I had a scenario where I needed to find values for a key in a complex JavaScript object which could be nested n levels deep.
I found numerous approaches to doing this, most were overly complicated, so I thought I would share the most straightforward, concise process.
the Codeโ
You can do this in a straightforward function implementing the "tail call recursion" pattern to search for a key (key
) from the root of an object (obj
), excluding any keys in excludeKeys
.
This will return a list of values for the given key, searching all levels in all branches of the object.
function getAllValuesForKey(obj, key, excludeKeys=[], values=[]) {
for (let k in obj) {
if (typeof obj[k] === "object") {
if(!excludeKeys.includes(k)){
getAllValuesForKey(obj[k], key, excludeKeys, values)
}
} else {
if (k === key){
values.push(obj[k]);
}
}
}
return values;
}
Exampleโ
In parsing an OpenAPI or Swagger specification, I am looking for all of the schema refs
in a successful response body, for example:
paths:
'/orgs/{org}/actions/permissions/selected-actions':
get:
...
responses:
'200': '...'
however these refs can present in various different ways depending upon the response type, such as:
'200':
$ref: '#/components/responses/actions_runner_labels'
or
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/runner'
or
'200':
content:
application/json:
schema:
anyOf:
- $ref: '#/components/schemas/interaction-limit-response'
or
'200':
content:
application/json:
schema:
type: object
required:
- total_count
- runners
properties:
total_count:
type: integer
runners:
type: array
items:
$ref: '#/components/schemas/runner'
To find all of the schema refs without knowing the response type or structure I used the above function as follows (excluding refs for examples
):
function getRespSchemaName(op){
for(let respCode in op.responses){
if(respCode.startsWith('2')){
return getAllValuesForKey(op.responses[respCode], "$ref", ['examples']);
}
}
}
You can find this implementation in openapi-doc-util
and @stackql/openapi-doc-util
.
simple!
if you have enjoyed this post, please consider buying me a coffee โ to help me keep writing!