Skip to content

Commit c1e2e5b

Browse files
Alan-ChaErikWittern
authored andcommitted
Support for constant and variable link params
Fixed #85 Signed-off-by: Alan Cha <[email protected]>
1 parent 6dce0e2 commit c1e2e5b

File tree

7 files changed

+294
-44
lines changed

7 files changed

+294
-44
lines changed

packages/oasgraph/lib/resolver_builder.js

Lines changed: 76 additions & 21 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/src/resolver_builder.ts

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -89,34 +89,37 @@ export function getResolver ({
8989

9090
// handle arguments provided by links
9191
for (let paramName in argsFromLink) {
92-
let value = argsFromLink[paramName]
93-
94-
// parameter names can specify location of parameter (e.g., path.id)
9592
let paramNameWithoutLocation = paramName
9693
if (paramName.indexOf('.') !== -1) {
9794
paramNameWithoutLocation = paramName.split('.')[1]
9895
}
9996

100-
// CASE: parameter in body
101-
if (/body#/.test(value)) {
102-
let tokens = JSONPath.JSONPath({ path: value.split('body#/')[1], json: root })
103-
if (Array.isArray(tokens) && tokens.length > 0) {
104-
args[paramNameWithoutLocation] = tokens[0]
97+
// link parameter
98+
let value = argsFromLink[paramName]
99+
100+
/**
101+
* see if the link parameter contains constants that are appended to the link parameter
102+
*
103+
* e.g. instead of:
104+
* $response.body#/employerId
105+
*
106+
* it could be:
107+
* abc_{$response.body#/employerId}
108+
*/
109+
if (value.search(/{|}/) === -1) {
110+
if (isRuntimeExpression(value)) {
111+
args[paramNameWithoutLocation] = resolveLinkParameter(paramName, value, _oasgraph, root)
105112
} else {
106-
log(`Warning: could not extract parameter ${paramName} form link`)
113+
args[paramNameWithoutLocation] = value
107114
}
108-
// CASE: parameter in previous query parameter
109-
} else if (/query\./.test(value)) {
110-
args[paramNameWithoutLocation] =
111-
_oasgraph.usedParams[Oas3Tools.beautify(value.split('query.')[1])]
112-
// CASE: parameter in previous path parameter
113-
} else if (/path\./.test(value)) {
114-
args[paramNameWithoutLocation] =
115-
_oasgraph.usedParams[Oas3Tools.beautify(value.split('path.')[1])]
116-
// CASE: link OASGraph currently does not support
117115
} else {
118-
log(`Warning: could not process link parameter ${paramName} with ` +
119-
`value ${value}`)
116+
// replace link parameters with appropriate values
117+
let linkParams = value.match(/{([^}]*)}/g)
118+
linkParams.forEach((linkParam) => {
119+
value = value.replace(linkParam, resolveLinkParameter(paramName, linkParam.substring(1, linkParam.length - 1), _oasgraph, root))
120+
})
121+
122+
args[paramNameWithoutLocation] = value
120123
}
121124
}
122125

@@ -428,3 +431,61 @@ function getAuthReqAndProtcolName (
428431
authRequired
429432
}
430433
}
434+
435+
/**
436+
* Given a link parameter, determine the value
437+
*
438+
* The link parameter is a reference to data contained in the
439+
* url/method/statuscode or response/request body/query/path/header
440+
*/
441+
function resolveLinkParameter(paramName: string, value: string, _oasgraph: any, root: any): any {
442+
// CASE: parameter in body
443+
if (/body#/.test(value)) {
444+
let tokens = JSONPath.JSONPath({ path: value.split('body#/')[1], json: root })
445+
if (Array.isArray(tokens) && tokens.length > 0) {
446+
return tokens[0]
447+
} else {
448+
log(`Warning: could not extract parameter ${paramName} from link`)
449+
}
450+
451+
// CASE: parameter in previous query parameter
452+
} else if (/query\./.test(value)) {
453+
return _oasgraph.usedParams[Oas3Tools.beautify(value.split('query.')[1])]
454+
455+
// CASE: parameter in previous path parameter
456+
} else if (/path\./.test(value)) {
457+
return _oasgraph.usedParams[Oas3Tools.beautify(value.split('path.')[1])]
458+
459+
// CASE: link OASGraph currently does not support
460+
} else {
461+
log(`Warning: could not process link parameter ${paramName} with ` +
462+
`value ${value}`)
463+
}
464+
}
465+
466+
/**
467+
* Check if a string is a runtime expression in the context of link parameters
468+
*/
469+
function isRuntimeExpression(str: string): boolean {
470+
let references = ["header.", "query.", "path.", "body"]
471+
472+
if (str.startsWith("$url") || str.startsWith("$method") || str.startsWith("$statusCode")) {
473+
return true
474+
475+
} else if (str.startsWith("$request.")) {
476+
for (let i = 0; i < references.length; i++) {
477+
if (str.startsWith(`$request.${references[i]}`)) {
478+
return true
479+
}
480+
}
481+
482+
} else if (str.startsWith("$response.")) {
483+
for (let i = 0; i < references.length; i++) {
484+
if (str.startsWith(`$response.${references[i]}`)) {
485+
return true
486+
}
487+
}
488+
}
489+
490+
return false
491+
}

packages/oasgraph/test/example_api.test.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,41 @@ test('Get nested resource via link operationRef', () => {
163163
})
164164
})
165165

166+
test('Link parameters as constant and as a variable', () => {
167+
let query = `{
168+
scanner(query: "hello") {
169+
query
170+
basicQueryProtocol{
171+
query
172+
}
173+
variableQueryProtocol{
174+
query
175+
}
176+
constantQueryProtocol{
177+
query
178+
}
179+
}
180+
}`
181+
return graphql(createdSchema, query).then(result => {
182+
expect(result).toEqual({
183+
data: {
184+
"scanner": {
185+
"query": "hello",
186+
"basicQueryProtocol": {
187+
"query": "hello"
188+
},
189+
"variableQueryProtocol": {
190+
"query": "_hello_hellohelloabchello123"
191+
},
192+
"constantQueryProtocol": {
193+
"query": "123"
194+
}
195+
}
196+
}
197+
})
198+
})
199+
})
200+
166201
test('Get response without providing parameter with default value', () => {
167202
let query = `{
168203
productsReviews (id: "100") {

packages/oasgraph/test/example_api_server.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,11 @@ function startServer (PORT) {
312312
}
313313
})
314314

315+
app.get('/api/copier', (req, res) => {
316+
console.log(req.method, req.path, req.query, req.headers)
317+
res.status(200).send(req.query)
318+
})
319+
315320
app.get('/api/cleanDesks', (req, res) => {
316321
console.log(req.method, req.path)
317322
res.send('5 clean desks')
@@ -446,6 +451,11 @@ function startServer (PORT) {
446451
}
447452
})
448453

454+
app.get('/api/scanner', (req, res) => {
455+
console.log(req.method, req.path, req.query, req.headers)
456+
res.status(200).send(req.query)
457+
})
458+
449459
app.get('/api/snack', (req, res) => {
450460
console.log(req.method, req.path, req.query, req.headers)
451461
if ('snack_type' in req.headers && 'snack_size' in req.headers) {

packages/oasgraph/test/example_gql_server.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ const graphqlHTTP = require('express-graphql')
1010
const app = express()
1111
const OasGraph = require('../lib/index.js')
1212

13-
// let oas = require('./fixtures/example_oas.json')
13+
let oas = require('./fixtures/example_oas.json')
1414
// let oas = require('./fixtures/github_oas.json')
1515
// let oas = require('./fixtures/instagram.json')
1616
// let oas = require('./fixtures/government_social_work_api.json')
17-
let oas = require('./fixtures/weather_underground_api.json')
17+
// let oas = require('./fixtures/weather_underground_api.json')
1818

1919
// const yamljs = require('yamljs')
2020
// const fs = require('fs')

0 commit comments

Comments
 (0)