{"id":29079425,"url":"https://github.com/loopwork/jsonschema","last_synced_at":"2025-06-27T17:08:04.438Z","repository":{"id":283169981,"uuid":"950914558","full_name":"loopwork/JSONSchema","owner":"loopwork","description":"A Swift library for working with JSON Schema definitions — especially for AI tool use.","archived":false,"fork":false,"pushed_at":"2025-06-14T13:21:46.000Z","size":70,"stargazers_count":35,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-26T23:13:52.262Z","etag":null,"topics":["json-schema","tool-use"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/loopwork.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-03-18T21:58:27.000Z","updated_at":"2025-06-25T04:12:00.000Z","dependencies_parsed_at":null,"dependency_job_id":"1d64cd17-585c-498c-8a61-f8c6e1bce77d","html_url":"https://github.com/loopwork/JSONSchema","commit_stats":null,"previous_names":["loopwork-ai/jsonschema","loopwork/jsonschema"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/loopwork/JSONSchema","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loopwork%2FJSONSchema","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loopwork%2FJSONSchema/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loopwork%2FJSONSchema/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loopwork%2FJSONSchema/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/loopwork","download_url":"https://codeload.github.com/loopwork/JSONSchema/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loopwork%2FJSONSchema/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262298771,"owners_count":23289603,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json-schema","tool-use"],"created_at":"2025-06-27T17:02:37.899Z","updated_at":"2025-06-27T17:08:04.385Z","avatar_url":"https://github.com/loopwork.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JSONSchema\n\nA Swift library for working with JSON Schema definitions —\nespecially for declaring schemas for AI tool use.\n\nThis library implements core features of the\n[JSON Schema](https://json-schema.org/) standard,\ntargeting the **draft-2020-12** version.\n\n🙅‍♀️ This library specifically **does not** support the following features:\n\n- Document validation\n- Reference resolution\n- Conditional validation keywords, like\n  `dependentRequired`, `dependentSchemas`, and `if`/`then`/`else`\n- Custom vocabularies and meta-schemas\n\n## Requirements\n\n- Swift 6.0+ / Xcode 16+\n- macOS 14.0+ (Sonoma)\n- iOS 17.0+\n\n## Installation\n\n### Swift Package Manager\n\nAdd the following to your `Package.swift` file:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/loopwork/JSONSchema.git\", from: \"1.3.0\")\n]\n```\n\n## Usage\n\n### Creating JSON Schemas with Dictionary Literals\n\nCreate JSON Schema definitions with Swift's expressive dictionary literal syntax:\n\n```swift\nimport JSONSchema\n\n// Example of defining a schema for an AI tool\nlet getWeatherSchema: JSONSchema = .object(\n    properties: [\n        \"location\": .string(\n            description: \"The city and state/country, e.g. 'San Francisco, CA'\",\n            examples: [\"London, UK\", \"Tokyo, Japan\"]\n        ),\n        \"unit\": .string(\n            description: \"The temperature unit to use\",\n            enum: [\"celsius\", \"fahrenheit\"],\n            default: \"celsius\"\n        ),\n        \"include_forecast\": .boolean(\n            description: \"Whether to include the weather forecast\",\n            default: false\n        )\n    ],\n    required: [\"location\"]\n)\n\n// Complex schema with nested objects\nlet addressSchema: JSONSchema = [\n    \"street\": .string(),\n    \"city\": .string(),\n    \"zip\": .string(pattern: \"^[0-9]{5}$\")\n]\n\nlet orderSchema: JSONSchema = [\n    \"name\": .string(minLength: 2, maxLength: 100),\n    \"email\": .string(format: .email),\n    \"address\": addressSchema,\n    \"tags\": .array(items: .string()),\n    \"status\": .oneOf([\n        .string(enum: [\"active\", \"inactive\", \"pending\"]),\n        .object(\n            properties: [\n                \"error\": .boolean(const: true),\n                \"code\": .integer(enum: [400, 401, 403, 404]),\n                \"message\": .string(\n                    description: \"Detailed error message\",\n                    examples: [\"Invalid credentials\", \"Not found\"]\n                )\n            ],\n            required: [\"error\"],\n            additionalProperties: false\n        )\n    ])\n]\n```\n\n### Working with JSON Values\n\nThe library provides a `JSONValue` type that represents any valid JSON value:\n\n```swift\nimport JSONSchema\n\n// Create JSON values\nlet nullValue: JSONValue = .null\nlet boolValue: JSONValue = true\nlet numberValue: JSONValue = 42\nlet stringValue: JSONValue = \"hello\"\nlet arrayValue: JSONValue = [1, 2, 3]\nlet objectValue: JSONValue = [\"key\": \"value\"]\n\n// Extract typed values\nif let string = stringValue.stringValue {\n    print(string) // \"hello\"\n}\n\nif let number = numberValue.intValue {\n    print(number) // 42\n}\n\n// Use in schema definitions\nlet schema: JSONSchema = .object(\n    default: [\"name\": \"John Doe\"],\n    examples: [[\"name\": \"Jane Doe\", \"age\": 25]],\n    properties: [\n        \"name\": .string(),\n        \"age\": .integer()\n    ]\n)\n```\n\n### Schema Properties\n\nAccess schema metadata and type information through convenience properties:\n\n```swift\nimport JSONSchema\n\nlet schema: JSONSchema = .object(\n    title: \"Person\",\n    description: \"A human being\",\n    properties: [\n        \"name\": .string,\n        \"age\": .integer\n    ]\n)\n\n// Access metadata\nprint(schema.typeName) // \"object\"\nprint(schema.title) // \"Person\"\nprint(schema.description) // \"A human being\"\n```\n\n### JSON Value Compatibility\n\nThe library provides methods to check compatibility between JSON values and schemas:\n\n```swift\nimport JSONSchema\n\n// Check if a JSON value is compatible with a schema\nlet value: JSONValue = 42\nlet schema: JSONSchema = .integer(minimum: 0)\nlet isCompatible = value.isCompatible(with: schema) // true\n\n// Strict vs non-strict compatibility\nlet numberValue: JSONValue = 42\nlet numberSchema: JSONSchema = .number()\nlet strictCompatible = numberValue.isCompatible(with: numberSchema) // false\nlet nonStrictCompatible = numberValue.isCompatible(with: numberSchema, strict: false) // true\n```\n\n### Schema Serialization\n\n```swift\nimport JSONSchema\n\n// Create a schema\nlet schema: JSONSchema = .object(\n    title: \"Person\",\n    description: \"A human being\",\n    properties: [\n        \"name\": .string(),\n        \"age\": .integer(minimum: 0)\n    ],\n    required: [\"name\"]\n)\n\n// Encode to JSON\nlet encoder = JSONEncoder()\nencoder.outputFormatting = [.prettyPrinted]\nlet jsonData = try encoder.encode(schema)\nprint(String(data: jsonData, encoding: .utf8)!)\n\n// Decode from JSON\nlet decoder = JSONDecoder()\nlet decodedSchema = try decoder.decode(JSONSchema.self, from: jsonData)\n```\n\n### Preserving Property Order\n\nAccording to [the JSON spec](https://www.ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf) (emphasis added):\n\n\u003e ## 6. Objects\n\u003e [...] The JSON syntax does not impose any restrictions on the strings used as names,\n\u003e does not require that name strings be unique,\n\u003e and **does not assign any significance to the ordering of name/value pairs**. [...]\n\nAnd yet,\nJSON Schema documents often _do_ assign significance to the order of properties.\nIn such cases, it may be desireable to preserve this ordering.\nFor example,\nensuring that an auto-generated form for a `createEvent` tool\nlists `start` before `end`.\nFor this reason,\nthe associated value for `JSONSchema.object` properties use\n[the `OrderedDictionary` type from `apple/swift-collections`](https://github.com/apple/swift-collections)\n\nBy default,\n`JSONDecoder` doesn't guarantee stable ordering of keys.\nHowever, this package provides the following affordances\nto decode `JSONSchema` objects with properties\nin order they appear in the JSON string:\n\n- A static `extractSchemaPropertyOrder` method\n  that extracts property order from the top-level `\"properties\"` field\n  of a JSON Schema object.\n- A static `extractPropertyOrder` method\n  that extracts property order from any JSON object at a specified keypath.\n- A static `propertyOrderUserInfoKey` constant\n  that you can pass to `JSONDecoder`\n  (determined with either extraction method or some other means)\n  to guide the ordering of JSON Schema object properties.\n\n```swift\nlet json = \"\"\"\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"firstName\": {\"type\": \"string\"},\n    \"lastName\": {\"type\": \"string\"},\n    \"age\": {\"type\": \"integer\"},\n    \"email\": {\"type\": \"string\", \"format\": \"email\"}\n  }\n}\n\"\"\".data(using: .utf8)!\n\n// Extract property order from a JSON Schema object's \"properties\" field\nif let propertyOrder = JSONSchema.extractSchemaPropertyOrder(from: jsonData) {\n    // Configure decoder to preserve order\n    let decoder = JSONDecoder()\n    decoder.userInfo[JSONSchema.propertyOrderUserInfoKey] = propertyOrder\n\n    // Decode with preserved property order\n    let schema = try decoder.decode(JSONSchema.self, from: data)\n\n    // Properties will maintain their original order: `firstName`, `lastName`, `age`, `email`\n}\n\n// Or extract from a nested object using a keypath\nlet nestedJSONData = \"\"\"\n{\n  \"definitions\": {\n    \"person\": {\n      \"firstName\": \"John\",\n      \"lastName\": \"Doe\"\n    }\n  }\n}\n\"\"\".data(using: .utf8)!\n\nlet keyOrder = JSONSchema.extractPropertyOrder(from: nestedJSONData,\n                                               at: [\"definitions\", \"person\"])\n// keyOrder will be [\"firstName\", \"lastName\"]\n```\n\n## Motivation\n\nThere are a few other packages out there for working with JSON Schema,\nbut they did more than I needed.\n\nThis library focuses solely on defining and serializing JSON Schema values\nwith a clean, ergonomic API. \u003cbr/\u003e\n_That's it_.\n\nThe [implementation](/Sources/JSONSchema/) is deliberately minimal.\nAt its core is one big `JSONSchema` enumeration\nwith associated values for most of the JSON Schema keywords you might want.\nNo result builders, property wrappers, macros, or dynamic member lookup —\njust old-school Swift with choice conformance to `ExpressibleBy___Literal` 💅\n\n## License\n\nThis project is licensed under the Apache License, Version 2.0.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floopwork%2Fjsonschema","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Floopwork%2Fjsonschema","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floopwork%2Fjsonschema/lists"}