Progressive JSON streaming parser that enables processing data as it arrives over HTTP without waiting for the complete response
94
Oboe.js uses a powerful JSONPath-style pattern matching system for selecting specific nodes and paths in the JSON stream. Patterns allow you to specify exactly which parts of the JSON structure you're interested in, enabling precise control over event triggering.
Match the root JSON object or array.
// Pattern: "!"
// Matches: The root node of the JSON structureUsage Examples:
// Match root object
oboe('https://api.example.com/user.json')
.node('!', function(root) {
console.log('Root object:', root);
// For JSON: {"name": "John", "age": 30}
// Outputs: {name: "John", age: 30}
});
// Root array
oboe('https://api.example.com/users.json')
.node('!', function(root) {
console.log('Root array:', root);
// For JSON: [{"name": "John"}, {"name": "Jane"}]
// Outputs: [{name: "John"}, {name: "Jane"}]
});Match specific properties of objects.
// Pattern: "!.propertyName"
// Matches: Named property of root object
// Pattern: "!.parent.child"
// Matches: Nested property accessUsage Examples:
// Direct property access
oboe('https://api.example.com/user.json')
.node('!.name', function(name) {
console.log('User name:', name);
// For JSON: {"name": "John", "age": 30}
// Outputs: "John"
});
// Nested property access
oboe('https://api.example.com/profile.json')
.node('!.user.profile.email', function(email) {
console.log('Email:', email);
// For JSON: {"user": {"profile": {"email": "john@example.com"}}}
// Outputs: "john@example.com"
});Match any property at a given level using the * wildcard.
// Pattern: "!.*"
// Matches: Any property of the root object
// Pattern: "!.users.*"
// Matches: Any property of the users objectUsage Examples:
// Any root property
oboe('https://api.example.com/data.json')
.node('!.*', function(value, path) {
console.log('Property', path[0], ':', value);
// For JSON: {"users": [...], "posts": [...], "count": 42}
// Outputs multiple times:
// Property users : [...]
// Property posts : [...]
// Property count : 42
});
// Any user object
oboe('https://api.example.com/data.json')
.node('!.users.*', function(user, path) {
console.log('User at index', path[1], ':', user.name);
// For JSON: {"users": [{"name": "John"}, {"name": "Jane"}]}
// Outputs:
// User at index 0 : John
// User at index 1 : Jane
});Access specific array elements or all elements.
// Pattern: "![*]"
// Matches: Any element of root array
// Pattern: "![0]"
// Matches: First element of root array
// Pattern: "!.users[*]"
// Matches: Any element of users array
// Pattern: "!.users[2]"
// Matches: Third element (index 2) of users arrayUsage Examples:
// Any array element
oboe('https://api.example.com/users.json')
.node('![*]', function(user, path) {
console.log('User at index', path[0], ':', user);
// For JSON: [{"name": "John"}, {"name": "Jane"}]
// Outputs:
// User at index 0 : {name: "John"}
// User at index 1 : {name: "Jane"}
});
// Specific array element
oboe('https://api.example.com/users.json')
.node('![0]', function(firstUser) {
console.log('First user:', firstUser);
// Only matches the first element
});
// Nested array access
oboe('https://api.example.com/data.json')
.node('!.departments.*.employees[*]', function(employee, path) {
console.log('Employee in dept', path[1], ':', employee.name);
// Matches employees in any department
});Use bracket notation for property names that contain special characters.
// Pattern: '!["property-name"]'
// Matches: Property with hyphens or special characters
// Pattern: '!.users[*]["full-name"]'
// Matches: Property with special characters in array elementsUsage Examples:
// Special character properties
oboe('https://api.example.com/data.json')
.node('!["content-type"]', function(contentType) {
console.log('Content type:', contentType);
// For JSON: {"content-type": "application/json"}
});
// Mixed notation
oboe('https://api.example.com/users.json')
.node('!.users[*]["first-name"]', function(firstName, path) {
console.log('First name of user', path[1], ':', firstName);
// For JSON: {"users": [{"first-name": "John"}]}
});Select only specific fields from matched objects using field selection syntax.
// Pattern: "!{field1 field2}"
// Matches: Root object with only specified fields
// Pattern: "!.users.*{name email}"
// Matches: User objects with only name and email fieldsUsage Examples:
// Root object field selection
oboe('https://api.example.com/user.json')
.node('!{name email}', function(user) {
console.log('Selected fields:', user);
// For JSON: {"name": "John", "age": 30, "email": "john@example.com"}
// Outputs: {name: "John", email: "john@example.com"}
// (age field excluded)
});
// Array element field selection
oboe('https://api.example.com/users.json')
.node('!.users.*{name}', function(user) {
console.log('User name only:', user);
// For JSON: {"users": [{"name": "John", "age": 30, "city": "NYC"}]}
// Outputs: {name: "John"}
// (age and city fields excluded)
});
// Multiple field selection
oboe('https://api.example.com/products.json')
.node('!.products.*{id title price}', function(product) {
console.log('Product summary:', product);
// Only id, title, and price fields included
});Use the $ prefix to capture matched values for later reference.
// Pattern: "$!.users.*"
// Captures: Each matched user object
// Pattern: "$!.users.*.name"
// Captures: Each matched user nameUsage Examples:
// Capture objects
oboe('https://api.example.com/users.json')
.node('$!.users.*', function(user, path, ancestors) {
console.log('Captured user:', user);
// The user object is captured and can be referenced
});
// Capture specific values
oboe('https://api.example.com/data.json')
.node('$!.config.settings.*', function(setting, path) {
console.log('Captured setting', path[2], ':', setting);
// Each configuration setting value is captured
});Combine various pattern elements for complex matching.
// Pattern: "!.departments.*.teams[*].members.*{name role}"
// Matches: Team member objects with name and role fields,
// from any team in any departmentComplex Usage Examples:
// Deep nested structure matching
oboe('https://api.example.com/organization.json')
.node('!.departments.*.teams[*].members.*', function(member, path) {
const deptName = path[1];
const teamIndex = path[3];
const memberIndex = path[5];
console.log(`Member ${memberIndex} in team ${teamIndex} of ${deptName}:`, member);
});
// Multiple wildcard levels
oboe('https://api.example.com/catalog.json')
.node('!.categories.*.products[*].variants.*', function(variant, path) {
console.log('Product variant:', variant);
console.log('Category:', path[1]);
console.log('Product index:', path[3]);
console.log('Variant index:', path[5]);
});
// Mixed patterns with field selection
oboe('https://api.example.com/social.json')
.node('!.users.*.posts[*].comments.*{author text timestamp}', function(comment) {
console.log('Comment summary:', comment);
// Only author, text, and timestamp fields included
});Use with .path() to match JSON structure paths rather than values.
// Matches when the path structure becomes available,
// not when the value is completePath Pattern Examples:
// Monitor structure discovery
oboe('https://api.example.com/data.json')
.path('!.users', function(path, ancestors) {
console.log('Users array discovered');
// Called when "users" property is found, before its contents
})
.path('!.users.*', function(path, ancestors) {
console.log('User object at path:', path);
// Called for each user path: ['users', '0'], ['users', '1'], etc.
});
// Deep path monitoring
oboe('https://api.example.com/complex.json')
.path('!.data.results[*].metadata', function(path) {
console.log('Metadata path found:', path);
// Called when metadata object structure is discovered
});Patterns are evaluated as the JSON structure is discovered:
Use path information in callbacks to understand matching:
oboe('https://api.example.com/data.json')
.node('!.users.*', function(user, path, ancestors) {
console.log('Pattern matched:');
console.log(' Value:', user);
console.log(' Path:', path); // ['users', '0']
console.log(' Ancestors:', ancestors); // [rootObject, usersArray]
});Install with Tessl CLI
npx tessl i tessl/npm-oboeevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10