JsonSchema
Helpers for normalizing and converting JSON Schema and OpenAPI schema
documents. Supported inputs include JSON Schema Draft-07, Draft 2020-12,
OpenAPI 3.0, and OpenAPI 3.1; conversions normalize through
Document<"draft-2020-12"> before emitting another dialect, including
JSON Schema Draft-04. The module also defines document types, meta-schema
constants, and OpenAPI component-key helpers.
Constants
META_SCHEMA_URI_DRAFT_04
Represents the $schema meta-schema URI for JSON Schema Draft-04.
When to use
Use when constructing a Draft-04 JSON Schema document and you need a stable
value for the root $schema field.
See
- META_SCHEMA_URI_DRAFT_07 for the Draft-07
$schemaURI
Signature
declare const META_SCHEMA_URI_DRAFT_04: "http://json-schema.org/draft-04/schema#"META_SCHEMA_URI_DRAFT_07
Represents the $schema meta-schema URI for JSON Schema Draft-07.
When to use
Use when constructing a Draft-07 JSON Schema document and you need a stable
value for the root $schema field.
Details
The exported value is the literal string
http://json-schema.org/draft-07/schema#.
See
- META_SCHEMA_URI_DRAFT_04 for the Draft-04
$schemaURI - META_SCHEMA_URI_DRAFT_2020_12 for the Draft 2020-12
$schemaURI
Signature
declare const META_SCHEMA_URI_DRAFT_07: "http://json-schema.org/draft-07/schema#"META_SCHEMA_URI_DRAFT_2020_12
Represents the $schema meta-schema URI for JSON Schema Draft 2020-12.
When to use
Use when you need to populate the $schema field while emitting a JSON
Schema document that should declare JSON Schema Draft 2020-12.
Details
The exported value is the literal string
https://json-schema.org/draft/2020-12/schema.
See
- META_SCHEMA_URI_DRAFT_07 for the Draft-07
$schemaURI
Signature
declare const META_SCHEMA_URI_DRAFT_2020_12: "https://json-schema.org/draft/2020-12/schema"Decoding
fromSchemaDraft07
Parses a raw Draft-07 JSON Schema into a Document<"draft-2020-12">.
When to use
Use when you have a raw JSON Schema object that follows Draft-07 conventions and need the canonical Draft-2020-12 document representation.
Details
This converts Draft-07 tuple syntax (items as array plus
additionalItems) to Draft-2020-12 form (prefixItems plus items), splits
dependencies into dependentRequired and dependentSchemas, converts
plain-name $id fragments to $anchor, and extracts root-level
definitions into the definitions field. Local JSON Pointer refs are
relocated when one of these structural conversions moves its target.
Gotchas
Unknown and custom keywords are copied as opaque values. Their contents are
not treated as nested schemas. Draft-07 keywords such as if / then /
else and contains are preserved and their subschemas are converted.
Siblings of a valid Draft-07 $ref are ignored according to Draft-07
semantics. The conversion throws when a Draft-07 $id fragment cannot be
represented as a Draft-2020-12 $anchor, or when an unknown Draft-07
keyword would become an active Draft-2020-12 keyword after copying.
See
Signature
declare function fromSchemaDraft07(js: JsonSchema): Document<"draft-2020-12">Example
(Parsing a Draft-07 schema)
import { JsonSchema } from "effect"
const raw: JsonSchema.JsonSchema = { type: "object", properties: { tags: { type: "array", items: { type: "string" } } }}
const doc = JsonSchema.fromSchemaDraft07(raw)doc.dialect // => "draft-2020-12"doc.schema.properties // => { tags: { type: "array", items: { type: "string" } } }fromSchemaDraft2020_12
Parses a raw Draft-2020-12 JSON Schema into a Document<"draft-2020-12">.
When to use
Use when you already have a raw JSON Schema object in Draft-2020-12 format.
Details
This separates $defs from the root schema into the definitions field.
Unlike fromSchemaDraft07, this performs no keyword rewriting.
See
Signature
declare function fromSchemaDraft2020_12(js: JsonSchema): Document<"draft-2020-12">Example
(Parsing a Draft-2020-12 schema)
import { JsonSchema } from "effect"
const raw: JsonSchema.JsonSchema = { type: "number", minimum: 0, $defs: { PositiveInt: { type: "integer", minimum: 1 } }}
const doc = JsonSchema.fromSchemaDraft2020_12(raw)doc.schema // => { type: "number", minimum: 0 }doc.definitions // => { PositiveInt: { type: "integer", minimum: 1 } }fromSchemaOpenApi3_0
Parses a raw OpenAPI 3.0 JSON Schema into a Document<"draft-2020-12">.
When to use
Use when you need to consume raw JSON Schema objects from an OpenAPI 3.0 specification.
Details
This directly converts OpenAPI 3.0 schema objects to Draft-2020-12. It
handles nullable, singular example, boolean exclusiveMinimum and
exclusiveMaximum, and OpenAPI component refs. Only values in OpenAPI
schema positions are traversed as schemas.
Gotchas
OpenAPI 3.0 nullable is applied only when the same Schema Object has an
explicit string type; other constraints such as enum are left
unchanged. Unknown keywords, vendor extensions, and annotation values are
copied opaquely unless their name would become active in Draft 2020-12 and
change meaning, in which case conversion throws. Siblings of a valid
OpenAPI 3.0 $ref are ignored.
See
Signature
declare function fromSchemaOpenApi3_0(schema: JsonSchema): Document<"draft-2020-12">Example
(Parsing an OpenAPI 3.0 nullable schema)
import { JsonSchema } from "effect"
const raw: JsonSchema.JsonSchema = { type: "string", nullable: true}
const doc = JsonSchema.fromSchemaOpenApi3_0(raw)doc.schema.type // => ["string", "null"]fromSchemaOpenApi3_1
Parses a raw OpenAPI 3.1 JSON Schema into a Document<"draft-2020-12">.
When to use
Use when you need to consume raw JSON Schema objects from an OpenAPI 3.1 specification.
Details
This rewrites #/components/schemas/... refs to #/$defs/..., normalizes the
OpenAPI base dialect URI to Draft 2020-12, converts the deprecated singular
example field to examples, then delegates to
fromSchemaDraft2020_12.
Gotchas
When both example and examples are present, the singular example is
prepended to the array. Custom $schema dialect URIs and unknown keywords
are copied opaquely. Component references inside a schema resource identified
by $id are left unchanged because they are relative to that resource.
See
Signature
declare function fromSchemaOpenApi3_1(js: JsonSchema): Document<"draft-2020-12">Example
(Parsing an OpenAPI 3.1 schema)
import { JsonSchema } from "effect"
const raw: JsonSchema.JsonSchema = { type: "object", properties: { user: { $ref: "#/components/schemas/User" } }}
const doc = JsonSchema.fromSchemaOpenApi3_1(raw)doc.schema.properties // => { user: { $ref: "#/$defs/User" } }Encoding
toDocumentDraft04
Converts a Document<"draft-2020-12"> to a Document<"draft-04">.
When to use
Use when you need to output a canonical JSON Schema document in Draft-04 format.
Details
This directly rewrites #/$defs/... refs to #/definitions/..., converts
tuple syntax, merges canonical dependencies, lowers const to enum,
converts numeric exclusive bounds to the Draft-04 boolean form, lowers
conditionals and basic contains through boolean applicators, and converts
both the root schema and all definitions.
Gotchas
Unknown and custom keywords are copied as opaque values. Newer annotation
keywords are preserved as Draft-04 extensions. Known keywords
without a Draft-04 equivalent, including propertyNames, non-default
contains cardinality, dynamic references, and unevaluated constraints,
cause the conversion to throw instead of being dropped. A conditional with
both branches also throws when lowering it would duplicate a nested schema
identifier. Conversion also throws when an opaque Draft-2020-12 keyword
would collide with an active Draft-04 keyword, or when $id and $anchor
occur together because Draft-04 cannot preserve both identifiers.
See
- toDocumentDraft07 for converting to Draft-07
Signature
declare function toDocumentDraft04(document: Document<"draft-2020-12">): Document<"draft-04">Example
(Converting exclusive bounds)
import { JsonSchema } from "effect"
const doc = JsonSchema.fromSchemaDraft2020_12({ type: "number", exclusiveMinimum: 0})
JsonSchema.toDocumentDraft04(doc).schema // => { type: "number", minimum: 0, exclusiveMinimum: true }toDocumentDraft07
Converts a Document<"draft-2020-12"> to a Document<"draft-07">.
When to use
Use when you need to output a canonical JSON Schema document in Draft-07 format.
Details
This rewrites #/$defs/... refs to #/definitions/..., converts
Draft-2020-12 tuple syntax (prefixItems plus items) to Draft-07 form
(items as array plus additionalItems), merges dependentRequired and
dependentSchemas into dependencies, and converts both the root schema
and all definitions. Local JSON Pointer refs are relocated when structural
keywords move.
Gotchas
Unknown and custom keywords are copied as opaque values. Known keywords
that Draft-07 cannot represent cause the conversion to throw
instead of being dropped. These include dynamic references,
unevaluatedProperties, unevaluatedItems, and non-default minContains
or maxContains constraints. Conversion also throws when an opaque
Draft-2020-12 keyword would collide with an active Draft-07 keyword, or when
$id and $anchor occur together because Draft-07 cannot preserve both identifiers.
See
- fromSchemaDraft07
- toDocumentDraft04 for converting to Draft-04
- toMultiDocumentOpenApi3_1
Signature
declare function toDocumentDraft07(document: Document<"draft-2020-12">): Document<"draft-07">Example
(Converting to Draft-07)
import { JsonSchema } from "effect"
const doc = JsonSchema.fromSchemaDraft2020_12({ type: "array", prefixItems: [{ type: "string" }, { type: "number" }], items: { type: "boolean" }})
const draft07 = JsonSchema.toDocumentDraft07(doc)draft07.dialect // => "draft-07"draft07.schema.items // => [{ type: "string" }, { type: "number" }]draft07.schema.additionalItems // => { type: "boolean" }toMultiDocumentOpenApi3_1
Converts a MultiDocument<"draft-2020-12"> to a
MultiDocument<"openapi-3.1">.
When to use
Use when you need to emit an OpenAPI 3.1 multi-document from canonical JSON Schema documents.
Details
This rewrites local #/$defs/... refs to #/components/schemas/... and
sanitizes definition keys to match the OpenAPI component key pattern
(^[a-zA-Z0-9.\-_]+$) by replacing invalid characters with _. Valid keys
are preserved. When sanitized keys collide, the converter appends the first
available _1, _2, and subsequent suffix, with allocation independent of
definition insertion order. All local refs are updated to use the allocated
keys, including refs to paths within a definition.
Gotchas
External refs and local refs outside #/$defs are left unchanged. Conversion
throws when a custom keyword would become an active OpenAPI keyword and
therefore change meaning. References inside schema resources identified by
$id are left unchanged. Conversion throws when an identified root schema
references the detached shared definitions pool because OpenAPI cannot
preserve that fragment reference.
See
Signature
declare function toMultiDocumentOpenApi3_1(multiDocument: MultiDocument<"draft-2020-12">): MultiDocument<"openapi-3.1">Example
(Converting to OpenAPI 3.1)
import { JsonSchema } from "effect"
const multi: JsonSchema.MultiDocument<"draft-2020-12"> = { dialect: "draft-2020-12", schemas: [{ $ref: "#/$defs/User" }], definitions: { User: { type: "object", properties: { name: { type: "string" } } } }}
const openapi = JsonSchema.toMultiDocumentOpenApi3_1(multi)openapi.dialect // => "openapi-3.1"openapi.schemas[0] // => { $ref: "#/components/schemas/User" }Models
Definitions interface
A record of named JSON Schema definitions, keyed by definition name.
When to use
Use as the shared lookup table for named JSON Schema nodes that are referenced from JSON Schema documents.
Details
The map is dialect-neutral. Conversion APIs emit it as $defs,
definitions, or components.schemas depending on the target format.
See
- Document for a single root schema with definitions
- MultiDocument for multiple root schemas sharing definitions
Signature
interface Definitions extends Record<string, JsonSchema> { [key: string]: JsonSchema;}The set of JSON Schema dialects supported by this module.
When to use
Use as the dialect marker for JsonSchema documents when parsing,
converting, or emitting schemas across the supported formats.
Details
Supported values are "draft-04" for JSON Schema Draft-04, "draft-07"
for JSON Schema Draft-07, "draft-2020-12" for JSON Schema Draft 2020-12
and the canonical internal form, "openapi-3.1" for OpenAPI 3.1, and
"openapi-3.0" for OpenAPI 3.0.
See
- Document for a single root schema tagged with a dialect
- MultiDocument for multiple root schemas tagged with a dialect
Signature
type Dialect = "draft-04" | "draft-07" | "draft-2020-12" | "openapi-3.1" | "openapi-3.0"A structured container for a single JSON Schema and its associated definitions.
When to use
Use when you need to carry a root schema together with its shared
definitions, or when converting between dialects with the from* and to*
functions.
Details
The schema field holds the root schema without the definitions
collection. Root definitions are stored separately in definitions and
referenced via #/$defs/<name> for Draft-2020-12, #/definitions/<name>
for Draft-04 and Draft-07, and #/components/schemas/<name> for OpenAPI 3.1
and OpenAPI 3.0.
See
Signature
interface Document<D extends Dialect> { readonly definitions: Definitions; readonly dialect: D; readonly schema: JsonSchema;}Example
(Inspecting a parsed document)
import { JsonSchema } from "effect"
const raw: JsonSchema.JsonSchema = { type: "string", $defs: { Trimmed: { type: "string", minLength: 1 } }}
const doc = JsonSchema.fromSchemaDraft2020_12(raw)
doc.dialect // => "draft-2020-12"doc.schema // => { type: "string" }doc.definitions // => { Trimmed: { type: "string", minLength: 1 } }JsonSchema interface
A plain object representing a single JSON Schema node.
When to use
Use to represent an arbitrary JSON Schema object regardless of dialect.
Details
This is an open record type ([x: string]: unknown) so it can hold any JSON
Schema keyword. Most functions in this module accept or return this type.
Signature
interface JsonSchema { [x: string]: unknown;}MultiDocument interface
Like Document, but carries multiple root schemas that share a single definitions pool.
When to use
Use when generating several schemas, such as a request body and a response body, that reference the same set of definitions.
Details
The schemas tuple is non-empty and contains at least one element.
See
Signature
interface MultiDocument<D extends Dialect> { readonly definitions: Definitions; readonly dialect: D; readonly schemas: readonly [JsonSchema, JsonSchema];}The JSON Schema primitive type names.
When to use
Use to restrict a JSON Schema type keyword to the supported primitive names.
Signature
type Type = "string" | "number" | "boolean" | "array" | "object" | "null" | "integer"