Skip to content

feat(handler): Expose parseRequestParams from the core and each of the adapters #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions docs/modules/handler.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
### Functions

- [createHandler](handler.md#createhandler)
- [parseRequestParams](handler.md#parserequestparams-1)

## Server

Expand Down Expand Up @@ -124,8 +125,10 @@ ___

▸ (`req`): `Promise`<[`RequestParams`](../interfaces/common.RequestParams.md) \| [`Response`](handler.md#response) \| `void`\> \| [`RequestParams`](../interfaces/common.RequestParams.md) \| [`Response`](handler.md#response) \| `void`

The request parser for an incoming GraphQL request. It parses and validates the
request itself, including the request method and the content-type of the body.
The request parser for an incoming GraphQL request in the handler.

It should parse and validate the request itself, including the request method
and the content-type of the body.

In case you are extending the server to handle more request types, this is the
perfect place to do so.
Expand Down Expand Up @@ -258,3 +261,37 @@ console.log('Listening to port 4000');
#### Returns

[`Handler`](handler.md#handler)<`RequestRaw`, `RequestContext`\>

___

### parseRequestParams

▸ **parseRequestParams**<`RequestRaw`, `RequestContext`\>(`req`): `Promise`<[`Response`](handler.md#response) \| [`RequestParams`](../interfaces/common.RequestParams.md)\>

The GraphQL over HTTP spec compliant request parser for an incoming GraphQL request.
It parses and validates the request itself, including the request method and the
content-type of the body.

If the HTTP request itself is invalid or malformed, the function will return an
appropriate [Response](handler.md#response).

If the HTTP request is valid, but is not a well-formatted GraphQL request, the
function will throw an error and it is up to the user to handle and respond as
they see fit.

#### Type parameters

| Name | Type |
| :------ | :------ |
| `RequestRaw` | `unknown` |
| `RequestContext` | `unknown` |

#### Parameters

| Name | Type |
| :------ | :------ |
| `req` | [`Request`](../interfaces/handler.Request.md)<`RequestRaw`, `RequestContext`\> |

#### Returns

`Promise`<[`Response`](handler.md#response) \| [`RequestParams`](../interfaces/common.RequestParams.md)\>
54 changes: 54 additions & 0 deletions docs/modules/use_express.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
### Functions

- [createHandler](use_express.md#createhandler)
- [parseRequestParams](use_express.md#parserequestparams)

## Server/express

Expand Down Expand Up @@ -66,3 +67,56 @@ console.log('Listening to port 4000');
#### Returns

`Handler`

___

### parseRequestParams

▸ **parseRequestParams**(`req`, `res`): `Promise`<[`RequestParams`](../interfaces/common.RequestParams.md) \| ``null``\>

The GraphQL over HTTP spec compliant request parser for an incoming GraphQL request.

If the HTTP request _is not_ a [well-formatted GraphQL over HTTP request](https://graphql.github.io/graphql-over-http/draft/#sec-Request), the function will respond
on the `Response` argument and return `null`.

If the HTTP request _is_ a [well-formatted GraphQL over HTTP request](https://graphql.github.io/graphql-over-http/draft/#sec-Request), but is invalid or malformed,
the function will throw an error and it is up to the user to handle and respond as they see fit.

```js
import express from 'express'; // yarn add express
import { parseRequestParams } from 'graphql-http/lib/use/express';

const app = express();
app.all('/graphql', async (req, res) => {
try {
const maybeParams = await parseRequestParams(req, res);
if (!maybeParams) {
// not a well-formatted GraphQL over HTTP request,
// parser responded and there's nothing else to do
return;
}

// well-formatted GraphQL over HTTP request,
// with valid parameters
res.writeHead(200).end(JSON.stringify(maybeParams, null, ' '));
} catch (err) {
// well-formatted GraphQL over HTTP request,
// but with invalid parameters
res.writeHead(400).end(err.message);
}
});

app.listen({ port: 4000 });
console.log('Listening to port 4000');
```

#### Parameters

| Name | Type |
| :------ | :------ |
| `req` | `Request`<`ParamsDictionary`, `any`, `any`, `ParsedQs`, `Record`<`string`, `any`\>\> |
| `res` | `Response`<`any`, `Record`<`string`, `any`\>\> |

#### Returns

`Promise`<[`RequestParams`](../interfaces/common.RequestParams.md) \| ``null``\>
54 changes: 54 additions & 0 deletions docs/modules/use_fastify.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
### Functions

- [createHandler](use_fastify.md#createhandler)
- [parseRequestParams](use_fastify.md#parserequestparams)

## Server/fastify

Expand Down Expand Up @@ -66,3 +67,56 @@ console.log('Listening to port 4000');
#### Returns

`RouteHandler`

___

### parseRequestParams

▸ **parseRequestParams**(`req`, `reply`): `Promise`<[`RequestParams`](../interfaces/common.RequestParams.md) \| ``null``\>

The GraphQL over HTTP spec compliant request parser for an incoming GraphQL request.

If the HTTP request _is not_ a [well-formatted GraphQL over HTTP request](https://graphql.github.io/graphql-over-http/draft/#sec-Request), the function will respond
on the `FastifyReply` argument and return `null`.

If the HTTP request _is_ a [well-formatted GraphQL over HTTP request](https://graphql.github.io/graphql-over-http/draft/#sec-Request), but is invalid or malformed,
the function will throw an error and it is up to the user to handle and respond as they see fit.

```js
import Fastify from 'fastify'; // yarn add fastify
import { parseRequestParams } from 'graphql-http/lib/use/fastify';

const fastify = Fastify();
fastify.all('/graphql', async (req, reply) => {
try {
const maybeParams = await parseRequestParams(req, reply);
if (!maybeParams) {
// not a well-formatted GraphQL over HTTP request,
// parser responded and there's nothing else to do
return;
}

// well-formatted GraphQL over HTTP request,
// with valid parameters
reply.status(200).send(JSON.stringify(maybeParams, null, ' '));
} catch (err) {
// well-formatted GraphQL over HTTP request,
// but with invalid parameters
reply.status(400).send(err.message);
}
});

fastify.listen({ port: 4000 });
console.log('Listening to port 4000');
```

#### Parameters

| Name | Type |
| :------ | :------ |
| `req` | `FastifyRequest`<`RouteGenericInterface`, `RawServerDefault`, `IncomingMessage`, `FastifySchema`, `FastifyTypeProviderDefault`, `unknown`, `FastifyBaseLogger`, `ResolveFastifyRequestType`<`FastifyTypeProviderDefault`, `FastifySchema`, `RouteGenericInterface`\>\> |
| `reply` | `FastifyReply`<`RawServerDefault`, `IncomingMessage`, `ServerResponse`<`IncomingMessage`\>, `RouteGenericInterface`, `unknown`, `FastifySchema`, `FastifyTypeProviderDefault`, `unknown`\> |

#### Returns

`Promise`<[`RequestParams`](../interfaces/common.RequestParams.md) \| ``null``\>
63 changes: 63 additions & 0 deletions docs/modules/use_fetch.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
### Functions

- [createHandler](use_fetch.md#createhandler)
- [parseRequestParams](use_fetch.md#parserequestparams)

## Server/fetch

Expand Down Expand Up @@ -87,3 +88,65 @@ console.log('Listening to port 4000');
##### Returns

`Promise`<`Response`\>

___

### parseRequestParams

▸ **parseRequestParams**(`req`, `api?`): `Promise`<[`RequestParams`](../interfaces/common.RequestParams.md) \| `Response`\>

The GraphQL over HTTP spec compliant request parser for an incoming GraphQL request.

It is important to pass in the `abortedRef` so that the parser does not perform any
operations on a disposed request (see example).

If the HTTP request _is not_ a [well-formatted GraphQL over HTTP request](https://graphql.github.io/graphql-over-http/draft/#sec-Request), the function will return a `Response`.

If the HTTP request _is_ a [well-formatted GraphQL over HTTP request](https://graphql.github.io/graphql-over-http/draft/#sec-Request), but is invalid or malformed,
the function will throw an error and it is up to the user to handle and respond as they see fit.

```js
import http from 'http';
import { createServerAdapter } from '@whatwg-node/server'; // yarn add @whatwg-node/server
import { parseRequestParams } from 'graphql-http/lib/use/fetch';

// Use this adapter in _any_ environment.
const adapter = createServerAdapter({
handleRequest: async (req) => {
try {
const paramsOrResponse = await parseRequestParams(req);
if (paramsOrResponse instanceof Response) {
// not a well-formatted GraphQL over HTTP request,
// parser created a response object to use
return paramsOrResponse;
}

// well-formatted GraphQL over HTTP request,
// with valid parameters
return new Response(JSON.stringify(paramsOrResponse, null, ' '), {
status: 200,
});
} catch (err) {
// well-formatted GraphQL over HTTP request,
// but with invalid parameters
return new Response(err.message, { status: 400 });
}
},
});

const server = http.createServer(adapter);

server.listen(4000);
console.log('Listening to port 4000');
```

#### Parameters

| Name | Type |
| :------ | :------ |
| `req` | `Request` |
| `api` | `Partial`<[`FetchAPI`](../interfaces/use_fetch.FetchAPI.md)\> |

#### Returns

`Promise`<[`RequestParams`](../interfaces/common.RequestParams.md) \| `Response`\>
57 changes: 57 additions & 0 deletions docs/modules/use_http.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
### Functions

- [createHandler](use_http.md#createhandler)
- [parseRequestParams](use_http.md#parserequestparams)

## Server/http

Expand Down Expand Up @@ -78,3 +79,59 @@ console.log('Listening to port 4000');
##### Returns

`Promise`<`void`\>

___

### parseRequestParams

▸ **parseRequestParams**(`req`, `res`): `Promise`<[`RequestParams`](../interfaces/common.RequestParams.md) \| ``null``\>

The GraphQL over HTTP spec compliant request parser for an incoming GraphQL request.

If the HTTP request _is not_ a [well-formatted GraphQL over HTTP request](https://graphql.github.io/graphql-over-http/draft/#sec-Request), the function will respond
on the `ServerResponse` argument and return `null`.

If the HTTP request _is_ a [well-formatted GraphQL over HTTP request](https://graphql.github.io/graphql-over-http/draft/#sec-Request), but is invalid or malformed,
the function will throw an error and it is up to the user to handle and respond as they see fit.

```js
import http from 'http';
import { parseRequestParams } from 'graphql-http/lib/use/http';

const server = http.createServer(async (req, res) => {
if (req.url.startsWith('/graphql')) {
try {
const maybeParams = await parseRequestParams(req, res);
if (!maybeParams) {
// not a well-formatted GraphQL over HTTP request,
// parser responded and there's nothing else to do
return;
}

// well-formatted GraphQL over HTTP request,
// with valid parameters
res.writeHead(200).end(JSON.stringify(maybeParams, null, ' '));
} catch (err) {
// well-formatted GraphQL over HTTP request,
// but with invalid parameters
res.writeHead(400).end(err.message);
}
} else {
res.writeHead(404).end();
}
});

server.listen(4000);
console.log('Listening to port 4000');
```

#### Parameters

| Name | Type |
| :------ | :------ |
| `req` | `IncomingMessage` |
| `res` | `ServerResponse`<`IncomingMessage`\> |

#### Returns

`Promise`<[`RequestParams`](../interfaces/common.RequestParams.md) \| ``null``\>
Loading