Skip to content

Commit e207168

Browse files
committed
Refactoring and doc improvements
Signed-off-by: Alan Cha <[email protected]>
1 parent 951e8ef commit e207168

23 files changed

+312
-128
lines changed

packages/openapi-to-graphql/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ Notice that the slashes in the path `/favoriteBooks/{name}` must be escaped with
133133

134134
### File Uploads
135135

136-
Support for file uploads through GraphQL is implemented based on the spec defined [here](https://github.com/jaydenseric/graphql-multipart-request-spec), through the module [`graphql-upload`](https://github.com/jaydenseric/graphql-upload). This requires that to opt-in for file uploads, it is required that a GraphQL client that provides support for the spec is used, additionally, on the Graphql Server the util method `processRequest` provided by the module `graphql-upload` is integrated to format the received request body to match the expectations for the spec.
136+
Support for file uploads through GraphQL is implemented based on the spec defined [here](https://github.com/jaydenseric/graphql-multipart-request-spec), through the module [`graphql-upload`](https://github.com/jaydenseric/graphql-upload). To opt in for file uploads, a GraphQL client that provides support for the spec must be used. Additionally, on the GraphQL server, the util method `processRequest` provided by the module `graphql-upload` must be integrated to format the received request body to match the expectations for the spec.
137137

138138
### Options
139139

@@ -187,7 +187,7 @@ Resolver options:
187187

188188
- `customSubscriptionResolvers` (type: `object`, default: `{}`): If the `createSubscriptionsFromCallbacks` is enabled, OpenAPI-to-GraphQL will generate Subscription fields. This option allows users to provide custom resolver and subscribe functions to be used in place of said ones created by OpenAPI-to-GraphQL. The field that the custom resolver and subscribe functions will affect is identifed first by the [title](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#infoObject) of the OAS, then the [path](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#paths-object) of the operation, and lastly the [method](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#path-item-object) of the operation. The resolver is provided via the `resolver` field and the publish function is provided via the `publish` field. The `customSubscriptionResolvers` object is thus a quadruply nested object where the outer key is the title, followed by the path, then the method, and lastly either `resolver` or `publish` which points to the [resolver function](https://graphql.org/learn/execution/#root-fields-resolvers) itself or publish function. See the [Subscriptions tutorial](./docs/subscriptions.md) for more information. _Note: Because the arguments are provided by the GraphQL interface, they may look different from the [parameters](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#parameterObject) defined by the OAS. For example, they will have [sanitized](https://github.com/IBM/openapi-to-graphql#characteristics) names. The [request body](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#requestBodyObject) will also be contained in the arguments as an [input object type](https://graphql.org/graphql-js/mutations-and-input-types/)._
189189

190-
- `fileUploadOptions` (type: `object`, default: `{}`): This options allows users to provide custom options for the form data object that will be used to process requests to endpoints that require a multipart request body, provided through the [`form-data` module](https://github.com/form-data/form-data)
190+
- `fileUploadOptions` (type: `object`, default: `{}`): This options allows users to provide custom options for the form data object that will be used to process requests to endpoints that require a multipart request body, provided through the [`form-data` module](https://github.com/form-data/form-data). See [file uploads](#file-uploads).
191191

192192
***
193193

packages/openapi-to-graphql/src/resolver_builder.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -328,14 +328,14 @@ export function getPublishResolver<TSource, TContext, TArgs>({
328328
* If the operation type is Query or Mutation, create and return a resolver
329329
* function that performs API requests for the given GraphQL query
330330
*/
331-
export function getResolver<TSource, TContext, TArgs> ({
331+
export function getResolver<TSource, TContext, TArgs>({
332332
operation,
333333
argsFromLink = {},
334334
payloadName,
335335
data,
336336
baseUrl,
337337
requestOptions,
338-
fileUploadOptions,
338+
fileUploadOptions,
339339
fetch
340340
}: GetResolverParams<TSource, TContext, TArgs>): GraphQLFieldResolver<
341341
TSource & OpenAPIToGraphQLSource<TSource, TContext, TArgs>,
@@ -560,7 +560,7 @@ export function getResolver<TSource, TContext, TArgs> ({
560560
* GraphQL produces sanitized payload names, so we have to sanitize before
561561
* lookup here
562562
*/
563-
let form
563+
let form: FormData
564564
resolveData.usedPayload = undefined
565565
if (typeof payloadName === 'string') {
566566
// The option genericPayloadArgName will change the payload name to "requestBody"
@@ -595,7 +595,7 @@ export function getResolver<TSource, TContext, TArgs> ({
595595

596596
originalFileStream.on('readable', function () {
597597
let data
598-
// tslint:disable-next-line:no-conditional-assignment
598+
599599
while (data = this.read()) {
600600
const canReadNext = filePassThrough.write(data)
601601
if (!canReadNext) {
@@ -621,7 +621,7 @@ export function getResolver<TSource, TContext, TArgs> ({
621621
contentType: uploadingFile.mimetype
622622
})
623623
} else if (typeof fieldValue !== 'string') {
624-
// handle all other primitives that aren't strings as strings the way the web server would expect it
624+
// Handle all other primitives that aren't strings as strings the way the web server would expect it
625625
form.append(fieldName, JSON.stringify(fieldValue))
626626
} else {
627627
form.append(fieldName, fieldValue)
@@ -657,9 +657,13 @@ export function getResolver<TSource, TContext, TArgs> ({
657657
}
658658

659659
if (form) {
660+
/**
661+
* When there is a form, remove default content type and leave
662+
* computation of content-type header to fetch
663+
*
664+
* See https://github.com/github/fetch/issues/505#issuecomment-293064470
665+
*/
660666
Object.assign(options.headers, form.getHeaders())
661-
// when is form, remove default content type and leave computation of content-type header to fetch
662-
// see https://github.com/github/fetch/issues/505#issuecomment-293064470
663667
delete options.headers['content-type']
664668
}
665669
}

packages/openapi-to-graphql/src/types/options.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ export type InternalOptions<TSource, TContext, TArgs> = {
291291
* Allows one to define config for the form data that will be used in streaming
292292
* the uploaded file from the client to the intending endpoint
293293
*
294-
* Based on https://github.com/form-data/form-data#custom-options
294+
* Based on: https://github.com/form-data/form-data#custom-options
295295
*/
296296
fileUploadOptions?: FileUploadOptions
297297

packages/openapi-to-graphql/test/README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ The following table summarizes the purposes of these tests.
2525
| Test file | API(s) | Testing purpose |
2626
|---|---|---|
2727
| `example_api.test.ts` | `Example API` | An assortment of basic functionality and options on a company-themed API |
28-
| `authentication.test.ts` | `Example API` | Basic authentication tests including using the [viewer functionality](https://github.com/IBM/openapi-to-graphql/blob/master/packages/openapi-to-graphql/README.md#authentication) |
29-
| `example_api2.test.ts` | `Example API 2` | The [`operationIdFieldNames` option](https://github.com/IBM/openapi-to-graphql/blob/master/packages/openapi-to-graphql/README.md#options) |
30-
| `example_api3.test.ts` | `Example API` and `Example API 3` | Creating GraphQL wrappers from multiple APIs and [interOAS links](https://github.com/IBM/openapi-to-graphql/blob/master/packages/openapi-to-graphql/README.md#nested-objects) |
28+
| `authentication.test.ts` | `Example API` | Basic authentication tests including using the [viewer functionality](../README.md#authentication) |
29+
| `example_api2.test.ts` | `Example API 2` | The [`operationIdFieldNames` option](../README.md#options) |
30+
| `example_api3.test.ts` | `Example API` and `Example API 3` | Creating GraphQL wrappers from multiple APIs and [interOAS links](../README.md#nested-objects) |
3131
| `example_api4.test.ts` | `Example API 4` | JSON schema [combining schema](https://json-schema.org/understanding-json-schema/reference/combining.html) keywords |
32-
| `example_api5.test.ts` | `Example API 5` | The [`simpleNames` option](https://github.com/IBM/openapi-to-graphql/blob/master/packages/openapi-to-graphql/README.md#options) |
32+
| `example_api5.test.ts` | `Example API 5` | The [`simpleNames` option](../README.md#options) |
3333
| `example_api6.test.ts` | `Example API 6` | An assortment of other functionality and options |
3434
| `example_api7.test.ts` | `Example API 7` | [Subscription support](../docs/subscriptions.md) |
35+
| `file_upload.test.ts` | `File Upload API` | [File uploads](../README.md#file-uploads) and [file upload options](../README.md#options) |
3536
| `extensions.test.ts` | `Extensions`, `Extensions Error 1`, `Extensions Error 2`, `Extensions Error 3`, `Extensions Error 4`, `Extensions Error 5`, `Extensions Error 6`, `Extensions Error 7` | The [`x-graphql-field-name`, `x-graphql-type-name`, and `x-graphql-enum-mapping` extensions](https://github.com/IBM/openapi-to-graphql/tree/master/packages/openapi-to-graphql#custom-type-and-field-names-and-enum-values)

packages/openapi-to-graphql/test/authentication.test.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
'use strict'
77

8-
import { graphql } from 'graphql'
8+
import { graphql, GraphQLSchema } from 'graphql'
99
import { afterAll, beforeAll, expect, test } from '@jest/globals'
1010

1111
import * as openAPIToGraphQL from '../src/index'
@@ -16,11 +16,9 @@ const PORT = 3003
1616
// update PORT for this test case:
1717
oas.servers[0].variables.port.default = String(PORT)
1818

19-
let createdSchema
19+
let createdSchema: GraphQLSchema
2020

21-
/**
22-
* Set up the schema first and run example API server
23-
*/
21+
// Set up the schema first and run example API server
2422
beforeAll(() => {
2523
return Promise.all([
2624
openAPIToGraphQL.createGraphQLSchema(oas).then(({ schema }) => {
@@ -30,9 +28,7 @@ beforeAll(() => {
3028
])
3129
})
3230

33-
/**
34-
* Shut down API server
35-
*/
31+
// Shut down API server
3632
afterAll(() => {
3733
return stopServer()
3834
})

packages/openapi-to-graphql/test/cloudfunction.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55

66
'use strict'
77

8-
import { graphql, parse, validate } from 'graphql'
8+
import { graphql, GraphQLSchema, parse, validate } from 'graphql'
99
import { afterAll, beforeAll, expect, test } from '@jest/globals'
1010

1111
import * as openAPIToGraphQL from '../src/index'
1212

1313
const oas = require('./fixtures/cloudfunction.json')
1414

15-
let createdSchema
15+
let createdSchema: GraphQLSchema
1616

1717
beforeAll(async () => {
1818
const { schema } = await openAPIToGraphQL.createGraphQLSchema(oas)

packages/openapi-to-graphql/test/example_api.test.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
'use strict'
77

8-
import { graphql, parse, validate } from 'graphql'
8+
import { graphql, GraphQLInputObjectType, GraphQLInputObjectTypeConfig, GraphQLObjectTypeConfig, GraphQLSchema, parse, validate } from 'graphql'
99
import { afterAll, beforeAll, expect, test } from '@jest/globals'
1010

1111
import * as openAPIToGraphQL from '../src/index'
@@ -18,11 +18,9 @@ const PORT = 3002
1818
// Update PORT for this test case:
1919
oas.servers[0].variables.port.default = String(PORT)
2020

21-
let createdSchema
21+
let createdSchema: GraphQLSchema
2222

23-
/**
24-
* Set up the schema first and run example API server
25-
*/
23+
// Set up the schema first and run example API server
2624
beforeAll(() => {
2725
return Promise.all([
2826
openAPIToGraphQL
@@ -36,9 +34,7 @@ beforeAll(() => {
3634
])
3735
})
3836

39-
/**
40-
* Shut down API server
41-
*/
37+
// Shut down API server
4238
afterAll(() => {
4339
return stopServer()
4440
})
@@ -1959,10 +1955,10 @@ test('Required properties for input object types', () => {
19591955
const userInputType = createdSchema.getType('UserInput')
19601956

19611957
// The exclamation mark shows that it is a required (non-nullable) property
1962-
expect(userInputType.toConfig().fields.address.type.toString()).toEqual(
1958+
expect((userInputType.toConfig() as GraphQLInputObjectTypeConfig).fields['address'].type.toString()).toEqual(
19631959
'AddressInput!'
19641960
)
1965-
expect(userInputType.toConfig().fields.address2.type.toString()).toEqual(
1961+
expect((userInputType.toConfig() as GraphQLInputObjectTypeConfig).fields['address2'].type.toString()).toEqual(
19661962
'AddressInput'
19671963
)
19681964
})
@@ -2312,8 +2308,8 @@ test('Non-nullable properties for object types', () => {
23122308
const coordinates = createdSchema.getType('Coordinates')
23132309

23142310
// The exclamation mark shows that it is a required (non-nullable) property
2315-
expect(coordinates.toConfig().fields.lat.type.toString()).toEqual('Float!')
2316-
expect(coordinates.toConfig().fields.long.type.toString()).toEqual('Float!')
2311+
expect((coordinates.toConfig() as GraphQLObjectTypeConfig<any, any>).fields['lat'].type.toString()).toEqual('Float!')
2312+
expect((coordinates.toConfig() as GraphQLObjectTypeConfig<any, any>).fields['long'].type.toString()).toEqual('Float!')
23172313
})
23182314

23192315
test('Option genericPayloadArgName', () => {

packages/openapi-to-graphql/test/example_api2.test.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
'use strict'
77

8-
import { graphql } from 'graphql'
8+
import { graphql, GraphQLObjectType, GraphQLSchema } from 'graphql'
99
import { afterAll, beforeAll, expect, test } from '@jest/globals'
1010

1111
import * as openAPIToGraphQL from '../src/index'
@@ -16,7 +16,7 @@ const PORT = 3004
1616
// Update PORT for this test case:
1717
oas.servers[0].variables.port.default = String(PORT)
1818

19-
let createdSchema
19+
let createdSchema: GraphQLSchema
2020

2121
/**
2222
* This test suite is used to verify the behavior of the operationIdFieldNames
@@ -26,9 +26,7 @@ let createdSchema
2626
* have operationIDs.
2727
*/
2828

29-
/**
30-
* Set up the schema first and run example API server
31-
*/
29+
// Set up the schema first and run example API server
3230
beforeAll(() => {
3331
return Promise.all([
3432
openAPIToGraphQL
@@ -40,9 +38,7 @@ beforeAll(() => {
4038
])
4139
})
4240

43-
/**
44-
* Shut down API server
45-
*/
41+
// Shut down API server
4642
afterAll(() => {
4743
return stopServer()
4844
})
@@ -62,7 +58,7 @@ test('The option operationIdFieldNames should allow both operations to be presen
6258
}
6359
}
6460

65-
const gqlTypes = Object.keys(createdSchema._typeMap.Query.getFields()).length
61+
const gqlTypes = Object.keys((createdSchema.getTypeMap().Query as GraphQLObjectType).getFields()).length
6662
expect(gqlTypes).toEqual(oasGetCount)
6763
})
6864

packages/openapi-to-graphql/test/example_api3.test.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
'use strict'
77

8-
import { graphql, parse, validate } from 'graphql'
8+
import { graphql, GraphQLSchema, parse, validate } from 'graphql'
99
import { afterAll, beforeAll, expect, test } from '@jest/globals'
1010

1111
import * as openAPIToGraphQL from '../src/index'
@@ -22,16 +22,14 @@ const PORT2 = 3006
2222
oas.servers[0].variables.port.default = String(PORT)
2323
oas3.servers[0].variables.port.default = String(PORT2)
2424

25+
let createdSchema: GraphQLSchema
26+
2527
/**
2628
* This test suite is used to verify the behavior of interOAS links, i.e.
2729
* links across different OASs
2830
*/
2931

30-
let createdSchema
31-
32-
/**
33-
* Set up the schema first and run example API server
34-
*/
32+
// Set up the schema first and run example API server
3533
beforeAll(() => {
3634
return Promise.all([
3735
openAPIToGraphQL
@@ -44,9 +42,7 @@ beforeAll(() => {
4442
])
4543
})
4644

47-
/**
48-
* Shut down API server
49-
*/
45+
// Shut down API server
5046
afterAll(() => {
5147
return Promise.all([api.stopServer(), api2.stopServer()])
5248
})

packages/openapi-to-graphql/test/example_api4.test.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,18 @@
55

66
'use strict'
77

8-
import { graphql } from 'graphql'
8+
import { graphql, GraphQLSchema } from 'graphql'
99
import { afterAll, beforeAll, expect, test } from '@jest/globals'
1010

1111
import * as openAPIToGraphQL from '../src/index'
1212

1313
const oas = require('./fixtures/example_oas4.json')
1414

15-
// This test suite is used to verify the behavior of anyOf and oneOf handling
15+
let createdSchema: GraphQLSchema
1616

17-
let createdSchema
17+
// This test suite is used to verify the behavior of anyOf and oneOf handling
1818

19-
/**
20-
* Set up the schema
21-
*/
19+
// Set up the schema
2220
beforeAll(() => {
2321
return openAPIToGraphQL
2422
.createGraphQLSchema(oas)

0 commit comments

Comments
 (0)