@valbo/reusable-json-schemas

Reusable JSON schemas with types and random data generators.

Usage no npm install needed!

<script type="module">
  import valboReusableJsonSchemas from 'https://cdn.skypack.dev/@valbo/reusable-json-schemas';
</script>

README

@valbo/reusable-json-schemas

Reusable JSON schemas with types and random data generators.

npm (scoped) semantic-release Build Status Coverage Status Known Vulnerabilities

Contents

Install

npm install @valbo/reusable-json-schemas

Usage

This package exports some JSON schemas that can be used as a base to create more complex schemas.

For each exported schema there is also a corresponding Typescript type (created using json-schema-to-ts) and a random data generation function.

The available schemas are:

String schemas

$schema

A constant string with the JSON Schema draft 7 URI.

"http://json-schema.org/draft-07/schema#"

dateString, DateString, randomDateString()

A string schema with the date format.

"2021-02-13"

timeString, TimeString, randomTimeString()

A string with the time format. The random function does not produce milliseconds or timezone.

"06:05:00"

datetimeString, DatetimeString, randomDatetimeString()

A string with the date-time format.

"2021-01-13T06:05:00.000Z"

uuidString, UuidString, randomUuidString()

A string with the uuid format.

"74141a5c-0213-4360-8051-2f6c9e29049e"

objectIdString, ObjectIdString, randomObjectIdString()

A MongoDB ObjectId as a hexadecimal string.

"507f1f77bcf86cd799439011"

countryCodeString, CountryCodeString, randomCountryCodeString()

An enumeration of ISO-3166-1 alpha-2 country codes.

"US"

timezoneString, TimezoneString, randomTimezoneString()

An enumeration of the tz database time zones.

"Europe/Madrid"

usernameString, UsernameString, randomUsernameString()

A string with a ^[a-zA-Z][a-zA-Z0-9\._\-]*$ regex pattern and minimum length 3.

"axel23"

passwordString, PasswordString, randomPasswordString()

A string with a ^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])[0-9A-Za-z]*$ regex pattern and minimum length 8.

"weyJRW84"

String tuple schemas

dateStringRange, DateStringRange, randomDateStringRange()

A 2-tuple of strings with the date format.

["2021-01-15", "2021-02-13"]

timeStringRange, TimeStringRange, randomTimeStringRange()

A 2-tuple of strings with the time format.

["06:05:00", "06:21:00"]

datetimeStringRange, DatetimeStringRange, randomDatetimeStringRange()

A 2-tuple of strings with the date-time format.

["2021-01-15T06:05:00.000Z", "2021-02-13T06:21:00.000Z"]

GeoJSON schemas

position, Position, randomPosition()

A 2-tuple with a longitude and latitude to build coordinates members of GeoJSON objects.

[2.175917, 41.410954]

linearRing, LinearRing, randomLinearRing()

A closed tuple of positions with at least 4 of them.

[
  [2.175917, 41.410954],
  [2.122324, 41.384716],
  [2.177483, 41.377022],
  [2.175917, 41.410954]
]

geoJSONPoint, GeoJSONPoint, randomGeoJSONPoint()

A GeoJSON Point geometry object.

{
  "type": "Point",
  "coordinates": [2.175917, 41.410954]
}

geoJSONMultiPoint, GeoJSONMultiPoint, randomGeoJSONMultiPoint()

A GeoJSON MultiPoint geometry object.

{
  "type": "MultiPoint",
  "coordinates": [
    [2.175917, 41.410954],
    [2.122324, 41.384716]
  ]
}

geoJSONLineString, GeoJSONLineString, randomGeoJSONLineString()

A GeoJSON LineString geometry object.

{
  "type": "LineString",
  "coordinates": [
    [2.175917, 41.410954],
    [2.122324, 41.384716]
  ]
}

geoJSONMultiLineString, GeoJSONMultiLineString, randomGeoJSONMultiLineString()

A GeoJSON MultiLineString geometry object.

{
  "type": "MultiLineString",
  "coordinates": [
    [
      [2.175917, 41.410954],
      [2.122324, 41.384716]
    ],
    [
      [2.177483, 41.377022],
      [2.175917, 41.410954]
    ]
  ]
}

geoJSONPolygon, GeoJSONPolygon, randomGeoJSONPolygon()

A GeoJSON Polygon geometry object.

{
  "type": "Polygon",
  "coordinates": [
    [
      [2.175917, 41.410954],
      [2.122324, 41.384716],
      [2.177483, 41.377022],
      [2.175917, 41.410954]
    ]
  ]
}

geoJSONMultiPolygon, GeoJSONMultiPolygon, randomGeoJSONMultiPolygon()

A GeoJSON MultiPolygon geometry object.

{
  "type": "MultiPolygon",
  "coordinates": [
    [
      [
        [2.175917, 41.410954],
        [2.122324, 41.384716],
        [2.177483, 41.377022],
        [2.175917, 41.410954]
      ]
    ],
    [
      [
        
        [-3.692731, 40.416569],
        [-3.688316, 40.454784],
        [-3.714438, 40.420152],
        [-3.692731, 40.416569]
      ]
    ]
  ]
}

Object schemas

email, Email, randomEmail()

An object with a label and an email address.

{
  "label": "work",
  "address": "example@example.com"
}

phone, Phone, randomPhone()

An object with a label and a phone number.

{
  "label": "work",
  "number": "(555) 927-2152"
}

money, Money, randomMoney()

An object with a currency (ISO 4217 alpha code) and an amount in the currency minor unit (e.g. cents) to avoid rounding errors.

{
  "currency": "EUR",
  "amount": 1650
}

geolocation, Geolocation, randomGeolocation()

An object with a GeoJSONPoint and a geocoding precision.

{
  "geometry": {
    "type": "Point",
    "coordinates": [2.175917, 41.410954]
  },
  "precision": "rooftop"
}

timedGeolocation, TimedGeolocation, randomTimedGeolocation()

Same as above with an additional timestamp.

{
  "geometry": {
    "type": "Point",
    "coordinates": [2.175917, 41.410954]
  },
  "precision": "rooftop",
  "at": "2021-02-13T06:48:00.000Z"
}

address, Address, randomAddress()

An object with a street, postal code, locality, country, etc.

{
  "street": "536 Zokpu Court",
  "door": "K",
  "postalCode": "09515",
  "locality": "Teudore",
  "administrativeArea": "AL",
  "country": "US",
  "geolocation": {
    "geometry": {
      "type": "Point", 
      "coordinates": [-177.8456, -13.77895]
    },
    "precision": "unknown"
  },
  "notes": "Bic etu sucfo taunavoj zoslurci tazdonej efuispup efej saj pol tavakado de urapusuk emaoni hu afidajsi to busdowif.",
  "placeId": "APA91fto-QJ3CqCcPVzspY8xVcDFb6rSQf1IqZln__EOCmpukH7UczZMWtFRq1lGklEf_i_z7zMNG6ny3MbnBSk2poTkVnDNVCU4Drm0NmNS9OgChZARboFmJDT2v5jc2fIw5xK12AasOwyv5uUafLIlBjw5VsJ3pCAL68CAwjiwLDGi6NPIbVU"
}

errorResponse, ErrorResponse, randomErrorResponse()

An object to return HTTP errors from an API.

{
  "error": {
    "status": "400",
    "name": "BadRequest",
    "message": "The request could not be fulfilled due to the incorrect syntax of the request."
  }
}

document, Document, randomDocument()

An object to use as base for MongoDB documents.

{
  "_id": "3bc50ffb-0e79-4d36-af6d-7d9db3afe253",
  "createdAt": "2021-02-13T07:02:30.000Z",
  "updatedAt": "2021-02-13T07:02:30.000Z",
  "deletable": true
}

Helpers for CRUD operations

skip, Skip, randomSkip()

A non-negative number which defaults to 0. Used to paginate results.

limit, Limit, randomLimit()

A number between 1 and 100 which defaults to 100. Used to paginate results.

findAll, FindAll, randomFindAll()

A filter to find all results.

{
  "all": true
}

findById, FindById, randomFindById()

A filter to find an exact result by _id.

{
  "_id": "7104984d-6330-4083-a9eb-1e8dc524cbc5"
}

Full example

The following example shows how to create a User schema and API requests and responses for CRUD operations.

import type { FromSchema } from 'json-schema-to-ts';
import Chance from 'chance';
import {
  $schema,
  uuidString,
  email,
  phone,
  document,
  skip,
  limit,
  findAll,
  findById,
  randomEmail,
  randomPhone,
  randomDocument,
} from '@valbo/reusable-json-schemas';

export const user = {
  $schema,
  $id: 'user',
  title: 'user',
  type: 'object',
  properties: {
    ...document.properties,
    name: { type: 'string' },
    email,
    phone,
    notes: { type: 'string' },
  },
  required: [...document.required, 'name'],
  additionalProperties: false,
} as const;

const { _id, name, notes } = user.properties;

export const createUserRequest = {
  $schema,
  $id: 'createUserRequest',
  type: 'object',
  properties: {
    create: {
      type: 'object',
      properties: { _id, name, email, phone, notes },
      required: ['name'],
      additionalProperties: false,
    },
  },
  required: ['create'],
  additionalProperties: false,
} as const;

export const createUserResponse = {
  $schema,
  $id: 'createUserResponse',
  type: 'object',
  properties: { created: user },
  required: ['created'],
  additionalProperties: false,
} as const;

export const findUsersRequest = {
  $schema,
  $id: 'findUsersRequest',
  type: 'object',
  properties: {
    find: { oneOf: [findAll, findById] },
    skip,
    limit,
  },
  required: ['find'],
  additionalProperties: false,
} as const;

export const findUsersResponse = {
  $schema,
  type: 'object',
  $id: 'findUsersRequest',
  properties: { found: { type: 'array', items: user } },
  required: ['found'],
  additionalProperties: false,
} as const;

export const unset = { type: 'boolean', enum: [true] } as const;

export const updateUserRequest = {
  $schema,
  $id: 'updateUserRequest',
  type: 'object',
  properties: {
    find: findById,
    set: {
      type: 'object',
      properties: { name, email, phone, notes },
      additionalProperties: false,
    },
    unset: {
      type: 'object',
      properties: { email: unset, phone: unset, notes: unset },
      additionalProperties: false,
    },
  },
  required: ['find'],
  additionalProperties: false,
} as const;

export const updateUserResponse = {
  $schema,
  $id: 'updateUserResponse',
  type: 'object',
  properties: { updated: user },
  required: ['updated'],
  additionalProperties: false,
} as const;

export const deleteUserRequest = {
  $schema,
  $id: 'deleteUserRequest',
  type: 'object',
  properties: { delete: findById },
  required: ['delete'],
  additionalProperties: false,
} as const;

export const deleteUserResponse = {
  $schema,
  $id: 'deleteUserResponse',
  type: 'object',
  properties: { deleted: user },
  required: ['deleted'],
  additionalProperties: false,
} as const;

export type User = FromSchema<typeof user>;
export type CreateUserRequest = FromSchema<typeof createUserRequest>;
export type CreateUserResponse = FromSchema<typeof createUserResponse>;
export type FindUsersRequest = FromSchema<typeof findUsersRequest>;
export type FindUsersResponse = FromSchema<typeof findUsersResponse>;
export type Unset = FromSchema<typeof unset>;
export type UpdateUserRequest = FromSchema<typeof updateUserRequest>;
export type UpdateUserResponse = FromSchema<typeof updateUserResponse>;
export type DeleteUserRequest = FromSchema<typeof deleteUserRequest>;
export type DeleteUserResponse = FromSchema<typeof deleteUserResponse>;

const chance = new Chance();

export function randomUser(partial?: Partial<User>): User {
  return {
    ...randomDocument(partial),
    name: partial?.name ?? chance.name(),
    email: partial?.email ?? randomEmail(),
    phone: partial?.phone ?? randomPhone(),
    notes: partial?.notes ?? chance.sentence(),
  }
}