Documentation section: Serialization
JSON Schema Import
Prerelease. These pages describe 3.0.0-prerelease.2 and can differ from the published release. Read the Live 2.4.2 documentation instead.
JSON Schema Import
Section titled “JSON Schema Import”Import a JSON Schema into a Purview.ZodSharp schema with Z.FromJsonSchema. This API is provided by the JSON integration packages — reference either Purview.ZodSharp.SystemTextJson or Purview.ZodSharp.NewtonsoftJson. The two JSON integrations are mutually exclusive; pick one and import its JSON Schema namespace (ZodSharp.JsonSchema.SystemTextJson or ZodSharp.JsonSchema.NewtonsoftJson).
using ZodSharp;using ZodSharp.JsonSchema.SystemTextJson; // or ZodSharp.JsonSchema.NewtonsoftJson
var jsonSchemaString = """ { "type": "object", "properties": { "name": { "type": "string", "minLength": 3 }, "email": { "type": "string", "format": "email" } }, "required": ["name", "email"] } """;
var userSchema = Z.FromJsonSchema(jsonSchemaString);var result = userSchema.Validate(userData);Overloads
Section titled “Overloads”| Signature | Notes |
|---|---|
IZodSchema<object, object> FromJsonSchema(string jsonSchema) |
parses the JSON string into a JsonSchemaDefinition, then into a schema |
IZodSchema<object, object> FromJsonSchema(JsonSchemaDefinition schema) |
import from an already-deserialized definition |
Supported keywords
Section titled “Supported keywords”FromJsonSchemaParser (namespace ZodSharp.JsonSchema.SystemTextJson or ZodSharp.JsonSchema.NewtonsoftJson) maps:
type—string/number/integer/boolean/null/object/array.enum→ZodUnionof literals (a single member becomes a literal);const→ literal.anyOf/oneOf→ZodUnion;allOf→ the intersection of every branch (and the base schema when the schema also declares atype). A type-less branch isany, matching Zod’sfromJSONSchema.- String constraints —
minLength,maxLength,pattern, andformat(email,uri,uuid). Theuuid/guidformat maps to the versionless.UUID(); a versioned.UUID(UuidVersion.V7)schema exportsformat: "uuid"plus a version-pinningpattern, and theallOfcomposition preserves that pattern on import. Multiplepatternconstraints are composed underallOf, and every branch is applied. - Numeric constraints —
minimum,maximum,multipleOf;integeradditionally applies.Int(). - Objects —
requiredand optional fields viaZ.Object().Field(...). - Arrays —
items,minItems,maxItems. A nullable item schema (items.anyOfcontaining a{"type":"null"}branch) imports as a nullable element, matchingz.array(T.nullable())and the shape the generated exporter emits for an allow-null collection. - Records — an object with no
propertiesand anadditionalPropertiesschema imports as a record: every member is validated by the value schema, and a failure is reported under a typed key segment for the member (FullPath.ToDottedString()renders[a]; the legacyPathis["a"]).additionalProperties: truetreats every member asany;false(and an absent value) keeps the object contract.
Records
Section titled “Records”var schema = Z.FromJsonSchema( """ { "type": "object", "additionalProperties": { "type": "string", "minLength": 1 } } """);
schema.Validate(new Dictionary<string, object?> { ["a"] = "x" }); // Successschema.Validate(new Dictionary<string, object?> { ["a"] = "" }); // Failure at [a] (key segment)This is the shape the generated exporter writes for a dictionary property, so a generated dictionary schema
round-trips through Z.FromJsonSchema in either integration package. The result is a record schema (the
Z.Record shape), not an object with fixed properties.
Failures
Section titled “Failures”Imported schemas report the same structured errors as the equivalent fluent schemas:
- Type mismatches describe JSON kinds with Zod’s type names -
"Expected string, but got number"- and never nameJsonElement,JTokenor another CLR type. Theexpected/receivedparameters carry the same names. minItems/maxItemsreport exactly whatZodArrayreports:"Array must have at least 2 elements, but got 1", originarray, both bounds with their inclusivity, and categorytoo_small/too_big.- Literal mismatches (
const, single-memberenum) name the expected literal and only the kind of the received value; the value itself is not echoed. - Array elements and record values are re-pathed with typed index and key segments (
[1],[a]), keeping every field of the inner error (origin, bounds, category, parameters).
Limitations
Section titled “Limitations”-
$refis supported only for local references (#/..., for example#/$defs/Name). External$reftargets throwNotSupportedExceptionnaming the unsupported reference:External $ref 'external.json#/$defs/name' is not supported. Only local references ('#/...', for example '#/$defs/Name') can be resolved; inline or pre-resolve external schemas before importing.Inline the referenced schema, or move it under the root
$defs, before importing. Local references may be cyclic — a reference that is still being resolved becomes a lazy schema. -
The reader binds the JSON Schema keyword names
$schema,$id,$ref, and$defs(plus the draft-07definitions) through the integration package’sJsonSchemaSerializerOptions, and the same options write them back, so exported definitions round-trip through either package.JsonSchemaDefinitionitself carries no serializer annotations, so serialize it withJsonSchemaSerializerOptionsto get keyword-compliant output.
Cross-platform reuse
Section titled “Cross-platform reuse”Export a TypeScript/Zod schema to JSON Schema (Zod v4+ z.toJSONSchema) and import it on the backend:
import { z } from "zod";const UserSchema = z.object({ username: z.string().min(3), email: z.string().email() });const jsonSchema = z.toJSONSchema(UserSchema);var userSchema = Z.FromJsonSchema(jsonSchemaString);var result = userSchema.Validate(incomingData);See Cross-Platform Interop for the repository’s fixture-based verification of this loop.