Skip to content
This repository was archived by the owner on Mar 20, 2023. It is now read-only.

Commit 81c7986

Browse files
committed
Flow cleanup typings
Motivation: #622 (comment)
1 parent 93f43d9 commit 81c7986

File tree

3 files changed

+64
-50
lines changed

3 files changed

+64
-50
lines changed

src/index.js

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ import {
2626
} from 'graphql';
2727

2828
import { parseBody } from './parseBody';
29-
import { renderGraphiQL, type GraphiQLOptions } from './renderGraphiQL';
29+
import {
30+
renderGraphiQL,
31+
type GraphiQLOptions,
32+
type GraphiQLData,
33+
} from './renderGraphiQL';
3034

3135
type $Request = IncomingMessage;
32-
type $Response = ServerResponse & {| json?: ?(data: mixed) => void |};
36+
type $Response = ServerResponse & {| json?: (data: mixed) => void |};
3337

3438
/**
3539
* Used to configure the graphqlHTTP middleware by providing a schema
@@ -56,29 +60,29 @@ export type OptionsData = {|
5660
/**
5761
* A value to pass as the context to this middleware.
5862
*/
59-
context?: ?mixed,
63+
context?: mixed,
6064

6165
/**
6266
* An object to pass as the rootValue to the graphql() function.
6367
*/
64-
rootValue?: ?mixed,
68+
rootValue?: mixed,
6569

6670
/**
6771
* A boolean to configure whether the output should be pretty-printed.
6872
*/
69-
pretty?: ?boolean,
73+
pretty?: boolean,
7074

7175
/**
7276
* An optional array of validation rules that will be applied on the document
7377
* in additional to those defined by the GraphQL spec.
7478
*/
75-
validationRules?: ?$ReadOnlyArray<(ValidationContext) => ASTVisitor>,
79+
validationRules?: $ReadOnlyArray<(ValidationContext) => ASTVisitor>,
7680

7781
/**
7882
* An optional function which will be used to validate instead of default `validate`
7983
* from `graphql-js`.
8084
*/
81-
customValidateFn?: ?(
85+
customValidateFn?: (
8286
schema: GraphQLSchema,
8387
documentAST: DocumentNode,
8488
rules: $ReadOnlyArray<ValidationRule>,
@@ -88,7 +92,7 @@ export type OptionsData = {|
8892
* An optional function which will be used to execute instead of default `execute`
8993
* from `graphql-js`.
9094
*/
91-
customExecuteFn?: ?(
95+
customExecuteFn?: (
9296
args: ExecutionArgs,
9397
) => ExecutionResult | Promise<ExecutionResult>,
9498

@@ -97,19 +101,19 @@ export type OptionsData = {|
97101
* fulfilling a GraphQL operation. If no function is provided, GraphQL's
98102
* default spec-compliant `formatError` function will be used.
99103
*/
100-
customFormatErrorFn?: ?(error: GraphQLError) => mixed,
104+
customFormatErrorFn?: (error: GraphQLError) => mixed,
101105

102106
/**
103107
* An optional function which will be used to create a document instead of
104108
* the default `parse` from `graphql-js`.
105109
*/
106-
customParseFn?: ?(source: Source) => DocumentNode,
110+
customParseFn?: (source: Source) => DocumentNode,
107111

108112
/**
109113
* `formatError` is deprecated and replaced by `customFormatErrorFn`. It will
110114
* be removed in version 1.0.0.
111115
*/
112-
formatError?: ?(error: GraphQLError) => mixed,
116+
formatError?: (error: GraphQLError) => mixed,
113117

114118
/**
115119
* An optional function for adding additional metadata to the GraphQL response
@@ -121,27 +125,27 @@ export type OptionsData = {|
121125
*
122126
* This function may be async.
123127
*/
124-
extensions?: ?(info: RequestInfo) => { [key: string]: mixed, ... },
128+
extensions?: (info: RequestInfo) => { [key: string]: mixed, ... },
125129

126130
/**
127131
* A boolean to optionally enable GraphiQL mode.
128132
* Alternatively, instead of `true` you can pass in an options object.
129133
*/
130-
graphiql?: ?boolean | ?GraphiQLOptions,
134+
graphiql?: boolean | GraphiQLOptions,
131135

132136
/**
133137
* A resolver function to use when one is not provided by the schema.
134138
* If not provided, the default field resolver is used (which looks for a
135139
* value or method on the source value with the field's name).
136140
*/
137-
fieldResolver?: ?GraphQLFieldResolver<mixed, mixed>,
141+
fieldResolver?: GraphQLFieldResolver<mixed, mixed>,
138142

139143
/**
140144
* A type resolver function to use when none is provided by the schema.
141145
* If not provided, the default type resolver is used (which looks for a
142146
* `__typename` field or alternatively calls the `isTypeOf` method).
143147
*/
144-
typeResolver?: ?GraphQLTypeResolver<mixed, mixed>,
148+
typeResolver?: GraphQLTypeResolver<mixed, mixed>,
145149
|};
146150

147151
/**
@@ -151,27 +155,27 @@ export type RequestInfo = {|
151155
/**
152156
* The parsed GraphQL document.
153157
*/
154-
document: ?DocumentNode,
158+
document: DocumentNode,
155159

156160
/**
157161
* The variable values used at runtime.
158162
*/
159-
variables: ?{ +[name: string]: mixed, ... },
163+
variables: { +[name: string]: mixed, ... } | null,
160164

161165
/**
162166
* The (optional) operation name requested.
163167
*/
164-
operationName: ?string,
168+
operationName: string | null,
165169

166170
/**
167171
* The result of executing the operation.
168172
*/
169-
result: ?ExecutionResult,
173+
result: ExecutionResult | null,
170174

171175
/**
172176
* A value to pass as the context to the graphql() function.
173177
*/
174-
context?: ?mixed,
178+
context?: mixed,
175179
|};
176180

177181
type Middleware = (request: $Request, response: $Response) => Promise<void>;
@@ -190,27 +194,32 @@ function graphqlHTTP(options: Options): Middleware {
190194
request: $Request,
191195
response: $Response,
192196
) {
193-
// Higher scoped variables are referred to at various stages in the
194-
// asynchronous state machine below.
195-
let params;
197+
// Higher scoped variables are referred to at various stages in the asynchronous state machine below.
198+
let params: GraphQLParams;
196199
let showGraphiQL = false;
197200
let graphiqlOptions;
201+
let formatErrorFn = formatError;
202+
let pretty = false;
198203
let result: ExecutionResult;
199-
let optionsData;
200204

201205
try {
202206
// Parse the Request to get GraphQL request parameters.
203207
try {
204-
params = await getGraphQLParams(request);
208+
params = (await getGraphQLParams(request): GraphQLParams);
205209
} catch (error) {
206210
// When we failed to parse the GraphQL parameters, we still need to get
207211
// the options object, so make an options call to resolve just that.
208-
optionsData = await resolveOptions();
212+
const optionsData = await resolveOptions();
213+
pretty = optionsData.pretty ?? false;
214+
formatErrorFn =
215+
optionsData.customFormatErrorFn ??
216+
optionsData.formatError ??
217+
formatErrorFn;
209218
throw error;
210219
}
211220

212221
// Then, resolve the Options to get OptionsData.
213-
optionsData = await resolveOptions(params);
222+
const optionsData: OptionsData = await resolveOptions(params);
214223

215224
// Collect information from the options data object.
216225
const schema = optionsData.schema;
@@ -225,6 +234,12 @@ function graphqlHTTP(options: Options): Middleware {
225234
const executeFn = optionsData.customExecuteFn ?? execute;
226235
const validateFn = optionsData.customValidateFn ?? validate;
227236

237+
pretty = optionsData.pretty ?? false;
238+
formatErrorFn =
239+
optionsData.customFormatErrorFn ??
240+
optionsData.formatError ??
241+
formatErrorFn;
242+
228243
// Assert that schema is required.
229244
if (schema == null) {
230245
throw httpError(
@@ -354,7 +369,7 @@ function graphqlHTTP(options: Options): Middleware {
354369
}
355370
}
356371

357-
result = { errors: error.graphqlErrors ?? [error] };
372+
result = { data: undefined, errors: error.graphqlErrors ?? [error] };
358373
}
359374

360375
// If no data was included in the result, that indicates a runtime query
@@ -368,10 +383,6 @@ function graphqlHTTP(options: Options): Middleware {
368383

369384
// Format any encountered errors.
370385
if (result.errors) {
371-
const formatErrorFn =
372-
optionsData?.customFormatErrorFn ??
373-
optionsData?.formatError ??
374-
formatError;
375386
(result: any).errors = result.errors.map(formatErrorFn);
376387
}
377388

@@ -383,7 +394,6 @@ function graphqlHTTP(options: Options): Middleware {
383394
// If "pretty" JSON isn't requested, and the server provides a
384395
// response.json method (express), use that directly.
385396
// Otherwise use the simplified sendResponse method.
386-
const pretty = optionsData?.pretty || false;
387397
if (!pretty && typeof response.json === 'function') {
388398
response.json(result);
389399
} else {
@@ -394,9 +404,11 @@ function graphqlHTTP(options: Options): Middleware {
394404
async function resolveOptions(
395405
requestParams?: GraphQLParams,
396406
): Promise<OptionsData> {
397-
const optionsResult = await (typeof options === 'function'
398-
? options(request, response, requestParams)
399-
: options);
407+
const optionsResult = await Promise.resolve(
408+
typeof options === 'function'
409+
? options(request, response, requestParams)
410+
: options,
411+
);
400412

401413
// Assert that optionsData is in fact an Object.
402414
if (optionsResult == null || typeof optionsResult !== 'object') {
@@ -419,17 +431,17 @@ function graphqlHTTP(options: Options): Middleware {
419431

420432
function respondWithGraphiQL(
421433
response: $Response,
422-
options: ?GraphiQLOptions,
434+
options?: GraphiQLOptions,
423435
params?: GraphQLParams,
424436
result?: ExecutionResult,
425437
): void {
426-
const payload = renderGraphiQL({
438+
const data: GraphiQLData = {
427439
query: params?.query,
428440
variables: params?.variables,
429441
operationName: params?.operationName,
430442
result,
431-
options,
432-
});
443+
};
444+
const payload = renderGraphiQL(data, options);
433445
return sendResponse(response, 'text/html', payload);
434446
}
435447

src/parseBody.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import getBody from 'raw-body';
88
import httpError from 'http-errors';
99
import contentType from 'content-type';
1010

11-
type $Request = IncomingMessage & { body?: ?mixed, ... };
11+
type $Request = IncomingMessage & { body?: mixed, ... };
1212

1313
/**
1414
* Provided a "Request" provided by express or connect (typically a node style

src/renderGraphiQL.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
import { type ExecutionResult } from 'graphql';
44

5-
type GraphiQLData = {|
6-
query: ?string,
7-
variables: ?{ +[name: string]: mixed, ... },
8-
operationName: ?string,
9-
result: ?ExecutionResult,
10-
options: ?GraphiQLOptions,
5+
export type GraphiQLData = {|
6+
query?: string | null,
7+
variables?: { +[name: string]: mixed, ... } | null,
8+
operationName?: string | null,
9+
result?: ExecutionResult,
1110
|};
1211

1312
export type GraphiQLOptions = {|
@@ -16,7 +15,7 @@ export type GraphiQLOptions = {|
1615
* query exists from a previous session. If undefined is provided, GraphiQL
1716
* will use its own default query.
1817
*/
19-
defaultQuery?: ?string,
18+
defaultQuery?: string,
2019
|};
2120

2221
// Ensures string values are safe to be used within a <script> tag.
@@ -36,14 +35,17 @@ declare function loadFileStaticlyFromNPM(npmPath: string): string;
3635
* When shown, it will be pre-populated with the result of having executed the
3736
* requested query.
3837
*/
39-
export function renderGraphiQL(data: GraphiQLData): string {
38+
export function renderGraphiQL(
39+
data: GraphiQLData,
40+
options?: GraphiQLOptions,
41+
): string {
4042
const queryString = data.query;
4143
const variablesString =
4244
data.variables != null ? JSON.stringify(data.variables, null, 2) : null;
4345
const resultString =
4446
data.result != null ? JSON.stringify(data.result, null, 2) : null;
4547
const operationName = data.operationName;
46-
const defaultQuery = data.options?.defaultQuery;
48+
const defaultQuery = options?.defaultQuery;
4749

4850
return `<!--
4951
The request to this GraphQL server provided the header "Accept: text/html"

0 commit comments

Comments
 (0)