Skip to content

Commit

Permalink
feat: remove request and response logic
Browse files Browse the repository at this point in the history
export handler feature only
  • Loading branch information
TomokiMiyauci committed Oct 14, 2022
1 parent 4cde34d commit 2ecea94
Show file tree
Hide file tree
Showing 20 changed files with 135 additions and 3,305 deletions.
4 changes: 0 additions & 4 deletions FUNDING.yml

This file was deleted.

406 changes: 36 additions & 370 deletions README.md

Large diffs are not rendered by default.

20 changes: 0 additions & 20 deletions SECURITY.md

This file was deleted.

6 changes: 3 additions & 3 deletions _test_import_map.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"imports": {
"https://deno.land/x/graphql_http@$VERSION/": "./",
"https://deno.land/std@$VERSION/": "https://deno.land/std@0.147.0/",
"https://esm.sh/graphql@$VERSION": "https://esm.sh/graphql@16.5.0",
"https://deno.land/x/pure_json@$VERSION/": "https://deno.land/x/pure_json@1.0.0-beta.1/"
"https://deno.land/std@$VERSION/": "https://deno.land/std@0.159.0/",
"https://esm.sh/graphql@$VERSION": "https://esm.sh/v96/graphql@16.6.0",
"https://deno.land/x/gql_request@$VERSION/": "https://deno.land/x/gql_request@1.0.0-beta.1/"
}
}
11 changes: 0 additions & 11 deletions constants.ts

This file was deleted.

101 changes: 9 additions & 92 deletions deps.ts
Original file line number Diff line number Diff line change
@@ -1,95 +1,12 @@
// Copyright 2022-latest the graphqland authors. All rights reserved. MIT license.
// This module is browser compatible.

export {
buildSchema,
execute,
executeSync,
type ExecutionResult,
getOperationAST,
graphql,
type GraphQLArgs,
GraphQLError,
type GraphQLFieldResolver,
assertValidSchema,
GraphQLSchema,
type GraphQLTypeResolver,
parse,
Source,
specifiedRules,
validate,
validateSchema,
} from "https://esm.sh/v87/graphql@16.5.0";
export {
contentType,
parseMediaType,
} from "https://deno.land/std@0.150.0/media_types/mod.ts";
export { accepts } from "https://deno.land/std@0.150.0/http/negotiation.ts";
export {
isNil,
isNull,
isObject,
isPlainObject,
isString,
isUndefined,
} from "https://deno.land/x/isx@1.0.0-beta.19/mod.ts";
export {
JSON,
type json,
stringify,
} from "https://deno.land/x/pure_json@1.0.0-beta.1/mod.ts";
import { type json } from "https://deno.land/x/pure_json@1.0.0-beta.1/mod.ts";
} from "https://esm.sh/v96/graphql@16.6.0";
export {
type RenderPageOptions,
renderPlaygroundPage,
} from "https://esm.sh/graphql-playground-html@1.6.30";
export {
createHttpError,
HttpError,
Status,
} from "https://deno.land/std@0.150.0/http/mod.ts";

export type PartialBy<T, K = keyof T> =
Omit<T, K & keyof T> & Partial<Pick<T, K & keyof T>> extends infer U
? { [K in keyof U]: U[K] }
: never;

export type PickBy<T, K> = {
[k in keyof T as (K extends T[k] ? k : never)]: T[k];
};

export type PickRequired<T> = {
[k in keyof T as Record<never, never> extends Pick<T, k> ? never : k]: T[k];
};

export type PickPartial<T> = {
[k in keyof T as Record<never, never> extends Pick<T, k> ? k : never]: T[k];
};

export type jsonObject = {
[k: string]: json;
};

export function tryCatchSync<T>(
fn: () => T,
): [data: T, err: undefined] | [data: undefined, err: unknown] {
try {
return [fn(), undefined];
} catch (er) {
return [, er];
}
}

export async function tryCatch<T>(
fn: () => Promise<T> | T,
): Promise<[data: T, err: undefined] | [data: undefined, err: unknown]> {
try {
return [await fn(), undefined];
} catch (er) {
return [, er];
}
}

// deno-lint-ignore no-explicit-any
export function has<T extends Record<any, any>, K extends string>(
value: T,
key: K,
): value is T & Record<K, unknown> {
return key in value;
}
createResponse,
type ExecutionParams,
} from "https://deno.land/x/graphql_response@1.0.0-beta.2/mod.ts";
export { type HttpHandler } from "https://deno.land/x/http_utils@1.0.0-beta.6/mod.ts";
93 changes: 4 additions & 89 deletions dev_deps.ts
Original file line number Diff line number Diff line change
@@ -1,90 +1,5 @@
export * from "https://deno.land/std@0.150.0/testing/asserts.ts";
export * from "https://deno.land/std@0.150.0/testing/bdd.ts";
export * from "https://deno.land/std@0.150.0/media_types/mod.ts";
export * from "https://deno.land/std@0.150.0/http/mod.ts";
import {
defineExpect,
equal,
jestMatcherMap,
jestModifierMap,
MatchResult,
} from "https://deno.land/x/unitest@v1.0.0-beta.82/mod.ts";
import { isString } from "https://deno.land/x/isx@v1.0.0-beta.17/mod.ts";
export * from "https://esm.sh/graphql@16.5.0";
export * from "https://deno.land/std@0.159.0/testing/asserts.ts";
export * from "https://deno.land/std@0.159.0/testing/mock.ts";
export * from "https://deno.land/std@0.159.0/testing/bdd.ts";

export const expect = defineExpect({
matcherMap: {
...jestMatcherMap,
toError: (
actual: unknown,
// deno-lint-ignore ban-types
error: Function,
message?: string,
) => {
if (!(actual instanceof Error)) {
return {
pass: false,
expected: "Error Object",
};
}

if (!(actual instanceof error)) {
return {
pass: false,
expected: `${error.name} Object`,
};
}

if (message) {
return {
pass: actual.message === message,
expected: message,
resultActual: actual.message,
};
}

return {
pass: true,
expected: error,
};
},
toEqualIterable,
},
modifierMap: jestModifierMap,
});

function toEqualIterable(
actual: Iterable<readonly [PropertyKey, string]>,
expected: Iterable<readonly [PropertyKey, string]>,
): MatchResult {
const act = Object.fromEntries(actual);
const exp = Object.fromEntries(expected);

return {
pass: equal(act, exp),
expected: exp,
resultActual: act,
};
}

export function queryString(
baseURL: string | URL,
urlParams: { [param: string]: string },
): string {
const url = isString(baseURL) ? new URL(baseURL) : baseURL;

Object.entries(urlParams).forEach(([key, value]) => {
url.searchParams.set(key, value);
});

return url.toString();
}

export class BaseRequest extends Request {
constructor(input: RequestInfo, init?: RequestInit) {
const headers = new Headers(init?.headers);
headers.append("accept", "application/graphql+json");

super(input, { ...init, headers });
}
}
export { buildSchema } from "https://esm.sh/v96/graphql@16.6.0";
97 changes: 19 additions & 78 deletions handler.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
import { accepts, Status, validateSchema } from "./deps.ts";
// Copyright 2022-latest the graphqland authors. All rights reserved. MIT license.
// This module is browser compatible.

import {
createJSONResponse,
assertValidSchema,
createResponse,
createResult,
withCharset,
} from "./responses.ts";
import { resolveRequest } from "./requests.ts";
import { GraphQLOptionalArgs, GraphQLRequiredArgs } from "./types.ts";

export type Options =
& GraphQLOptionalArgs
& Pick<GraphQLRequiredArgs, "source">;
GraphQLSchema,
HttpHandler,
} from "./deps.ts";
import { HandlerOptions } from "./types.ts";

/** Create HTTP handler what handle GraphQL over HTTP request.
* @throws {@link AggregateError}
* When graphql schema validation is fail.
/** Create HTTP handler what handle GraphQL-over-HTTP request.
* @throws {Error} When schema is invalid.
*
* @example
* ```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 schema = buildSchema(`type Query { hello: String! }`);
* const handler = createHandler(schema, {
* rootValue: {
* hello: "world",
Expand All @@ -32,65 +27,11 @@ export type Options =
* 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, variables: variableValues, operationName } = data;

const res = createResponse({
schema,
source,
method: req.method as "GET" | "POST",
}, {
mimeType: mimeType,
variableValues,
operationName,
...options,
});

return res;
}
}
export function createHandler(
schema: GraphQLSchema,
options?: HandlerOptions,
): HttpHandler {
assertValidSchema(schema);

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";
return (request) => createResponse(request, { ...options, schema });
}
Loading

0 comments on commit 2ecea94

Please sign in to comment.