Created
December 21, 2022 03:01
-
-
Save nestarz/79b7976c9ee93d164c5952d574e50ecb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { runHttpQuery } from 'https://deno.land/x/[email protected]/common.ts' | |
import type { GQLRequest, GQLOptions, GraphQLParams } from 'https://deno.land/x/[email protected]/types.ts' | |
import { renderPlaygroundPage } from 'https://deno.land/x/[email protected]/graphiql/render.ts'; | |
/** | |
* Create a new GraphQL HTTP middleware with schema, context etc | |
* @param {GQLOptions} options | |
* | |
* @example | |
* ```ts | |
* const graphql = await GraphQLHTTP({ schema }) | |
* | |
* for await (const req of s) graphql(req) | |
* ``` | |
*/ | |
export function GraphQLHTTP<Req extends GQLRequest = GQLRequest, Ctx extends { request: Req } = { request: Req }>({ | |
playgroundOptions = {}, | |
headers = {}, | |
...options | |
}: GQLOptions<Ctx, Req>) { | |
return async (request: Req) => { | |
const accept = request.headers.get('Accept') || '' | |
const typeList = ['text/html', 'text/plain', 'application/json', '*/*'] | |
.map((contentType) => ({ contentType, index: accept.indexOf(contentType) })) | |
.filter(({ index }) => index >= 0) | |
.sort((a, b) => a.index - b.index) | |
.map(({ contentType }) => contentType) | |
if (accept && !typeList.length) { | |
return new Response('Not Acceptable', { status: 406, headers: new Headers(headers) }) | |
} else if (!['GET', 'PUT', 'POST', 'PATCH'].includes(request.method)) { | |
return new Response('Method Not Allowed', { status: 405, headers: new Headers(headers) }) | |
} | |
let params: Promise<GraphQLParams> | |
if (request.method === 'GET') { | |
const urlQuery = request.url.substring(request.url.indexOf('?')) | |
const queryParams = new URLSearchParams(urlQuery) | |
if (options.graphiql && typeList[0] === 'text/html' && !queryParams.has('raw')) { | |
const playground = renderPlaygroundPage({ ...playgroundOptions, endpoint: '/graphql' }) | |
return new Response(playground, { | |
headers: new Headers({ | |
'Content-Type': 'text/html', | |
...headers | |
}) | |
}) | |
} else if (typeList.length === 1 && typeList[0] === 'text/html') { | |
return new Response('Not Acceptable', { status: 406, headers: new Headers(headers) }) | |
} else if (queryParams.has('query')) { | |
params = Promise.resolve({ query: queryParams.get('query') } as GraphQLParams) | |
} else { | |
params = Promise.reject(new Error('No query given!')) | |
} | |
} else if (typeList.length === 1 && typeList[0] === 'text/html') { | |
return new Response('Not Acceptable', { status: 406, headers: new Headers(headers) }) | |
} else { | |
params = request.json() | |
} | |
try { | |
const result = await runHttpQuery<Req, Ctx>(await params, options, { request }) | |
let contentType = 'text/plain' | |
if (!typeList.length || typeList.includes('application/json') || typeList.includes('*/*')) | |
contentType = 'application/json' | |
return new Response(JSON.stringify(result, null, 2), { | |
status: 200, | |
headers: new Headers({ | |
'Content-Type': contentType, | |
...headers | |
}) | |
}) | |
} catch (e) { | |
console.error(e) | |
return new Response('Malformed Request ' + (request.method === 'GET' ? 'Query' : 'Body'), { | |
status: 400, | |
headers: new Headers(headers) | |
}) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment