graphql-http
Advanced tools
Comparing version 1.6.1 to 1.7.0
@@ -90,3 +90,3 @@ "use strict"; | ||
}), | ||
(0, utils_1.audit)('MUST accept only utf-8 charset', async () => { | ||
(0, utils_1.audit)('MUST accept utf-8 encoding', async () => { | ||
const url = new URL(opts.url); | ||
@@ -96,16 +96,19 @@ url.searchParams.set('query', '{ __typename }'); | ||
headers: { | ||
accept: 'application/graphql-response+json; charset=iso-8859-1', | ||
'content-type': 'application/json; charset=utf-8', | ||
}, | ||
}); | ||
// application/json is 200 + errors | ||
const contentType = res.headers.get('content-type') || ''; | ||
if (contentType.includes('application/json')) { | ||
(0, utils_1.assert)(`Content-Type ${contentType} status code`, res.status).toBe(200); | ||
(0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).toHaveProperty('errors'); | ||
return; | ||
} | ||
// other content-types must be 4xx | ||
(0, utils_1.assert)(`Content-Type ${contentType} status code`, res.status).toBeGreaterThanOrEqual(400); | ||
(0, utils_1.assert)(`Content-Type ${contentType} status code`, res.status).toBeLessThanOrEqual(499); | ||
(0, utils_1.assert)('Status code', res.status).toBe(200); | ||
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('utf-8'); | ||
}), | ||
(0, utils_1.audit)('MUST assume utf-8 if encoding is unspecified', async () => { | ||
const url = new URL(opts.url); | ||
url.searchParams.set('query', '{ __typename }'); | ||
const res = await fetchFn(url.toString(), { | ||
headers: { | ||
'content-type': 'application/json', | ||
}, | ||
}); | ||
(0, utils_1.assert)('Status code', res.status).toBe(200); | ||
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('utf-8'); | ||
}), | ||
// Request | ||
@@ -112,0 +115,0 @@ (0, utils_1.audit)('MUST accept POST requests', async () => { |
@@ -6,3 +6,3 @@ /** | ||
*/ | ||
import { ExecutionResult } from 'graphql'; | ||
import type { ExecutionResult } from 'graphql'; | ||
import { Audit, AuditName } from './common'; | ||
@@ -9,0 +9,0 @@ export * from '../utils'; |
@@ -11,16 +11,14 @@ /** | ||
* | ||
* @category Common | ||
* @category Server | ||
*/ | ||
export interface RequestHeaders { | ||
accept?: string | undefined; | ||
allow?: string | undefined; | ||
'content-type'?: string | undefined; | ||
export declare type RequestHeaders = { | ||
/** | ||
* Always an array in Node. Duplicates are added to it. | ||
* Not necessarily true for other environments, make sure | ||
* to check the type during runtime. | ||
* Not necessarily true for other environments. | ||
*/ | ||
'set-cookie'?: string | string[] | undefined; | ||
[key: string]: string | string[] | undefined; | ||
} | ||
} | { | ||
get: (key: string) => string | null; | ||
}; | ||
/** | ||
@@ -30,5 +28,5 @@ * Server agnostic request interface containing the raw request | ||
* | ||
* @category Common | ||
* @category Server | ||
*/ | ||
export interface Request<RawRequest, Context> { | ||
export interface Request<Raw, Context> { | ||
readonly method: string; | ||
@@ -50,3 +48,3 @@ readonly url: string; | ||
*/ | ||
readonly raw: RawRequest; | ||
readonly raw: Raw; | ||
/** | ||
@@ -60,3 +58,3 @@ * Context value about the incoming request, you're free to pass any information here. | ||
* | ||
* @category Common | ||
* @category Server | ||
*/ | ||
@@ -72,3 +70,3 @@ export declare type ResponseHeaders = { | ||
* | ||
* @category Common | ||
* @category Server | ||
*/ | ||
@@ -80,3 +78,3 @@ export declare type ResponseBody = string; | ||
* | ||
* @category Common | ||
* @category Server | ||
*/ | ||
@@ -92,3 +90,3 @@ export interface ResponseInit { | ||
* | ||
* @category Common | ||
* @category Server | ||
*/ | ||
@@ -99,3 +97,3 @@ export declare type Response = readonly [body: ResponseBody | null, init: ResponseInit]; | ||
* | ||
* @category Common | ||
* @category Server | ||
*/ | ||
@@ -113,5 +111,9 @@ export declare function isResponse(val: unknown): val is Response; | ||
*/ | ||
export declare type ExecutionContext = object | symbol | number | string | boolean | undefined | null; | ||
export declare type OperationContext = Record<PropertyKey, unknown> | symbol | number | string | boolean | undefined | null; | ||
/** @category Server */ | ||
export interface HandlerOptions<RawRequest = unknown, Context = unknown> { | ||
export declare type OperationArgs<Context extends OperationContext = undefined> = ExecutionArgs & { | ||
contextValue?: Context; | ||
}; | ||
/** @category Server */ | ||
export interface HandlerOptions<RequestRaw = unknown, RequestContext = unknown, Context extends OperationContext = undefined> { | ||
/** | ||
@@ -133,3 +135,3 @@ * The GraphQL schema on which the operations will | ||
*/ | ||
schema?: GraphQLSchema | ((req: Request<RawRequest, Context>, args: Omit<ExecutionArgs, 'schema'>) => Promise<GraphQLSchema | Response> | GraphQLSchema | Response); | ||
schema?: GraphQLSchema | ((req: Request<RequestRaw, RequestContext>, args: Omit<OperationArgs<Context>, 'schema'>) => Promise<GraphQLSchema | Response> | GraphQLSchema | Response); | ||
/** | ||
@@ -140,3 +142,3 @@ * A value which is provided to every resolver and holds | ||
*/ | ||
context?: ExecutionContext | ((req: Request<RawRequest, Context>, args: ExecutionArgs) => Promise<ExecutionContext | Response> | ExecutionContext | Response); | ||
context?: Context | ((req: Request<RequestRaw, RequestContext>, params: RequestParams) => Promise<Context | Response> | Context | Response); | ||
/** | ||
@@ -190,3 +192,3 @@ * A custom GraphQL validate function allowing you to apply your | ||
*/ | ||
onSubscribe?: (req: Request<RawRequest, Context>, params: RequestParams) => Promise<ExecutionResult | ExecutionArgs | readonly GraphQLError[] | Response | void> | ExecutionResult | ExecutionArgs | readonly GraphQLError[] | Response | void; | ||
onSubscribe?: (req: Request<RequestRaw, RequestContext>, params: RequestParams) => Promise<ExecutionResult | OperationArgs<Context> | readonly GraphQLError[] | Response | void> | ExecutionResult | OperationArgs<Context> | readonly GraphQLError[] | Response | void; | ||
/** | ||
@@ -205,3 +207,3 @@ * Executed after the operation call resolves. | ||
*/ | ||
onOperation?: (req: Request<RawRequest, Context>, args: ExecutionArgs, result: ExecutionResult) => Promise<ExecutionResult | Response | void> | ExecutionResult | Response | void; | ||
onOperation?: (req: Request<RequestRaw, RequestContext>, args: OperationArgs<Context>, result: ExecutionResult) => Promise<ExecutionResult | Response | void> | ExecutionResult | Response | void; | ||
} | ||
@@ -218,3 +220,3 @@ /** | ||
*/ | ||
export declare type Handler<RawRequest = unknown, Context = unknown> = (req: Request<RawRequest, Context>) => Promise<Response>; | ||
export declare type Handler<RequestRaw = unknown, RequestContext = unknown> = (req: Request<RequestRaw, RequestContext>) => Promise<Response>; | ||
/** | ||
@@ -275,3 +277,3 @@ * Makes a GraphQL over HTTP Protocol compliant server handler. The handler can | ||
*/ | ||
export declare function createHandler<RawRequest = unknown, Context = unknown>(options: HandlerOptions<RawRequest, Context>): Handler<RawRequest, Context>; | ||
export declare function createHandler<RequestRaw = unknown, RequestContext = unknown, Context extends OperationContext = undefined>(options: HandlerOptions<RequestRaw, RequestContext, Context>): Handler<RequestRaw, RequestContext>; | ||
/** | ||
@@ -278,0 +280,0 @@ * Request's Media-Type that the server accepts. |
@@ -14,3 +14,3 @@ "use strict"; | ||
* | ||
* @category Common | ||
* @category Server | ||
*/ | ||
@@ -96,3 +96,3 @@ function isResponse(val) { | ||
} | ||
const acceptedMediaType = getAcceptableMediaType(req.headers.accept); | ||
const acceptedMediaType = getAcceptableMediaType(getHeader(req, 'accept')); | ||
if (!acceptedMediaType) { | ||
@@ -112,3 +112,3 @@ return [ | ||
const [mediaType, charset = 'charset=utf-8', // utf-8 is assumed when not specified. this parameter is either "charset" or "boundary" (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length) | ||
] = (req.headers['content-type'] || '') | ||
] = (getHeader(req, 'content-type') || '') | ||
.replace(/\s/g, '') | ||
@@ -214,2 +214,5 @@ .toLowerCase() | ||
} | ||
const resOrContext = typeof context === 'function' ? await context(req, params) : context; | ||
if (isResponse(resOrContext)) | ||
return resOrContext; | ||
const argsWithoutSchema = { | ||
@@ -219,2 +222,3 @@ operationName, | ||
variableValues: variables, | ||
contextValue: resOrContext, | ||
}; | ||
@@ -265,6 +269,6 @@ if (typeof schema === 'function') { | ||
if (!('contextValue' in args)) { | ||
const maybeResOrContext = typeof context === 'function' ? await context(req, args) : context; | ||
if (isResponse(maybeResOrContext)) | ||
return maybeResOrContext; | ||
args.contextValue = maybeResOrContext; | ||
const resOrContext = typeof context === 'function' ? await context(req, params) : context; | ||
if (isResponse(resOrContext)) | ||
return resOrContext; | ||
args.contextValue = resOrContext; | ||
} | ||
@@ -365,1 +369,7 @@ let result = await execute(args); | ||
exports.makeResponse = makeResponse; | ||
function getHeader(req, key) { | ||
if (typeof req.headers.get === 'function') { | ||
return req.headers.get(key); | ||
} | ||
return Object(req.headers)[key]; | ||
} |
MIT License | ||
Copyright (c) 2022 Denis Badurina | ||
Copyright (c) GraphQL Contributors | ||
@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
{ | ||
"name": "graphql-http", | ||
"version": "1.6.1", | ||
"version": "1.7.0", | ||
"description": "Simple, pluggable, zero-dependency, GraphQL over HTTP Protocol compliant server and client", | ||
@@ -19,6 +19,6 @@ "keywords": [ | ||
"license": "MIT", | ||
"homepage": "https://github.com/enisdenjo/graphql-http#readme", | ||
"homepage": "https://github.com/graphql/graphql-http#readme", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/enisdenjo/graphql-http.git" | ||
"url": "https://github.com/graphql/graphql-http.git" | ||
}, | ||
@@ -28,3 +28,3 @@ "engines": { | ||
}, | ||
"packageManager": "yarn@3.2.3", | ||
"packageManager": "yarn@3.2.4", | ||
"main": "lib/index.js", | ||
@@ -40,2 +40,22 @@ "module": "lib/index.mjs", | ||
}, | ||
"./lib/use/fetch": { | ||
"types": "./lib/use/fetch.d.ts", | ||
"require": "./lib/use/fetch.js", | ||
"import": "./lib/use/fetch.mjs" | ||
}, | ||
"./lib/use/node": { | ||
"types": "./lib/use/node.d.ts", | ||
"require": "./lib/use/node.js", | ||
"import": "./lib/use/node.mjs" | ||
}, | ||
"./lib/use/express": { | ||
"types": "./lib/use/express.d.ts", | ||
"require": "./lib/use/express.js", | ||
"import": "./lib/use/express.mjs" | ||
}, | ||
"./lib/use/fastify": { | ||
"types": "./lib/use/fastify.d.ts", | ||
"require": "./lib/use/fastify.js", | ||
"import": "./lib/use/fastify.mjs" | ||
}, | ||
"./package.json": "./package.json" | ||
@@ -74,31 +94,35 @@ }, | ||
"devDependencies": { | ||
"@babel/core": "^7.18.13", | ||
"@babel/core": "^7.20.2", | ||
"@babel/plugin-proposal-class-properties": "^7.18.6", | ||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.18.9", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.20.2", | ||
"@babel/plugin-proposal-optional-chaining": "^7.18.9", | ||
"@babel/preset-env": "^7.18.10", | ||
"@babel/preset-env": "^7.20.2", | ||
"@babel/preset-typescript": "^7.18.6", | ||
"@rollup/plugin-typescript": "^8.4.0", | ||
"@rollup/plugin-typescript": "^9.0.2", | ||
"@semantic-release/changelog": "^6.0.1", | ||
"@semantic-release/git": "^10.0.1", | ||
"@types/jest": "^29.0.0", | ||
"@typescript-eslint/eslint-plugin": "^5.36.1", | ||
"@typescript-eslint/parser": "^5.36.1", | ||
"babel-jest": "^29.0.1", | ||
"eslint": "^8.23.0", | ||
"@types/express": "^4.17.14", | ||
"@types/jest": "^29.2.2", | ||
"@typescript-eslint/eslint-plugin": "^5.42.1", | ||
"@typescript-eslint/parser": "^5.42.1", | ||
"@whatwg-node/fetch": "^0.5.1", | ||
"babel-jest": "^29.3.0", | ||
"eslint": "^8.27.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"eslint-plugin-prettier": "^4.2.1", | ||
"express": "^4.18.2", | ||
"fastify": "^4.9.2", | ||
"graphql": "^16.6.0", | ||
"jest": "^29.0.1", | ||
"jest-jasmine2": "^29.0.1", | ||
"jest": "^29.3.0", | ||
"jest-jasmine2": "^29.3.0", | ||
"node-fetch": "^3.2.10", | ||
"prettier": "^2.7.1", | ||
"rollup": "^2.79.0", | ||
"rollup": "^3.2.5", | ||
"rollup-plugin-terser": "^7.0.2", | ||
"semantic-release": "^19.0.5", | ||
"tslib": "^2.4.0", | ||
"typedoc": "^0.23.13", | ||
"typedoc-plugin-markdown": "^3.13.5", | ||
"typescript": "^4.8.2" | ||
"tslib": "^2.4.1", | ||
"typedoc": "^0.23.20", | ||
"typedoc-plugin-markdown": "^3.13.6", | ||
"typescript": "^4.8.4" | ||
}, | ||
@@ -105,0 +129,0 @@ "resolutions": { |
237
README.md
@@ -8,6 +8,8 @@ <div align="center"> | ||
[](https://github.com/enisdenjo/graphql-http/actions?query=workflow%3A%22Continuous+integration%22) [](https://www.npmjs.com/package/graphql-http) | ||
[](https://github.com/graphql/graphql-http/actions?query=workflow%3A%22Continuous+integration%22) [](https://www.npmjs.com/package/graphql-http) | ||
<i>Need subscriptions? Try <b>[graphql-ws](https://github.com/enisdenjo/graphql-ws)</b> or <b>[graphql-sse](https://github.com/enisdenjo/graphql-sse)</b> instead!</i> | ||
<i>Want a full-featured server? See the <b>[servers section](#servers)</b></i>! | ||
<br /> | ||
@@ -55,31 +57,15 @@ </div> | ||
import http from 'http'; | ||
import { createHandler } from 'graphql-http'; | ||
import { createHandler } from 'graphql-http/lib/use/node'; | ||
import { schema } from './previous-step'; | ||
// Create the GraphQL over HTTP handler | ||
// Create the GraphQL over HTTP Node request handler | ||
const handler = createHandler({ schema }); | ||
// Create a HTTP server using the handler on `/graphql` | ||
const server = http.createServer(async (req, res) => { | ||
if (!req.url.startsWith('/graphql')) { | ||
return res.writeHead(404).end(); | ||
// Create a HTTP server using the listner on `/graphql` | ||
const server = http.createServer((req, res) => { | ||
if (req.url.startsWith('/graphql')) { | ||
handler(req, res); | ||
} else { | ||
res.writeHead(404).end(); | ||
} | ||
try { | ||
const [body, init] = await handler({ | ||
url: req.url, | ||
method: req.method, | ||
headers: req.headers, | ||
body: () => | ||
new Promise((resolve) => { | ||
let body = ''; | ||
req.on('data', (chunk) => (body += chunk)); | ||
req.on('end', () => resolve(body)); | ||
}), | ||
raw: req, | ||
}); | ||
res.writeHead(init.status, init.statusText, init.headers).end(body); | ||
} catch (err) { | ||
res.writeHead(500).end(err.message); | ||
} | ||
}); | ||
@@ -103,6 +89,6 @@ | ||
import http2 from 'http2'; | ||
import { createHandler } from 'graphql-http'; | ||
import { createHandler } from 'graphql-http/lib/use/node'; | ||
import { schema } from './previous-step'; | ||
// Create the GraphQL over HTTP handler | ||
// Create the GraphQL over HTTP Node request handler | ||
const handler = createHandler({ schema }); | ||
@@ -116,24 +102,8 @@ | ||
}, | ||
async (req, res) => { | ||
if (!req.url.startsWith('/graphql')) { | ||
return res.writeHead(404).end(); | ||
(req, res) => { | ||
if (req.url.startsWith('/graphql')) { | ||
handler(req, res); | ||
} else { | ||
res.writeHead(404).end(); | ||
} | ||
try { | ||
const [body, init] = await handler({ | ||
url: req.url, | ||
method: req.method, | ||
headers: req.headers, | ||
body: () => | ||
new Promise((resolve) => { | ||
let body = ''; | ||
req.on('data', (chunk) => (body += chunk)); | ||
req.on('end', () => resolve(body)); | ||
}), | ||
raw: req, | ||
}); | ||
res.writeHead(init.status, init.statusText, init.headers).end(body); | ||
} catch (err) { | ||
res.writeHead(500).end(err.message); | ||
} | ||
}, | ||
@@ -150,31 +120,11 @@ ); | ||
import express from 'express'; // yarn add express | ||
import { createHandler } from 'graphql-http'; | ||
import { createHandler } from 'graphql-http/lib/use/express'; | ||
import { schema } from './previous-step'; | ||
// Create the GraphQL over HTTP handler | ||
const handler = createHandler({ schema }); | ||
// Create an express app serving all methods on `/graphql` | ||
// Create a express instance serving all methods on `/graphql` | ||
// where the GraphQL over HTTP express request handler is | ||
const app = express(); | ||
app.use('/graphql', async (req, res) => { | ||
try { | ||
const [body, init] = await handler({ | ||
url: req.url, | ||
method: req.method, | ||
headers: req.headers, | ||
body: () => | ||
new Promise((resolve) => { | ||
let body = ''; | ||
req.on('data', (chunk) => (body += chunk)); | ||
req.on('end', () => resolve(body)); | ||
}), | ||
raw: req, | ||
}); | ||
res.writeHead(init.status, init.statusText, init.headers).end(body); | ||
} catch (err) { | ||
res.writeHead(500).end(err.message); | ||
} | ||
}); | ||
app.all('/graphql', createHandler({ schema })); | ||
app.listen(4000); | ||
app.listen({ port: 4000 }); | ||
console.log('Listening to port 4000'); | ||
@@ -187,26 +137,11 @@ ``` | ||
import Fastify from 'fastify'; // yarn add fastify | ||
import { createHandler } from 'graphql-http'; | ||
import { createHandler } from 'graphql-http/lib/use/fastify'; | ||
import { schema } from './previous-step'; | ||
// Create the GraphQL over HTTP handler | ||
const handler = createHandler({ schema }); | ||
// Create a fastify instance serving all methods on `/graphql` | ||
// where the GraphQL over HTTP fastify request handler is | ||
const fastify = Fastify(); | ||
fastify.all('/graphql', async (req, res) => { | ||
try { | ||
const [body, init] = await handler({ | ||
url: req.url, | ||
method: req.method, | ||
headers: req.headers, | ||
body: req.body, // fastify reads the body for you | ||
raw: req, | ||
}); | ||
res.writeHead(init.status, init.statusText, init.headers).end(body); | ||
} catch (err) { | ||
res.writeHead(500).end(err.message); | ||
} | ||
}); | ||
fastify.all('/graphql', createHandler({ schema })); | ||
fastify.listen(4000); | ||
fastify.listen({ port: 4000 }); | ||
console.log('Listening to port 4000'); | ||
@@ -219,33 +154,45 @@ ``` | ||
import { serve } from 'https://deno.land/std@0.151.0/http/server.ts'; | ||
import { createHandler } from 'https://esm.sh/graphql-http'; | ||
import { createHandler } from 'https://esm.sh/graphql-http/lib/use/fetch'; | ||
import { schema } from './previous-step'; | ||
// Create the GraphQL over HTTP handler | ||
const handler = createHandler<Request>({ schema }); | ||
// Create the GraphQL over HTTP native fetch handler | ||
const handler = createHandler({ schema }); | ||
// Start serving on `/graphql` using the handler | ||
await serve( | ||
async (req: Request) => { | ||
(req: Request) => { | ||
const [path, _search] = req.url.split('?'); | ||
if (!path.endsWith('/graphql')) { | ||
return new Response(null, { status: 404, statusText: 'Not Found' }); | ||
if (path.endsWith('/graphql')) { | ||
return handler(req); | ||
} else { | ||
return new Response(null, { status: 404 }); | ||
} | ||
const headers: Record<string, string> = {}; | ||
req.headers.forEach((value, key) => (headers[key] = value)); | ||
const [body, init] = await handler({ | ||
url: req.url, | ||
method: req.method, | ||
headers, | ||
body: () => req.text(), | ||
raw: req, | ||
}); | ||
return new Response(body, init); | ||
}, | ||
{ | ||
port: 4000, | ||
port: 4000, // Listening to port 4000 | ||
}, | ||
); | ||
``` | ||
// Listening to port 4000 | ||
##### With [`Bun`](https://bun.sh/) | ||
```js | ||
import { createHandler } from 'graphql-http/lib/use/fetch'; // bun install graphql-http | ||
import { schema } from './previous-step'; | ||
// Create the GraphQL over HTTP native fetch handler | ||
const handler = createHandler({ schema }); | ||
// Start serving on `/graphql` using the handler | ||
export default { | ||
port: 4000, // Listening to port 4000 | ||
fetch(req) { | ||
const [path, _search] = req.url.split('?'); | ||
if (path.endsWith('/graphql')) { | ||
return handler(req); | ||
} else { | ||
return new Response(null, { status: 404 }); | ||
} | ||
}, | ||
}; | ||
``` | ||
@@ -565,3 +512,3 @@ | ||
```js | ||
import { createClient } from 'graphql-http'; | ||
import { createClient } from 'https://esm.sh/graphql-http'; | ||
@@ -577,2 +524,39 @@ const client = createClient({ | ||
<details id="bun-client"> | ||
<summary><a href="#bun-client">🔗</a> Client usage in Bun</summary> | ||
```js | ||
import { createClient } from 'graphql-http'; // bun install graphql-http | ||
const client = createClient({ | ||
url: 'http://bun.bread:4000/graphql', | ||
}); | ||
// consider other recipes for usage inspiration | ||
``` | ||
</details> | ||
<details id="migrating-express-grpahql"> | ||
<summary><a href="#migrating-express-grpahql">🔗</a> Server handler migration from <a href="https://github.com/graphql/express-graphql">express-graphql</a></summary> | ||
```diff | ||
import express from 'express'; | ||
import { schema } from './my-graphql-schema'; | ||
-import { graphqlHTTP } from 'express-graphql'; | ||
+import { createHandler } from 'graphql-http/lib/use/express'; | ||
const app = express(); | ||
app.use( | ||
'/graphql', | ||
- graphqlHTTP({ schema }), | ||
+ createHandler({ schema }), | ||
); | ||
app.listen(4000); | ||
``` | ||
</details> | ||
<details id="auth"> | ||
@@ -747,2 +731,19 @@ <summary><a href="#auth">🔗</a> Server handler usage with authentication</summary> | ||
## Only [GraphQL over HTTP](https://graphql.github.io/graphql-over-http/) | ||
This is the official [GraphQL over HTTP spec](https://graphql.github.io/graphql-over-http/) reference implementation and as such follows the specification strictly without any additional features (like file uploads, @stream/@defer directives and subscriptions). | ||
Having said this, graphql-http is mostly aimed for library authors and simple server setups, where the requirements are exact to what the aforementioned spec offers. | ||
## [Servers](/implementations) | ||
If you want a feature-full server with bleeding edge technologies, you're recommended to use one of the following. | ||
| Name | Audit | | ||
| -------------------------------------------------------------- | ------------------------------------------------------------------ | | ||
| [graphql-yoga](https://www.the-guild.dev/graphql/yoga-server) | [✅ Fully compliant](/implementations/graphql-yoga/README.md) | | ||
| [apollo-server](https://www.the-guild.dev/graphql/yoga-server) | [⚠️ Partially compliant](/implementations/apollo-server/README.md) | | ||
| [mercurius](https://mercurius.dev) | [⚠️ Partially compliant](/implementations/mercurius/README.md) | | ||
| [graphql-helix](https://www.graphql-helix.com/) | [⚠️ Partially compliant](/implementations/graphql-helix/README.md) | | ||
## [Documentation](docs/) | ||
@@ -756,4 +757,12 @@ | ||
## [Want to help?](CONTRIBUTING.md) | ||
## Want to help? | ||
File a bug, contribute with code, or improve documentation? Read up on our guidelines for [contributing](CONTRIBUTING.md) and drive development with `yarn test --watch` away! | ||
File a bug, contribute with code, or improve documentation? Read up on our guidelines below and drive development with `yarn test --watch` away! | ||
This repository is managed by EasyCLA. Project participants must sign the free [GraphQL Specification Membership agreement](https://preview-spec-membership.graphql.org) before making a contribution. You only need to do this one time, and it can be signed by [individual contributors](http://individual-spec-membership.graphql.org/) or their [employers](http://corporate-spec-membership.graphql.org/). | ||
To initiate the signature process please open a PR against this repo. The EasyCLA bot will block the merge if we still need a membership agreement from you. | ||
You can find [detailed information here](https://github.com/graphql/graphql-wg/tree/main/membership). If you have issues, please email [operations@graphql.org](mailto:operations@graphql.org). | ||
If your company benefits from GraphQL and you would like to provide essential financial support for the systems and people that power our community, please also consider membership in the [GraphQL Foundation](https://foundation.graphql.org/join). |
@@ -188,4 +188,2 @@ (function (global, factory) { | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
})); |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).graphqlHttp={})}(this,(function(e){"use strict";class t extends Error{constructor(e){let t,r;var o;(function(e){return"object"==typeof e&&null!==e})(o=e)&&"boolean"==typeof o.ok&&"number"==typeof o.status&&"string"==typeof o.statusText?(r=e,t="Server responded with "+e.status+": "+e.statusText):t=e instanceof Error?e.message:String(e),super(t),this.name=this.constructor.name,this.response=r}}e.NetworkError=t,e.createClient=function(e){const{credentials:r="same-origin",referrer:o,referrerPolicy:n,shouldRetry:s=(()=>!1)}=e,i=e.fetchFn||fetch,a=e.abortControllerImpl||AbortController,c=(()=>{let e=!1;const t=[];return{get disposed(){return e},onDispose:r=>e?(setTimeout((()=>r()),0),()=>{}):(t.push(r),()=>{t.splice(t.indexOf(r),1)}),dispose(){if(!e){e=!0;for(const e of[...t])e()}}}})();return{subscribe(p,l){if(c.disposed)throw new Error("Client has been disposed");const f=new a,u=c.onDispose((()=>{u(),f.abort()}));return(async()=>{var a;let c=null,u=0;for(;;){if(c){const e=await s(c,u);if(f.signal.aborted)return;if(!e)throw c;u++}try{const s="function"==typeof e.url?await e.url(p):e.url;if(f.signal.aborted)return;const c="function"==typeof e.headers?await e.headers():null!==(a=e.headers)&&void 0!==a?a:{};if(f.signal.aborted)return;let u;try{u=await i(s,{signal:f.signal,method:"POST",headers:Object.assign(Object.assign({},c),{"content-type":"application/json; charset=utf-8",accept:"application/graphql-response+json, application/json"}),credentials:r,referrer:o,referrerPolicy:n,body:JSON.stringify(p)})}catch(e){throw new t(e)}if(!u.ok)throw new t(u);if(!u.body)throw new Error("Missing response body");const d=u.headers.get("content-type");if(!d)throw new Error("Missing response content-type");if(!d.includes("application/graphql-response+json")&&!d.includes("application/json"))throw new Error(`Unsupported response content-type ${d}`);const h=await u.json();return l.next(h),f.abort()}catch(e){if(f.signal.aborted)return;if(!(e instanceof t))throw e;c=e}}})().then((()=>l.complete())).catch((e=>l.error(e))),()=>f.abort()},dispose(){c.dispose()}}},Object.defineProperty(e,"__esModule",{value:!0})})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).graphqlHttp={})}(this,(function(e){"use strict";class t extends Error{constructor(e){let t,r;var o;(function(e){return"object"==typeof e&&null!==e})(o=e)&&"boolean"==typeof o.ok&&"number"==typeof o.status&&"string"==typeof o.statusText?(r=e,t="Server responded with "+e.status+": "+e.statusText):t=e instanceof Error?e.message:String(e),super(t),this.name=this.constructor.name,this.response=r}}e.NetworkError=t,e.createClient=function(e){const{credentials:r="same-origin",referrer:o,referrerPolicy:n,shouldRetry:s=(()=>!1)}=e,i=e.fetchFn||fetch,a=e.abortControllerImpl||AbortController,c=(()=>{let e=!1;const t=[];return{get disposed(){return e},onDispose:r=>e?(setTimeout((()=>r()),0),()=>{}):(t.push(r),()=>{t.splice(t.indexOf(r),1)}),dispose(){if(!e){e=!0;for(const e of[...t])e()}}}})();return{subscribe(p,l){if(c.disposed)throw new Error("Client has been disposed");const f=new a,u=c.onDispose((()=>{u(),f.abort()}));return(async()=>{var a;let c=null,u=0;for(;;){if(c){const e=await s(c,u);if(f.signal.aborted)return;if(!e)throw c;u++}try{const s="function"==typeof e.url?await e.url(p):e.url;if(f.signal.aborted)return;const c="function"==typeof e.headers?await e.headers():null!==(a=e.headers)&&void 0!==a?a:{};if(f.signal.aborted)return;let u;try{u=await i(s,{signal:f.signal,method:"POST",headers:Object.assign(Object.assign({},c),{"content-type":"application/json; charset=utf-8",accept:"application/graphql-response+json, application/json"}),credentials:r,referrer:o,referrerPolicy:n,body:JSON.stringify(p)})}catch(e){throw new t(e)}if(!u.ok)throw new t(u);if(!u.body)throw new Error("Missing response body");const d=u.headers.get("content-type");if(!d)throw new Error("Missing response content-type");if(!d.includes("application/graphql-response+json")&&!d.includes("application/json"))throw new Error(`Unsupported response content-type ${d}`);const h=await u.json();return l.next(h),f.abort()}catch(e){if(f.signal.aborted)return;if(!(e instanceof t))throw e;c=e}}})().then((()=>l.complete())).catch((e=>l.error(e))),()=>f.abort()},dispose(){c.dispose()}}}})); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
233775
58
4268
758
33
8