sinclairzx81 / typebox

Json Schema Type Builder with Static Type Resolution for TypeScript
Other
4.65k stars 150 forks source link

Schema of JSON Schema #832

Closed MatanYadaev closed 3 months ago

MatanYadaev commented 3 months ago

Is there a way to make a schema of JSON schema with TypeBox?

AFAIK, this is a schema of JSON Schema 2019-09: https://json-schema.org/draft/2019-09/schema

Use case: I have an endpoint that clients can pass JSON Schemas, as part of the endpoint, I would like to check that this given schema is a valid JSON Schema.

sinclairzx81 commented 3 months ago

@MatanYadaev Hi,

Is there a way to make a schema of JSON schema with TypeBox?

Yes, partially. However you may run into some challenges adequately expressing both the Json Schema specification while retaining type inference (as schematics can get recursive). This said, The following sets up a few Json Schema types and shows the Recursive / Generic pattern self referential schematics.

import { Type, TSchema, Static } from '@sinclair/typebox'
import { Value } from '@sinclair/typebox/value'

export const AnyOf = <T extends TSchema>(This: T) => Type.Object({
  anyOf: Type.Array(This)
})
export const AllOf = <T extends TSchema>(This: T) => Type.Object({
  allOf: Type.Array(This)
})
export const Object = <T extends TSchema>(This: T) => Type.Object({
  type: Type.Literal('object'),
  properties: Type.Record(Type.String(), This),
  required: Type.Array(Type.String())
})
export const Array = <T extends TSchema>(This: T) => Type.Object({
  type: Type.Literal('array'),
  items: This
})
export const String = Type.Object({ type: Type.Literal('string') })
export const Number = Type.Object({ type: Type.Literal('number') })
export const Boolean = Type.Object({ type: Type.Literal('boolean') })
export const Null = Type.Object({ type: Type.Literal('null') })

export type Schema = Static<typeof Schema>
export const Schema = Type.Recursive(This => Type.Union([
  AllOf(This),
  AnyOf(This),
  Object(This),
  Array(This),
  String,
  Number,
  Boolean,
  Null
]), { $id: 'Schema' })

// some tests
console.log(Schema)
console.log(Value.Check(Schema, { type: 'null' }))
console.log(Value.Check(Schema, { type: 'string' }))
console.log(Value.Check(Schema, { type: 'object', properties: {
  x: { type: 'number' }
}, required: ['x'] }))

Hope this helps S

MatanYadaev commented 3 months ago

Thanks @sinclairzx81 for the quick reply.

nounderline commented 3 months ago

Thank you @sinclairzx81

Creating JSON Schema of JSON Schema in TypeBox feels quite meta and powerful :)