Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
@stoplight/json-ref-resolver
Advanced tools
Recursively resolve JSON pointers and remote authorities.
@stoplight/json-ref-resolver is a utility for resolving JSON references ($ref) in JSON documents. It helps in dereferencing and bundling JSON schemas or other JSON documents that contain references to other documents or internal references.
Dereferencing JSON References
This feature allows you to resolve internal JSON references within a document. The example shows how a reference to '#/bar' is resolved to the actual content of 'bar'.
const { resolve } = require('@stoplight/json-ref-resolver');
const document = {
"foo": { "$ref": "#/bar" },
"bar": { "baz": 123 }
};
resolve(document).then(result => {
console.log(result);
// Output: { foo: { baz: 123 }, bar: { baz: 123 } }
});
Resolving External JSON References
This feature allows you to resolve external JSON references by fetching the referenced document from a URL. The example shows how a reference to an external URL is resolved.
const { resolve } = require('@stoplight/json-ref-resolver');
const document = {
"foo": { "$ref": "http://example.com/bar.json" }
};
resolve(document).then(result => {
console.log(result);
// Output will depend on the content of http://example.com/bar.json
});
Custom Resolvers
This feature allows you to define custom resolvers for handling specific types of references. The example shows how to create a custom resolver for a 'custom://' scheme.
const { resolve } = require('@stoplight/json-ref-resolver');
const customResolver = {
canRead: (file) => file.url.startsWith('custom://'),
read: (file) => Promise.resolve({ custom: 'data' })
};
const document = {
"foo": { "$ref": "custom://example" }
};
resolve(document, { resolvers: [customResolver] }).then(result => {
console.log(result);
// Output: { foo: { custom: 'data' } }
});
json-schema-ref-parser is a powerful library for parsing, resolving, and dereferencing JSON Schema $ref pointers. It supports both internal and external references and provides similar functionality to @stoplight/json-ref-resolver. However, it is more focused on JSON Schema specifically.
json-ref-lite is a lightweight library for resolving JSON references. It is simpler and has fewer features compared to @stoplight/json-ref-resolver, making it suitable for basic use cases where performance and simplicity are priorities.
json-refs is another library for resolving JSON references. It provides a comprehensive set of features for both internal and external references, similar to @stoplight/json-ref-resolver. It also includes additional utilities for working with JSON references.
Follow $ref
values in JSON Schema, OpenAPI (formerly known as Swagger), and any other objects with $ref
values inside of them.
http://
, file://
, mongo://
, custom://
... etc, or use one of ours.Supported in modern browsers and node.
yarn add @stoplight/json-ref-resolver
All relevant types and options can be found in src/types.ts.
// Import the Resolver class.
import { Resolver } from "@stoplight/json-ref-resolver";
/**
* Create a Resolver instance. Resolve can be called on this instance multiple times to take advantage of caching.
*
* @param globalOpts {IResolverOpts} [{}]
*
* These options are used on every resolve call for this resolver instance.
*
* See `IResolverOpts` interface defined in [src/types.ts](src/types.ts) for available options.
*
* @return IResolver
*/
const resolver = new Resolver(globalOpts);
/**
* Resolve the passed in object, replacing all references.
* @param resolveOpts {any} - The object to resolve.
* @param resolveOpts {IResolveOpts} [{}]
*
* These options override any globalOpts specified on the resolver instance, and only apply during this resolve call.
*
* See `IResolveOpts` interface defined in [src/types.ts](src/types.ts) for available options.
*
* @return IResolveResult - see [src/types.ts](src/types.ts) for interface definition.
*/
const resolved = await resolver.resolve(sourceObj, resolveOpts);
By default, only inline references will be dereferenced.
import { Resolver } from "@stoplight/json-ref-resolver";
const resolver = new Resolver();
const resolved = await resolver.resolve({
user: {
$ref: "#/models/user"
},
models: {
user: {
name: "john"
}
}
});
// ==> result is the original object, with local refs resolved and replaced
expect(resolved.result).toEqual({
user: {
name: "john"
},
models: {
user: {
name: "john"
}
}
});
This will dereference the minimal number of references needed for the given target, and return the target.
In the example below, the address reference (https://slow-website.com/definitions#/address
) will NOT be dereferenced, since
it is not needed to resolve the #/user
jsonPointer target we have specified. However, #/models/user/card
IS dereferenced since
it is needed in order to full dereference the #/user
property.
import { Resolver } from "@stoplight/json-ref-resolver";
const resolver = new Resolver();
const resolved = await resolver.resolve(
{
user: {
$ref: "#/models/user"
},
address: {
$ref: "https://slow-website.com/definitions#/address"
},
models: {
user: {
name: "john",
card: {
$ref: "#/models/card"
}
},
card: {
type: "visa"
}
}
},
{
jsonPointer: "#/user"
}
);
// ==> result is the target object, with refs resolved and replaced
expect(resolved.result).toEqual({
name: "john",
card: {
type: "visa"
}
});
By default only inline references (those that point to values inside of the original object) are dereferenced.
In order to dereference remote URIs (file, http, etc) you must provide resolvers for each URI scheme.
Resolvers are keyed by scheme, receive the URI to fetch, and must return the fetched data.
import { Resolver } from "@stoplight/json-ref-resolver";
// some example http library
import * as axios from "axios";
// if we're in node, we create a file resolver with fs
import * as fs from "fs";
// create our resolver instance
const resolver = new Resolver({
// resolvers can do anything, so long as they define an async read function that resolves to a value
resolvers: {
// this resolver will be invoked for refs with the https protocol
https: {
async resolve(ref: uri.URI) {
return axios({
method: "get",
url: String(ref)
});
}
},
// this resolver will be invoked for refs with the file protocol
file: {
async resolve(ref: uri.URI) {
return fs.read(String(ref));
}
}
}
});
const resolved = await resolver.resolve({
definitions: {
someOASFile: {
$ref: "./main.oas2.yml#/definitions/user"
},
someMarkdownFile: {
$ref: "https://foo.com/intro.md"
}
}
});
// ==> result is the original object, with refs resolved and replaced
expect(resolved.result).toEqual({
definitions: {
someOASFile: {
// ... the data located in the relative file `./main.oas2.yml` and inner json path `#/definitions/user`
},
someMarkdownFile: {
// ... the data located at the url `https://foo.com/intro.md`
}
}
});
If there are relative remote references (for example, a relative file path ../model.json
), then the location of the source
data must be specified via the baseUri
option. Relative references will be dereferenced against this baseUri.
import { Resolver } from "@stoplight/json-ref-resolver";
import * as fs from "fs";
import * as URI from "urijs";
const resolver = new Resolver({
readers: {
file: {
async read(ref: uri.URI) {
return fs.read(String(ref));
}
}
}
});
const sourcePath = "/specs/api.json";
const sourceData = fs.readSync(sourcePath);
// sourceData === {
// user: {
// $ref: "../models/user.json"
// }
// }
const resolved = await resolver.resolve(sourceData, {
// Indicate where the `sourceData` being resolved lives, so that relative remote references can be fetched and resolved.
baseUri: new URI(sourcePath)
});
expect(resolved.result).toEqual({
user: {
// ... the user object defined in `../models/user.json`
}
});
In the above example, the user $ref
will resolve to /models/user.json
, because ../models/user.json
is resolved against the baseUri
of the current document (which was indicated at /specs/api.json
). Relative references will not work if the source document has no baseUri set.
This is a simplistic example of a reader. You can create your own, but we have built some readers which you might find useful.
If you are interested in contributing to Spectral itself, check out our contributing docs to get started.
FAQs
Recursively resolve JSON pointers and remote authorities.
We found that @stoplight/json-ref-resolver demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.