-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhandler.ts
96 lines (86 loc) · 2.62 KB
/
handler.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import { accepts, Status, validateSchema } from "./deps.ts";
import {
createJSONResponse,
createResponse,
createResult,
withCharset,
} from "./responses.ts";
import { resolveRequest } from "./requests.ts";
import { GraphQLOptionalArgs, GraphQLRequiredArgs } from "./types.ts";
export type Options =
& GraphQLOptionalArgs
& Pick<GraphQLRequiredArgs, "source">;
/** Create HTTP handler what handle GraphQL over HTTP request.
* @throws {@link AggregateError}
* When graphql schema validation is fail.
* ```ts
* import { createHandler } from "https://deno.land/x/graphql_http@$VERSION/mod.ts";
* import { buildSchema } from "https://esm.sh/graphql@$VERSION";
*
* const schema = buildSchema(`type Query {
* hello: String!
* }`);
*
* const handler = createHandler(schema, {
* rootValue: {
* hello: "world",
* },
* });
* const req = new Request("<ENDPOINT>");
* const res = await handler(req);
* ```
*/
export default function createHandler(
schema: GraphQLRequiredArgs["schema"],
options: Readonly<Partial<Options>> = {},
): (req: Request) => Promise<Response> | Response {
const validateSchemaResult = validateSchema(schema);
if (validateSchemaResult.length) {
throw new AggregateError(validateSchemaResult, "Schema validation error");
}
return async (req) => {
const result = await process(req);
return result;
};
async function process(req: Request): Promise<Response> {
const mimeType = getMediaType(req);
const preferContentType = withCharset(mimeType);
const [data, err] = await resolveRequest(req);
if (!data) {
const result = createResult(err);
const baseHeaders: HeadersInit = { "content-type": preferContentType };
const responseInit: ResponseInit = err.status === Status.MethodNotAllowed
? {
status: err.status,
headers: {
...baseHeaders,
allow: ["GET", "POST"].join(","),
},
}
: {
status: err.status,
headers: baseHeaders,
};
const res = createJSONResponse(result, responseInit);
return res;
}
const { query: source, variableValues, operationName } = data;
const res = createResponse({
schema,
source,
method: req.method as "GET" | "POST",
}, {
mimeType: mimeType,
variableValues,
operationName,
...options,
});
return res;
}
}
function getMediaType(
req: Request,
): "application/graphql+json" | "application/json" {
return (accepts(req, "application/graphql+json", "application/json") ??
"application/json") as "application/graphql+json" | "application/json";
}