Created
December 25, 2022 16:29
-
-
Save nestarz/7c0275b94b4e18ed1a108237732fd57f to your computer and use it in GitHub Desktop.
Deno Deploy compatible https://deno.land/x/[email protected]/http.ts?source=#L45
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