Contents

ajevans99/swift-json-schema-codegen

Generate Swift types and JSON parsers from JSON Schema. Define a schema inline

Installation

Requires Swift 6.1 or later. Deployment targets are macOS 14, iOS 17, tvOS 17, watchOS 10, Mac Catalyst 17, and visionOS 1 or later. The CLI and generation core also support Linux.

Add the package dependency to Package.swift:

dependencies: [
  .package(
    url: "https://github.com/ajevans99/swift-json-schema-codegen.git",
    from: "0.3.0"
  )
]

Then add the library to your target's dependencies:

.product(name: "JSONSchemaCodegen", package: "swift-json-schema-codegen")

SwiftPM resolves the JSON Schema runtime dependency automatically.

Quick start

import JSONSchemaCodegen

@Schema(
  """
  {
    "type": "object",
    "properties": {
      "name": { "type": "string", "minLength": 1 },
      "age": { "type": "integer", "minimum": 0 }
    },
    "required": ["name"],
    "additionalProperties": false
  }
  """,
  output: .models
)
enum PersonSchema {}

let person: PersonSchema.Value = try PersonSchema.schema.parseAndValidate(
  instance: #"{"name":"Ada","age":36}"#
)

print(person.name) // Ada
// person.age is Int? because "age" is not required.

@Schema adds a static schema member and, in model mode, named types inside the enum. Here, PersonSchema.Value is an immutable Sendable struct with name: String and age: Int?. Missing required fields, negative ages, and unknown properties cause parseAndValidate to throw.

The macro takes a string literal and must be attached to an empty enum outside generic contexts. Invalid schemas produce compiler diagnostics with a JSON Pointer identifying the problem.

Choosing an output type

Use output: .models when you want named types, initializers, and typed string enums. Omitting it uses the default tuple output: the example above would return (name: String, age: Int?) without generating a Value model.

Two details are worth knowing before choosing:

  • In tuple mode, an object with one property returns that property's value,

not a one-field tuple. An object with no declared properties returns Void.

  • Optional and nullable are different. An optional nullable string is String??:

nil means absent, while .some(nil) means JSON null.

Use parseAndValidate for input validation. parse performs typed conversion but does not check every schema constraint. Model initializers do not validate constraints either.

See output types and schema support for collections, unions, recursion, and validation limits.

Generate from files

Command-line tool

From a checkout of this repository:

swift run json-schema-codegen \
  --output-style models \
  --output-directory Generated \
  Examples/PluginExample/Sources/PluginExample/Schemas/Common/design-tokens.schema.json \
  Examples/PluginExample/Sources/PluginExample/Schemas/theme.schema.json

This writes DesignTokensSchema.generated.swift and ThemeSchema.generated.swift. Each contains a public namespace enum with a static schema member and its generated models.

Include the generated Swift in your target. It imports JSONSchema and JSONSchemaBuilder; linking JSONSchemaCodegen as above makes those modules available. Schemas are compiled into the generated code, so the input files are not needed at runtime.

Pass all referenced schema files in the same invocation. References are resolved offline: a $ref URL is an identifier, not a request to download a schema.

SwiftPM build plugin

For generation during a build, attach the plugin to your target:

.executableTarget(
  name: "Example",
  dependencies: [
    .product(name: "JSONSchemaCodegen", package: "swift-json-schema-codegen")
  ],
  exclude: ["json-schema-codegen.json"],
  resources: [.copy("Schemas")],
  plugins: [
    .plugin(name: "JSONSchemaCodegenPlugin", package: "swift-json-schema-codegen")
  ]
)

Put your .schema.json files in Sources/Example/Schemas/ and create Sources/Example/json-schema-codegen.json:

{
  "version": 1,
  "output": "models"
}

The plugin generates and compiles the Swift sources automatically. It discovers schemas recursively under the target directory and resolves them as one batch. The resource declaration avoids SwiftPM's unhandled-file warnings; the generated parsers do not load those resources.

See the complete plugin example or the generation guide for configuration, filename rules, naming overrides, and the core API.

Scope and documentation

The generator targets JSON Schema 2020-12, including composition, local and cross-document references, and recursive schemas. It does not support custom dialects or every possible Swift representation of a schema. Validation and typed output are separate: a constraint can be enforced without appearing as a Swift field or type.

| Guide | Contents | | --- | --- | | Output types and schema support | Type mapping, string enums, recursion, supported keywords, and limits | | Generation | CLI options, plugin configuration, naming, references, and core APIs | | Shared schemas and encoding | Multiple roots sharing model types, and mapping models back to JSONValue | | Official meta-schema example | Offline generation from the official 2020-12 meta-schemas |

For OpenAPI generation, use Swift OpenAPI Schema Codegen.

Development

Run the package tests from the repository root:

swift test

The CI workflow also runs generated-code consumers on macOS and Linux. For a local end-to-end check of the CLI and plugin:

bash Tests/CLI/smoke.sh

On macOS with Xcode installed, also run the Xcode build-system regression check:

bash Tests/CLI/xcode-smoke.sh

It builds and runs the plugin example with fresh DerivedData, retaining logs under .build/xcode-smoke.*. To build it interactively, open Examples/PluginExample/PluginExample.xcworkspace and select the PluginExample scheme. The CLI product, executable target, and plugin tool lookup all use json-schema-codegen so Xcode locates the generated tool executable correctly.

The conformance harness checks generated code against the official JSON Schema Test Suite. Its README covers fixture setup, measured coverage, and known failures.

License

MIT. See LICENSE.

Package Metadata

Repository: ajevans99/swift-json-schema-codegen

Default branch: main

README: README.md