json-schema-faker including extra url in results - javascript

I'm setting up json-schema-faker to create some mock data for a project.
When I generate the data it includes an extra bit with the following as the last item in the generated data.
"id": "http://json-schema.org/schema#"
Here is my schema (from a file named 'mockDataSchema.js'):
exports.schema = {
"type": "object",
"properties": {
"users": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"items": {
"type": "object",
"properties": {
"id": {
"type": "number",
"unique": true,
"minimum": 1
},
"firstName": {
"type": "string",
"faker": "name.firstName"
},
"lastName": {
"type": "string",
"faker": "name.lastName"
},
"email": {
"type": "string",
"faker": "internet.email"
}
},
"required": ["id", "firstName", "lastName", "email"]
}
}
},
"required": ["users"]
}
The code to generate the data ('generate-mock-data.js'):
var jsf = require('json-schema-faker')
var schema = require('./mockDataSchema')
var fs = require('fs')
var chalk = require('chalk')
const json = JSON.stringify(jsf(schema))
console.log(json)
fs.writeFile('./src/api/db.json', json, function(err) {
if (err) {
return console.log(chalk.red(err))
} else {
console.log(chalk.green('Mock data generated.'))
}
})
Add the data that is returned:
{
"schema": {
"users": [
{ "id": 25582343, "firstName": "Brycen", "lastName": "Dickens", "email": "Angelica_Jakubowski#hotmail.com" },
{ "id": 39817508, "firstName": "Marisa", "lastName": "Terry", "email": "Arlo.Hermann0#yahoo.com" }
]
},
"id": "http://json-schema.org/schema#"
}
I've been unable to determine why it includes the "id": "http://json-schema.org/schema#"
I would like to get rid of that line. I'll be using this with 'json-server' to provide a mock api and it chokes on that line.

Figured this out.
exports.schema = {
was causing jscon-schema-faker to interpret '.schema' as part of the schema.
Changed to
module.exports = {
and the trailing schema link wnet away.

Related

How to print huge number of items from the json array

This is my json format with that im displaying my array items like this.
If i have more items in my array mean how can i print that all using for loop or is there any method available to print all that items in an array?
{
"workers": [
{ "id": "5001", "type": "Basic" },
{ "id": "5002", "type": "Admin" },
{ "id": "5003", "type": "Basic" }
],
"clients": [
{ "id": "5004", "type": "Pro" },
{ "id": "5005", "type": "Basic" },
{ "id": "5006", "type": "Basic" },
{ "id": "5007", "type": "Pro" }
]
}
<script>
const api_url = "API URL";
async function get_data_from_api() {
const response = await fetch(api_url);
var data = await response.json();
var track = data["workers"][2]["id"];
document.getElementById('demo2').innerHTML = track ;
}
</script>
Reference:
JSON.stringify()
const o = {
"workers": [
{ "id": "5001", "type": "Basic" },
{ "id": "5002", "type": "Admin" },
{ "id": "5003", "type": "Basic" }
],
"clients": [
{ "id": "5004", "type": "Pro" },
{ "id": "5005", "type": "Basic" },
{ "id": "5006", "type": "Basic" },
{ "id": "5007", "type": "Pro" }
]
};
output.innerHTML = JSON.stringify(o, undefined, 2);
<pre id="output"></pre>

Deriving the list of JSON Paths from a JSON Schema model

I am looking for a Javascript library to list the possible Json Paths based on a Json Schema.
For a json schema like below, I want to list the possible json paths.
{
"$id": "https://example.com/person.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Customer",
"type": "object",
"properties": {
"firstName": {
"type": "string",
"description": "The person's first name."
},
"lastName": {
"type": "string",
"description": "The person's last name."
},
"age": {
"description": "Age in years which must be equal to or greater than zero.",
"type": "integer",
"minimum": 0
},
"address": {
"type": "object",
"city": {
"type": "string",
},
"country": {
"type": "string",
}
}
}
}
Possible Json Paths: firstName, lastName, age, address.city, and address.country
Based on #customcommander's answer
Add support for $ref (prevent recursion)
Add hierarchy parents paths too (i.e. a.b.c -> a + a.b + a.b.c)
Add support for array items (using [] as a generic indexer)
const _derivePathsFromSchema = (schema, properties, defined) => {
let paths = [];
if (!properties) return paths;
return Object.keys(properties).reduce((paths, childKey) => {
let child = properties[childKey];
const { $ref, ...childProperties } = child;
if ($ref?.startsWith('#/definitions/')) {
const definition = $ref.substr($ref.lastIndexOf('/') + 1);
if (!defined.includes(definition)) // prevent recursion of definitions
{
defined.push(definition);
child = {
...schema.definitions[definition], // load $ref properties
...childProperties, // child properties override those of the $ref
};
}
}
if (child.type === 'object') {
return paths.concat(childKey, _derivePathsFromSchema(schema, child.properties, defined.slice()).map(p => `${childKey}.${p}`));
}
if (child.type === 'array' && child.items?.properties) {
return paths.concat(childKey, `${childKey}[]`, _derivePathsFromSchema(schema, child.items.properties, defined.slice()).map(p => `${childKey}[].${p}`));
}
return paths.concat(childKey);
}, paths);
};
const derivePathsFromSchema = schema => _derivePathsFromSchema(schema, schema.properties, []);
console.log(derivePathsFromSchema({
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"BType": {
"type": "object",
"properties": {
"a": {
"$ref": "#/definitions/AType"
}
}
},
"AType": {
"type": "object",
"properties": {
"b": {
"$ref": "#/definitions/BType"
}
}
}
},
"type": "object",
"properties": {
"a": {
"$ref": "#/definitions/AType"
},
"b": {
"$ref": "#/definitions/BType"
},
"id": {
"type": "string"
},
"array": {
"type": "array",
"items": {
"type": "object",
"properties": {
"item": { "type": "string" }
}
}
},
"obj": {
"type": "object",
"properties": {
"nested": { "type": "string" }
}
}
}
}));
You don't necessarily need a library for that. You can use a simple recursive function:
var schema = {
"$id": "https://example.com/person.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Customer",
"type": "object",
"properties": {
"firstName": {
"type": "string",
"description": "The person's first name."
},
"lastName": {
"type": "string",
"description": "The person's last name."
},
"age": {
"description": "Age in years which must be equal to or greater than zero.",
"type": "integer",
"minimum": 0
},
"address": {
"type": "object",
"properties": {
"city": {
"type": "string",
},
"country": {
"type": "string",
}
}
}
}
};
var path = ({properties}) =>
Object.keys(properties).reduce((acc, key) =>
acc.concat(properties[key].type !== 'object' ? key :
path(properties[key]).map(p => `${key}.${p}`)), []);
console.log(
path(schema)
);

How filter search in elasticlunr.js

i am trying to search an index generated by #gatsby-contrib/elasticlunr the generated index looks like this:
{
"version": "0.9.5",
"fields": ["title", "path", "section"],
"ref": "id",
"documentStore": {
"docs": {
"fe565569-77a5-566d-bb47-96a6094c22c5": {
"id": "fe565569-77a5-566d-bb47-96a6094c22c5",
"title": "schema",
"path": "/graphql/schema",
"section": "graphql"
},
"cd1cdd40-4bb7-5ff6-9908-6c9ad692e75c": {
"id": "cd1cdd40-4bb7-5ff6-9908-6c9ad692e75c",
"title": "Component",
"path": "/react/component",
"section": "react"
},
"c1aecadb-3d1e-5d49-87f3-2b6f2c73433c": {
"id": "c1aecadb-3d1e-5d49-87f3-2b6f2c73433c",
"title": "Component",
"path": "/react/component2",
"section": "react"
},
"07159f12-dafb-53f6-b1ad-5032d56d25bb": {
"id": "07159f12-dafb-53f6-b1ad-5032d56d25bb",
"title": "Lazy",
"path": "/react/suspense",
"section": "react"
},
"380309db-ffa1-5f24-a192-36ac36b90a06": {
"id": "380309db-ffa1-5f24-a192-36ac36b90a06",
"title": "suspense",
"path": "/react/lazy",
"section": "react"
},
"380309db-ffa1-5f24-a192-36ac36b90uuuu": {
"id": "380309db-ffa1-5f24-a192-36ac36b9uuuu",
"title": "super",
"path": "/graphql/super",
"section": "graphql"
}
}
}
.....
}
is there a way i can get only get results whose section == react alone, and not all docs that match a search query in terms of a field.
e.g
when i search with a term su with expand: true in the config and set a filter section = 'graphql' it should return :
"380309db-ffa1-5f24-a192-36ac36b90uuuu": {
"id": "380309db-ffa1-5f24-a192-36ac36b9uuuu",
"title": "super",
"path": "/graphql/super",
"section": "graphql"
}
but what i am currently getting is :
{
"380309db-ffa1-5f24-a192-36ac36b90a06": {
"id": "380309db-ffa1-5f24-a192-36ac36b90a06",
"title": "suspense",
"path": "/react/lazy",
"section": "react"
},
"380309db-ffa1-5f24-a192-36ac36b90uuuu": {
"id": "380309db-ffa1-5f24-a192-36ac36b9uuuu",
"title": "super",
"path": "/graphql/super",
"section": "graphql"
}
}
Thanks!
You can't filter like this with elasticlunr.js. It's a Lightweight full-text search engine.
Also elasticlunr does not support regex
Alternatively you can filter result by using loop again.
var finalResult ={};
for (var key in label) {
var result = label[key];
// graphql
if (result.doc.section === 'graphql' && !!result.doc.title.match(/su/g)) {
finalResult[key] = result;
}
console.log(finalResult);
}
// output
console.log(finalResult);
Thank you

Validate an API response against JSON schema using AJV

I have many days reading a lot and doing several tests with this, without the expected results.
I need validate an API response with its JSON schema (Swagger 2.0). The JSON is longer but I've reduced it to simply. I need to know if "code" and "message" keywords in the response have the type and values defined. Here the code I'm using:
var Ajv = require('ajv');
var ajv = new Ajv();
var schema = {
"host": "cert",
"paths": {
"products": {
"get": {
"responses": {
"401": {
"description": "Problem with the client request",
"headers": {
"x-correlator": {
"type": "string",
"format": "uuid",
"description": "Correlation id"
}
},
"schema": {
"$ref": "file:///../errors.json#/definitions/Unauthenticated"
}
}
}
}
},
"products": {
"get": {
"responses": {
"401": {
"description": "Problem with the client request",
"headers": {
"x-correlator": {
"type": "string",
"format": "uuid",
"description": "Correlation id"
}
},
"schema": {
"$ref": "file:///../errors.json#/definitions/Unauthenticated"
},
"examples": {
"application/json": {
"code": "UNAUTHENTICATED",
"message": "Authentication error"
}
}
}
}
}
}
}
}
var errors_schema = {
"info": {
"description": "Common errors",
"version": "3.0.1",
"title": "Common errors",
"contact": {
"name": "Team"
}
},
"definitions": {
"ModelError": {
"type": "object",
"required": [
"message"
],
"properties": {
"message": {
"type": "string",
"description": "A human readable description"
}
}
},
"Unauthenticated": {
"allOf": [
{
"type": "object",
"required": [
"code"
],
"properties": {
"code": {
"type": "string",
"enum": [
"UNAUTHENTICATED"
],
"default": "UNAUTHENTICATED",
"description": "Request not authenticated due to missing, invalid, or expired credentials."
}
}
},
{
"$ref": "#/definitions/ModelError"
}
]
}
}
}
ajv.addSchema(errors_schema, 'file:///../errors.json');
var testajv = ajv.compile(schema);
var response = {"code": 123, "message":"token expired"}
var valid = testajv(response);
console.log(valid);
if(!valid) {
console.log(testajv.errors);
}
As you see the keyword "code" in the response is '123' integer but in the schema it is defined as string. Independently of the value the validation always gets 'true'. What should I do to get my needs? Thanks in advance.
Swagger schema contains multiple JSON schemas organized in API structure, you need to address a correct part of Swagger schema to employ JSON schema for validation.
Please check example code (https://runkit.com/embed/bwj42juwyjo4):
var Ajv = require('ajv');
var ajv = new Ajv();
var schema = {
"host": "cert",
"paths": {
"products": {
"get": {
"responses": {
"401": {
"description": "Problem with the client request",
"headers": {
"x-correlator": {
"type": "string",
"format": "uuid",
"description": "Correlation id"
}
},
"schema": {
"$ref": "errors.json#/definitions/Unauthenticated"
}
}
}
}
},
"products": {
"get": {
"responses": {
"401": {
"description": "Problem with the client request",
"headers": {
"x-correlator": {
"type": "string",
"format": "uuid",
"description": "Correlation id"
}
},
"schema": {
"$ref": "errors.json#/definitions/Unauthenticated"
},
"examples": {
"application/json": {
"code": "UNAUTHENTICATED",
"message": "Authentication error"
}
}
}
}
}
}
}
}
var errors_schema = {
"info": {
"description": "Common errors",
"version": "3.0.1",
"title": "Common errors",
"contact": {
"name": "Team"
}
},
"definitions": {
"ModelError": {
"type": "object",
"required": [
"message"
],
"properties": {
"message": {
"type": "string",
"description": "A human readable description"
}
}
},
"Unauthenticated": {
"allOf": [
{
"type": "object",
"required": [
"code"
],
"properties": {
"code": {
"type": "string",
"enum": [
"UNAUTHENTICATED"
],
"default": "UNAUTHENTICATED",
"description": "Request not authenticated due to missing, invalid, or expired credentials."
}
}
},
{
"$ref": "#/definitions/ModelError"
}
]
}
}
}
ajv.addSchema(errors_schema, 'errors.json');
ajv.addSchema(schema, 'swagger.json')
var testajv = ajv.compile({ $ref: 'errors.json#/definitions/Unauthenticated' });
console.log(testajv({"code": 123, "message":"token expired"}), testajv.errors); // Fails
console.log(testajv({"code": "AAA", "message":"token expired"}), testajv.errors); // Fails
console.log(testajv({"code": "UNAUTHENTICATED", "message":"token expired"}), testajv.errors); // Passes
var testajv2 = ajv.compile({ $ref: 'swagger.json#/paths/products/get/responses/401/schema' });
console.log(testajv2({"code": 123, "message":"token expired"}), testajv2.errors); // Fails
console.log(testajv2({"code": "AAA", "message":"token expired"}), testajv2.errors); // Fails
console.log(testajv2({"code": "UNAUTHENTICATED", "message":"token expired"}), testajv2.errors); // Passes
Some more information in relevant ajv issue: https://github.com/epoberezkin/ajv/issues/195
Use type as number instead of string in code property.
"properties": {
"code": {
"type": "number",
"enum": [
"UNAUTHENTICATED"
],
"default": "UNAUTHENTICATED",
"description": "Request not authenticated due to missing, invalid, or expired credentials."
}
}

Using negative lookbehind with jsonschema

I'm using Node 9.2.0 and ajv 6.0.0.
I have a schema that I wish to use negative lookbehind on, it's defined like:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "release format",
"description": "A Release Format",
"type": "object",
"properties": {
"id": {"type": "integer"},
"title": {
"anyOf": [
{
"type": "string",
"pattern": "^((?!itunes).)*$"
},
{
"type": "string",
"pattern": "^((?!exclusive).)*$"
},
{
"type": "string",
"pattern": "^((?!ringtone).)*$"
}
]
}
}
}
However, it appears that when I try and validate this with AJV using the following data: {"id": 123, "title": "world exclusive"} I don't get a validation error.
The code:
const Ajv = require('ajv');
class Validator {
constructor() {
this.releaseFormatSchema = JSON.parse(fs.readFileSync('./schemas/release-format.json'));
this.schemaValidator = new Ajv({allErrors: true});
}
validate(data) {
let validate = this.schemaValidator.compile(this.releaseFormatSchema);
let valid = validate(data);
console.log(valid);
console.log(validate);
}
}
where data would be: {"id": 123, "title": "world exclusive"}. I would expect this to error, however it's currently telling me that the data is valid.
The answer was also found by #sln and #ClasG, anyOf does a union between titles patterns can match : "all except strings which contains itunes" union "all except strings which contains exclusive" union "...", which means all which not contains all the forbidden keywords. It can be fixed either
using allOf instead of anyOF
"title": {
"allOf": [
{
"type": "string",
"pattern": "^((?!itunes).)*$"
},
{
"type": "string",
"pattern": "^((?!exclusive).)*$"
},
{
"type": "string",
"pattern": "^((?!ringtone).)*$"
}
]
}
using single type/pattern :
"title": {
"type": "string",
"pattern": "^((?!itunes|exclusive|ringtone).)*$"
}

Categories

Resources