A powerful JavaScript library implementing the JSON Reference and JSON Pointer specifications. Resolve $ref
references in JSON documents, handle external references, and manipulate JSON data using JSON Pointer syntax.
- âś… JSON Reference Resolution: Resolve
$ref
references in JSON documents - âś… External References: Fetch and resolve external URI references
- âś… JSON Pointer: Navigate and manipulate JSON data using JSON Pointer syntax
- âś… Caching: Built-in store mechanism for efficient reference caching
- âś… TypeScript Support: Full TypeScript definitions included
- âś… Modern ES Modules: Supports both ESM and CommonJS
- âś… Browser & Node.js: Works in both environments
- âś… Zero Dependencies: Lightweight with no external dependencies
# npm
npm install jsonref
# pnpm
pnpm add jsonref
# yarn
yarn add jsonref
import { parse } from 'jsonref';
const schema = {
"definitions": {
"person": {
"type": "object",
"properties": {
"name": { "type": "string" }
}
}
},
"type": "object",
"properties": {
"user": { "$ref": "#/definitions/person" }
}
};
const resolved = await parse(schema);
console.log(resolved.properties.user); // { type: "object", properties: { name: { type: "string" } } }
import { parse } from 'jsonref';
const schema = {
"allOf": [
{ "$ref": "https://json-schema.org/draft/2019-09/schema" },
{ "type": "object" }
]
};
// Define a retriever function to fetch external references
function retriever(url) {
return fetch(url).then(response => response.json());
}
const resolved = await parse(schema, { retriever });
Resolves all $ref
references in a JSON document.
Parameters:
dataOrUri
(object | string): The JSON data to parse or a URI to fetchoptions
(object, optional): Configuration optionsscope
(string): Base URI for resolving relative referencesstore
(object): Cache object to store resolved references for reuseretriever
(function): Function to fetch external references(url: string) => Promise<object>
Returns: Promise<object>
- The resolved JSON data
Example:
import { parse } from 'jsonref';
const schema = {
"definitions": {
"user": { "type": "object", "properties": { "id": { "type": "string" } } }
},
"properties": {
"currentUser": { "$ref": "#/definitions/user" }
}
};
const resolved = await parse(schema);
Navigate or modify JSON data using JSON Pointer syntax.
Parameters:
data
(object): The object to traversepath
(string | string[]): JSON Pointer path (e.g.,"/users/0/name"
or["users", "0", "name"]
)value
(any, optional): Value to set at the specified path
Returns: The value at the path, or the modified object if setting a value
Examples:
import { pointer } from 'jsonref';
const data = {
users: [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 }
]
};
// Get a value
const name = pointer(data, "/users/0/name"); // "Alice"
// Set a value
pointer(data, "/users/0/age", 31);
console.log(data.users[0].age); // 31
// Create nested paths
pointer(data, "/users/0/address/city", "New York");
The library also exports several utility functions for advanced use cases:
isRef(obj)
- Check if an object is a JSON ReferenceisAnnotated(obj)
- Check if an object has been processed by jsonrefgetMeta(obj)
- Get metadata from a processed objectnormalize(obj)
- Normalize$id
and$ref
values in an objectscope(obj)
- Get the resolution scope of an object
import { parse } from 'jsonref';
const schema = {
"$id": "https://example.com/person.schema.json",
"type": "object",
"properties": {
"firstName": { "type": "string" },
"lastName": { "type": "string" },
"age": { "$ref": "#/definitions/positiveInteger" }
},
"definitions": {
"positiveInteger": {
"type": "integer",
"minimum": 0
}
}
};
const resolved = await parse(schema);
console.log(resolved.properties.age); // { type: "integer", minimum: 0 }
import { parse } from 'jsonref';
const store = {}; // Reuse this store across multiple parse operations
const schema1 = {
"allOf": [{ "$ref": "https://json-schema.org/draft-07/schema" }]
};
const schema2 = {
"allOf": [{ "$ref": "https://json-schema.org/draft-07/schema" }]
};
// First parse will fetch the external reference
const resolved1 = await parse(schema1, { store, retriever });
// Second parse will use cached reference (faster)
const resolved2 = await parse(schema2, { store, retriever });
import { pointer } from 'jsonref';
const config = {
database: {
host: "localhost",
port: 5432,
credentials: {
username: "admin",
password: "secret"
}
},
features: ["auth", "logging"]
};
// Navigate nested objects
const host = pointer(config, "/database/host"); // "localhost"
// Work with arrays
const firstFeature = pointer(config, "/features/0"); // "auth"
// Modify existing values
pointer(config, "/database/port", 3306);
// Create new nested structures
pointer(config, "/cache/redis/host", "redis.example.com");
console.log(config.cache); // { redis: { host: "redis.example.com" } }
function retriever(url) {
return fetch(url, {
method: 'GET',
headers: { 'Accept': 'application/json' }
}).then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response.json();
});
}
import { fetch } from 'undici'; // or use built-in fetch in Node 18+
function retriever(url) {
return fetch(url).then(response => response.json());
}
import fs from 'fs/promises';
import path from 'path';
function retriever(url) {
if (url.startsWith('file://')) {
const filePath = url.replace('file://', '');
return fs.readFile(filePath, 'utf8').then(JSON.parse);
}
// Handle HTTP URLs
return fetch(url).then(response => response.json());
}
The library provides comprehensive error handling for various scenarios:
import { parse } from 'jsonref';
try {
// This will throw an error because no retriever is provided for external reference
const schema = { "$ref": "https://example.com/schema.json" };
await parse(schema); // Throws: no_retriever
} catch (error) {
console.error('Error:', error.message);
}
// Proper error handling with retriever
async function safeRetriever(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch ${url}: ${response.status}`);
}
return await response.json();
} catch (error) {
throw new Error(`Network error: ${error.message}`);
}
}
Full TypeScript definitions are included:
import { parse, pointer, isRef, ParseOptions } from 'jsonref';
interface Schema {
type: string;
properties?: Record<string, any>;
}
const options: ParseOptions = {
retriever: async (url: string) => {
const response = await fetch(url);
return response.json();
}
};
const schema: Schema = {
type: "object",
properties: {
user: { "$ref": "#/definitions/user" }
}
};
const resolved = await parse(schema, options);
- Reuse stores for better performance when parsing multiple documents with shared references
- Cache external references by implementing a smart retriever function
- Use scopes when working with relative references to avoid unnecessary network requests
// Efficient caching retriever
const cache = new Map();
function cachingRetriever(url) {
if (cache.has(url)) {
return Promise.resolve(cache.get(url));
}
return fetch(url)
.then(response => response.json())
.then(data => {
cache.set(url, data);
return data;
});
}
jsonref works in all modern browsers that support:
- Promises (or use a polyfill)
- Object.keys, Object.defineProperty
- JSON.parse/JSON.stringify
For older browsers, consider using polyfills for missing features.
MIT License - see the LICENSE file for details.
Contributions are welcome! Please read our contributing guidelines and ensure all tests pass:
pnpm install
pnpm test
pnpm run coverage