Skip to content

Commit d0317f3

Browse files
mtthAlan-Cha
authored andcommitted
Suport arbitrary JSON pointer references
References in API specs can contain characters which require escaping as described in [RFC 6901](https://tools.ietf.org/html/rfc6901). Forward slashes are particularly common in API specs since they are used as path item key. For example, [PagerDuty's spec](https://raw.githubusercontent.com/PagerDuty/api-schema/master/reference/REST/openapiv3.json) makes heavy use of them and can't be currently be imported. With this change, import works. Signed-off-by: Matthieu Monsch <[email protected]>
1 parent 1e845bf commit d0317f3

File tree

4 files changed

+44
-31
lines changed

4 files changed

+44
-31
lines changed

packages/openapi-to-graphql/package-lock.json

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

packages/openapi-to-graphql/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"form-urlencoded": "^4.1.1",
7272
"graphql-subscriptions": "^1.1.0",
7373
"graphql-type-json": "^0.2.1",
74+
"json-ptr": "^1.2.0",
7475
"jsonpath-plus": "^3.0.0",
7576
"oas-validator": "^3.1.0",
7677
"pluralize": "^8.0.0",

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

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import * as Swagger2OpenAPI from 'swagger2openapi'
4040
import * as OASValidator from 'oas-validator'
4141
import debug from 'debug'
4242
import { handleWarning } from './utils'
43+
import * as jsonptr from 'json-ptr'
4344
import * as pluralize from 'pluralize'
4445

4546
// Type definitions & exports:
@@ -231,37 +232,7 @@ export function countOperationsWithPayload(oas: Oas3): number {
231232
* Resolves the given reference in the given object.
232233
*/
233234
export function resolveRef(ref: string, oas: Oas3): any {
234-
// Break path into individual tokens
235-
const parts = ref.split('/')
236-
const resolvedObject = resolveRefHelper(oas, parts)
237-
238-
if (resolvedObject !== null) {
239-
return resolvedObject
240-
} else {
241-
throw new Error(
242-
`Could not resolve reference '${ref}' in OAS '${oas.info.title}'`
243-
)
244-
}
245-
}
246-
247-
/**
248-
* Helper for resolveRef
249-
*
250-
* @param parts The path to be resolved, but broken into tokens
251-
*/
252-
function resolveRefHelper(obj: object, parts?: string[]): any {
253-
if (parts.length === 0) {
254-
return obj
255-
}
256-
257-
const firstElement = parts.splice(0, 1)[0]
258-
if (firstElement in obj) {
259-
return resolveRefHelper(obj[firstElement], parts)
260-
} else if (firstElement === '#') {
261-
return resolveRefHelper(obj, parts)
262-
} else {
263-
return null
264-
}
235+
return jsonptr.get(oas, ref)
265236
}
266237

267238
/**

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const {
1414
graphql
1515
} = require('graphql')
1616
import * as Oas3Tools from '../lib/oas_3_tools'
17+
import { PathItemObject } from '../lib/types/oas3'
1718

1819
test('Applying sanitize multiple times does not change outcome', () => {
1920
const str = 'this Super*annoying-string()'
@@ -180,3 +181,38 @@ test('Properly treat null values during sanitization', () => {
180181
})
181182
})
182183
})
184+
185+
test('Handle encoded JSON pointer references', () => {
186+
const oas = {
187+
openapi: '3.0.0',
188+
info: {
189+
title: 'test',
190+
version: '0.0.1'
191+
},
192+
paths: {
193+
'/users': getPathItemObject('all'),
194+
'/users/{id}': getPathItemObject('one')
195+
}
196+
}
197+
198+
expect(Oas3Tools.resolveRef('/openapi', oas)).toBe('3.0.0')
199+
expect(Oas3Tools.resolveRef('/paths/~1users/description', oas)).toBe('all')
200+
expect(Oas3Tools.resolveRef('#/paths/~1users/description', oas)).toBe('all')
201+
expect(
202+
Oas3Tools.resolveRef('#/paths/~1users~1%7bid%7d/description', oas)
203+
).toBe('one')
204+
205+
function getPathItemObject(description): PathItemObject {
206+
return {
207+
description,
208+
get: {},
209+
put: {},
210+
post: {},
211+
delete: {},
212+
options: {},
213+
head: {},
214+
patch: {},
215+
trace: {}
216+
}
217+
}
218+
})

0 commit comments

Comments
 (0)