Skip to content

Commit c8c28d0

Browse files
Alan-ChaErikWittern
authored andcommitted
Add provideErrorExtension option
Signed-off-by: Alan Cha <[email protected]>
1 parent 7c104f3 commit c8c28d0

File tree

11 files changed

+137
-34
lines changed

11 files changed

+137
-34
lines changed

packages/oasgraph/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ The options object can contain the following properties:
157157

158158
* `requestOptions` (type: `object`, default: `{}`): Additional [options](https://github.com/request/request#requestoptions-callback), provided by the [`Request` module](https://github.com/request/request), that can be used to configure the HTTP calls that powers the generated GraphQL resolvers. A common use case is to use this to up set a web proxy with the `proxy` field.
159159

160+
* `provideErrorExtensions` (type: `boolean`, default: `true`): If a query cannot fulfilled, GraphQL will provide a [list of error objects](https://graphql.github.io/graphql-spec/draft/#sec-Errors) for all fields that could not be resolved. OASGraph will add an extensions to all error objects resulting from REST calls that did not return successful HTTP codes (i.e. 200-299). These extensions contain data about the REST call (e.g. the method, path, status code, response headers, and response body). This data can be useful for debugging but it can also _unintentionally leak information_. This option prevents the error extensions from being created.
161+
160162
Consider this example of passing options:
161163

162164
```javascript

packages/oasgraph/lib/index.js

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/oasgraph/lib/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/oasgraph/lib/resolver_builder.js

Lines changed: 14 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/oasgraph/lib/resolver_builder.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/oasgraph/lib/types/options.d.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ export declare type Options = {
7979
* e.g. Setup the web proxy to use.
8080
*/
8181
requestOptions?: NodeRequest.OptionsWithUrl;
82+
/**
83+
* The error extension is part of the GraphQLErrors that will be returned if
84+
* the query cannot be fulfilled. It provides information about the REST call
85+
* that could be fulfilled (e.g. the method, path, status code, response
86+
* headers, and response body). It can be useful for debugging but may
87+
* unintentionally leak information.
88+
*
89+
* This option prevents the extension from being created.
90+
*/
91+
provideErrorExtensions?: boolean;
8292
};
8393
export declare type InternalOptions = {
8494
/**
@@ -148,4 +158,14 @@ export declare type InternalOptions = {
148158
* e.g. Setup the web proxy to use.
149159
*/
150160
requestOptions?: NodeRequest.OptionsWithUrl;
161+
/**
162+
* The error extension is part of the GraphQLErrors that will be returned if
163+
* the query cannot be fulfilled. It provides information about the REST call
164+
* that could be fulfilled (e.g. the method, path, status code, response
165+
* headers, and response body). It can be useful for debugging but may
166+
* unintentionally leak information.
167+
*
168+
* This option prevents the extension from being created.
169+
*/
170+
provideErrorExtensions: boolean;
151171
};

packages/oasgraph/src/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ export async function createGraphQlSchema (
8888
options.operationIdFieldNames = typeof options.operationIdFieldNames === 'boolean'
8989
? options.operationIdFieldNames
9090
: false
91+
options.provideErrorExtensions = typeof options.provideErrorExtensions === 'boolean'
92+
? options.provideErrorExtensions
93+
: true
9194

9295
options['report'] = {
9396
warnings: [],
@@ -140,7 +143,8 @@ async function translateOpenApiToGraphQL (
140143
baseUrl,
141144
operationIdFieldNames,
142145
report,
143-
requestOptions
146+
requestOptions,
147+
provideErrorExtensions
144148
}: InternalOptions
145149
): Promise<{ schema: GraphQLSchema, report: Report }> {
146150
let options = {
@@ -154,7 +158,8 @@ async function translateOpenApiToGraphQL (
154158
baseUrl,
155159
operationIdFieldNames,
156160
report,
157-
requestOptions
161+
requestOptions,
162+
provideErrorExtensions
158163
}
159164
log(`Options: ${JSON.stringify(options)}`)
160165

packages/oasgraph/src/resolver_builder.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -270,15 +270,20 @@ export function getResolver({
270270
log(`${response.statusCode} - ${Oas3Tools.trim(body, 100)}`)
271271

272272
const operationString = `${operation.method.toUpperCase()} ${operation.path}`
273-
const extensions = {
274-
method: operation.method,
275-
path: operation.path,
276-
277-
statusCode: response.statusCode,
278-
responseHeaders: response.headers,
279-
responseBody: JSON.parse(body)
273+
const errorString = `Could not invoke operation ${operationString}`
274+
if (data.options.provideErrorExtensions) {
275+
const extensions = {
276+
method: operation.method,
277+
path: operation.path,
278+
279+
statusCode: response.statusCode,
280+
responseHeaders: response.headers,
281+
responseBody: JSON.parse(body)
282+
}
283+
reject(graphQLErrorWithExtensions(errorString, extensions))
284+
} else {
285+
reject(new Error(errorString))
280286
}
281-
reject(graphQLErrorWithExtensions(`Could not invoke operation ${operationString}`, extensions))
282287

283288
} else {
284289
log(`${response.statusCode} - ${Oas3Tools.trim(body, 100)}`)

packages/oasgraph/src/types/options.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ export type Options = {
9393
* e.g. Setup the web proxy to use.
9494
*/
9595
requestOptions?: NodeRequest.OptionsWithUrl
96+
97+
/**
98+
* The error extensions is part of the GraphQLErrors that will be returned if
99+
* the query cannot be fulfilled. It provides information about the REST call
100+
* that could be fulfilled (e.g. the method, path, status code, response
101+
* headers, and response body). It can be useful for debugging but may
102+
* unintentionally leak information.
103+
*
104+
* This option prevents the extensions from being created.
105+
*/
106+
provideErrorExtensions?: boolean
96107
}
97108

98109

@@ -170,4 +181,15 @@ export type InternalOptions = {
170181
* e.g. Setup the web proxy to use.
171182
*/
172183
requestOptions?: NodeRequest.OptionsWithUrl
184+
185+
/**
186+
* The error extensions is part of the GraphQLErrors that will be returned if
187+
* the query cannot be fulfilled. It provides information about the REST call
188+
* that could be fulfilled (e.g. the method, path, status code, response
189+
* headers, and response body). It can be useful for debugging but may
190+
* unintentionally leak information.
191+
*
192+
* This option prevents the extensions from being created.
193+
*/
194+
provideErrorExtensions: boolean
173195
}

packages/oasgraph/test/example_api.test.js

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -630,19 +630,19 @@ test('Define header and query options', () => {
630630
status2 (globalquery: "test")
631631
}`
632632
return OasGraph.createGraphQlSchema(oas, options)
633-
.then(({schema}) => {
634-
// validate that 'limit' parameter is covered by options:
635-
let ast = parse(query)
636-
let errors = validate(schema, ast)
637-
expect(errors).toEqual([])
638-
return graphql(schema, query).then(result => {
639-
expect(result).toEqual({
640-
data: {
641-
status2: 'Ok.'
642-
}
643-
})
633+
.then(({schema}) => {
634+
// validate that 'limit' parameter is covered by options:
635+
let ast = parse(query)
636+
let errors = validate(schema, ast)
637+
expect(errors).toEqual([])
638+
return graphql(schema, query).then(result => {
639+
expect(result).toEqual({
640+
data: {
641+
status2: 'Ok.'
642+
}
644643
})
645644
})
645+
})
646646
})
647647

648648
test('Resolve allOf', () => {
@@ -695,4 +695,43 @@ test('Error contains extension', () => {
695695
}
696696
})
697697
})
698+
})
699+
700+
test('Option provideErrorExtensions should prevent error extensions from being created', () => {
701+
let options = {
702+
provideErrorExtensions: false
703+
}
704+
let query = `query {
705+
user(username: "abcdef") {
706+
name
707+
}
708+
}`
709+
return OasGraph.createGraphQlSchema(oas, options)
710+
.then(({schema}) => {
711+
// validate that 'limit' parameter is covered by options:
712+
let ast = parse(query)
713+
let errors = validate(schema, ast)
714+
expect(errors).toEqual([])
715+
return graphql(schema, query).then(result => {
716+
expect(result).toEqual({
717+
"errors": [
718+
{
719+
"message": "Could not invoke operation GET /users/{username}",
720+
"locations": [
721+
{
722+
"line": 2,
723+
"column": 5
724+
}
725+
],
726+
"path": [
727+
"user"
728+
]
729+
}
730+
],
731+
"data": {
732+
"user": null
733+
}
734+
})
735+
})
736+
})
698737
})

0 commit comments

Comments
 (0)