schema-metadata
TypeScript icon, indicating that this package has built-in type declarations

0.0.1 • Public • Published

schema-metadata

schema-metadata is a library that annotates classes with JSON schema. It uses Decorators and Decorator Metadata Stage 3 proposals.

This library contains differences from other libraries that provide more convenient ways to define JSON schema and may not align with your preferences. See Differences from other libraries for more information.

Usage

Install the package:

npm i schema-metadata

Disable the experimentalDecorators and emitDecoratorMetadata in your tsconfig.json:

{
  "compilerOptions": {
    "experimentalDecorators": false,
    "emitDecoratorMetadata": false
  }
}

Import the decorators:

import { json, getJSONSchema } from "schema-metadata";

enum Role {
  Admin = "admin",
  User = "user",
}

@json.schema({ type: "object", $id: "User" })
class User {
  @json.property({ type: "string" })
  name: string;

  @json.property(json.enum(Role))
  role: Role;

  constructor(name: string) {
    this.name = name;
  }
}

@json.schema({ type: "object", $id: "Comment" })
class Comment {
  @json.property({ type: "string" })
  public content: string;

  @json.property(json.ref(User))
  public author: User;

  constructor(content: string, author: User) {
    this.content = content;
    this.author = author;
  }
}

@json.schema({ type: "object", $id: "Post" })
class Post {
  @json.property({ type: "string" })
  title: string;

  @json.property({ type: "string" })
  content: string;

  @json.property(json.ref(User))
  user: User;

  @json.property({ type: "array", items: json.ref(Comment) })
  comments: Comment[] = [];

  constructor(title: string, content: string, user: User) {
    this.title = title;
    this.content = content;
    this.user = user;
  }
}

printSchemas({ User, Comment, Post });

function printSchemas(ctors: any) {
  // console.log(ctor.name, JSON.stringify(getJSONSchema(ctor), null, 2));

  const schemas = Object.entries(ctors).reduce(
    (acc, [key, ctor]) => {
      acc[key] = getJSONSchema(ctor);
      return acc;
    },
    {} as Record<string, any>
  );

  console.log(JSON.stringify(schemas, null, 2));
}

Output:

{
  "User": {
    "type": "object",
    "properties": {
      "name": {
        "type": "string"
      },
      "role": {
        "enum": ["admin", "user"]
      }
    },
    "$id": "User"
  },
  "Comment": {
    "type": "object",
    "properties": {
      "content": {
        "type": "string"
      },
      "author": {
        "$ref": "User"
      }
    },
    "$id": "Comment"
  },
  "Post": {
    "type": "object",
    "properties": {
      "title": {
        "type": "string"
      },
      "content": {
        "type": "string"
      },
      "user": {
        "$ref": "User"
      },
      "comments": {
        "type": "array",
        "items": {
          "$ref": "Comment"
        }
      }
    },
    "$id": "Post"
  }
}

Differences from other libraries

Validation

This library does not provide validation. It only generates JSON schema from the decorated classes. You can use other libraries like ajv to validate the data against the generated schema.

Experimental Decorators

Other libraries use experimentalDecorators and emitDecoratorMetadata to generate metadata. emitDecoratorMetadata is a TypeScript compiler option that provides the decorated field's TypeScript type information, enabling it to work without specifically annotating the type of the field.

class User {
  @Property() // <-- { type: 'string' } is inferred from the TypeScript type
  name: string;
}

schema-metadata requires you to explicitly define the type of the field:

class User {
  @json.property({ type: "string" })
  name: string;
}

While helpful, experimentalDecorators and emitDecoratorMetadata syntax is not part of the TC39 standardization process and is not compatible with the latest specification. Such libraries also only work with TypeScript, and not with JavaScript where there is no type information.

TypeBox

TypeBox is a library that provides a more convenient way to define JSON schema. It uses a fluent API to define the schema.

One inconvenience with this library is that for properties that are $ref to another class, ctrl+clicking the reference will not navigate to the class definition.

Package Sidebar

Install

npm i schema-metadata

Weekly Downloads

7

Version

0.0.1

License

MIT

Unpacked Size

13.9 kB

Total Files

13

Last publish

Collaborators

  • hoangvvo