{"id":15013059,"url":"https://github.com/andyglow/scala-jsonschema","last_synced_at":"2025-04-06T09:10:46.597Z","repository":{"id":24119966,"uuid":"89709210","full_name":"andyglow/scala-jsonschema","owner":"andyglow","description":"Scala JSON Schema","archived":false,"fork":false,"pushed_at":"2024-09-16T22:31:16.000Z","size":1353,"stargazers_count":125,"open_issues_count":45,"forks_count":38,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-30T07:11:18.451Z","etag":null,"topics":["json-schema","scala"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andyglow.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"andyglow","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2017-04-28T13:36:17.000Z","updated_at":"2025-03-06T17:54:28.000Z","dependencies_parsed_at":"2023-11-16T20:05:38.852Z","dependency_job_id":"dd3d590f-445c-403f-906e-735e0bba5bba","html_url":"https://github.com/andyglow/scala-jsonschema","commit_stats":{"total_commits":465,"total_committers":16,"mean_commits":29.0625,"dds":0.5870967741935484,"last_synced_commit":"91c9c09f4ecf8cf4921062384310b333a832a0ee"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyglow%2Fscala-jsonschema","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyglow%2Fscala-jsonschema/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyglow%2Fscala-jsonschema/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyglow%2Fscala-jsonschema/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andyglow","download_url":"https://codeload.github.com/andyglow/scala-jsonschema/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247457803,"owners_count":20941906,"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","scala"],"created_at":"2024-09-24T19:43:40.700Z","updated_at":"2025-04-06T09:10:46.575Z","avatar_url":"https://github.com/andyglow.png","language":"Scala","funding_links":["https://github.com/sponsors/andyglow"],"categories":[],"sub_categories":[],"readme":"# Scala JSON Schema\n[![Support ukraine](https://img.shields.io/static/v1?label=United24\u0026message=Support%20Ukraine\u0026color=lightgrey\u0026link=https%3A%2F%2Fu24.gov.ua\u0026logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAASwAAADICAYAAABS39xVAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANKSURBVHhe7dZBThRhFEbRnx1IgvtFiIoxbgemOHLAhAoJ1QyaBahroKxqE%2BMS6iZncPKSbwE3b4yr6W58en4Z148zwC5tjbqabrdgvZ59PS5nn2eAfVobtbbquAXrcBquJ4B9Wht1%2BrQEC9g9wQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8j4F6zL%2BTA%2BHpfxYR0A9mhr1OXzPC5u7g%2Fvv%2F1YLr58B9ilU6Nu7ufx6%2BH88Hs6X9YLsEtbo34%2BvJvH29M4LC9jWZ4Admpt1NqqNVjTGqz5bFkmgJ1aG%2FX2KFhAgWABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVk%2FBes1%2BX4dwDYpbVRa6uOW7Du3p7Hy1YvgF3aGjWN2z9qCgwkg1n6XwAAAABJRU5ErkJggg%3D%3D)](https://u24.gov.ua)\n[![Build](https://github.com/andyglow/scala-jsonschema/actions/workflows/ci.yml/badge.svg?event=push)](https://github.com/andyglow/scala-jsonschema/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/andyglow/scala-jsonschema/branch/master/graph/badge.svg?token=e8E62N8PiJ)](https://codecov.io/gh/andyglow/scala-jsonschema)\n![](https://img.shields.io/static/v1.svg?label=Supported\u0026nbsp;Scala\u0026message=2.11,2.12,2.13\u0026color=gray)\n[![Version](https://img.shields.io/badge/dynamic/json.svg?label=Released\u0026nbsp;Version\u0026query=%24.response.docs%5B0%5D.latestVersion\u0026url=https%3A%2F%2Fsearch.maven.org%2Fsolrsearch%2Fselect%3Fq%3Dscala-jsonschema-core_2.13%26start%3D0%26rows%3D1)](https://search.maven.org/artifact/com.github.andyglow/scala-jsonschema-core_2.13/)\n\n*SBT dependencies:*\n\nMain module:\n\n```scala\nlibraryDependencies += \"com.github.andyglow\" %% \"scala-jsonschema\" % \u003cversion\u003e // \u003c-- required\n```\n\nOther libraries:\n\n```scala\nlibraryDependencies ++= Seq(\n  \"com.github.andyglow\" %% \"scala-jsonschema-core\" % \u003cversion\u003e,              // \u003c-- transitive\n  \"com.github.andyglow\" %% \"scala-jsonschema-macros\" % \u003cversion\u003e % Provided, // \u003c-- transitive\n  // json bridge. pick one\n  \"com.github.andyglow\" %% \"scala-jsonschema-play-json\" % \u003cversion\u003e,         // \u003c-- optional\n  \"com.github.andyglow\" %% \"scala-jsonschema-spray-json\" % \u003cversion\u003e,        // \u003c-- optional\n  \"com.github.andyglow\" %% \"scala-jsonschema-circe-json\" % \u003cversion\u003e,        // \u003c-- optional\n  \"com.github.andyglow\" %% \"scala-jsonschema-json4s-json\" % \u003cversion\u003e,       // \u003c-- optional\n  \"com.github.andyglow\" %% \"scala-jsonschema-ujson\" % \u003cversion\u003e,             // \u003c-- optional\n  // joda-time support\n  \"com.github.andyglow\" %% \"scala-jsonschema-joda-time\" % \u003cversion\u003e,         // \u003c-- optional\n  // cats support\n  \"com.github.andyglow\" %% \"scala-jsonschema-cats\" % \u003cversion\u003e,              // \u003c-- optional\n  // refined support\n  \"com.github.andyglow\" %% \"scala-jsonschema-refined\" % \u003cversion\u003e,           // \u003c-- optional\n  // enumeratum support\n  \"com.github.andyglow\" %% \"scala-jsonschema-enumeratum\" % \u003cversion\u003e,        // \u003c-- optional\n  // zero-dependency json and jsonschema parser\n  \"com.github.andyglow\" %% \"scala-jsonschema-parser\" % \u003cversion\u003e             // \u003c-- optional\n)\n```\n\n\n## Generate JSON Schema from Scala classes\n\nThe goal of this library is to make JSON Schema generation done the way all popular JSON reading/writing libraries do.\nInspired by Coursera Autoschema but uses `Scala Macros` instead of `Java Reflection`.\n\n## Features\n- Supports Json Schema `draft-04`, `draft-06`, `draft-07`, `draft-09`, `draft-12`\n- Supports `case classes`\n- Supports `value classes`\n- Supports `sealed trait enums`\n- Supports `sealed trait case classes`\n- Supports `recursive types`\n- Supports `scala.Enumeration`\n- Treats `scala.Option` as optional fields\n- As well as treats fields with `default values` as optional\n- Any `Iterable` is treated as `array`\n- Pluggable [Joda-Time](https://github.com/JodaOrg/joda-time) Support\n- Pluggable [Cats](https://github.com/typelevel/cats) Support\n- Pluggable [Refined](https://github.com/fthomas/refined) Support\n- Pluggable [Enumeratum](https://github.com/lloydmeta/enumeratum) Support\n- Supports generic data types\n\n### Types supported out of the box\n- `Boolean`\n- Numeric\n    - `Short`\n    - `Int`\n    - `Char`\n    - `Double`\n    - `Float`\n    - `Long`\n    - `BigInt`\n    - `BigDecimal`\n- `String`\n- Date Time\n    - `java.util.Date`\n    - `java.sql.Timestamp`\n    - `java.time.Instant`\n    - `java.time.LocalDateTime`\n    - `java.sql.Date`\n    - `java.time.LocalDate`\n    - `java.sql.Time`\n    - `java.time.LocalTime`\n- with JodaTime module imported\n    - `org.joda.time.Instant`\n    - `org.joda.time.DateTime`\n    - `org.joda.time.LocalDateTime`\n    - `org.joda.time.LocalDate`\n    - `org.joda.time.LocalTime`\n- with Cats module imported\n    - `cats.data.NonEmptyList`\n    - `cats.data.NonEmptyVector`\n    - `cats.data.NonEmptySet`\n    - `cats.data.NonEmptyChain`\n    - `cats.data.NonEmptyMap`\n    - `cats.data.NonEmptyStream` (for scala 2.11, 2.12)\n    - `cats.data.NonEmptyLazyList` (for scala 2.13)\n    - `cats.data.OneAnd`\n- with Refined module imported you can refine original types with these\n    - boolean\n        - `eu.timepit.refined.boolean.And`\n        - `eu.timepit.refined.boolean.Or`\n        - `eu.timepit.refined.boolean.Not`\n    - string\n        - `eu.timepit.refined.collection.Size`\n        - `eu.timepit.refined.collection.MinSize`\n        - `eu.timepit.refined.collection.MaxSize`\n        - `eu.timepit.refined.collection.Empty`\n        - `eu.timepit.refined.collection.NonEmpty`\n        - `eu.timepit.refined.string.Uuid`\n        - `eu.timepit.refined.string.Uri`\n        - `eu.timepit.refined.string.Url`\n        - `eu.timepit.refined.string.IPv4`\n        - `eu.timepit.refined.string.IPv6`\n        - `eu.timepit.refined.string.Xml`\n        - `eu.timepit.refined.string.StartsWith`\n        - `eu.timepit.refined.string.EndsWith`\n        - `eu.timepit.refined.string.MatchesRegex`\n        - `eu.timepit.refined.string.Trimmed`\n    - number\n        - `eu.timepit.refined.numeric.Positive`\n        - `eu.timepit.refined.numeric.Negative`\n        - `eu.timepit.refined.numeric.NonPositive`\n        - `eu.timepit.refined.numeric.NonNegative`\n        - `eu.timepit.refined.numeric.Greather`\n        - `eu.timepit.refined.numeric.Less`\n        - `eu.timepit.refined.numeric.GreaterEqual`\n        - `eu.timepit.refined.numeric.LessEqual`\n        - `eu.timepit.refined.numeric.Divisable`\n    - collection\n        - `eu.timepit.refined.collection.Size`\n        - `eu.timepit.refined.collection.MinSize`\n        - `eu.timepit.refined.collection.MaxSize`\n        - `eu.timepit.refined.collection.Empty`\n        - `eu.timepit.refined.collection.NonEmpty`\n- with Enumeratum module enabled\n    - `enums` based on `EnumEntry`/`Enum`            \n    - `enums` based on `ValueEnumEntry`/`ValueEnum`            \n- Misc\n    - `java.util.UUID`\n    - `java.net.URL`\n    - `java.net.URI`\n- Collections\n    - String Map (eg. `Map[String, T]`)\n    - Int Map (eg. `Map[Int, T]`)\n    - `Iterable[T]`\n- Sealed Trait hierarchy of case objects (Enums)\n- Case Classes\n    - default value\n- Sealed Trait hierarchy of case classes\n- Value Classes    \n\n## Example\nSuppose you have defined this data structures\n```scala\nsealed trait Gender\n\nobject Gender {\n\n    case object Male extends Gender\n\n    case object Female extends Gender\n}\n\ncase class Company(name: String)\n\ncase class Car(name: String, manufacturer: Company)\n\ncase class Person(\n    firstName: String,\n    middleName: Option[String],\n    lastName: String,\n    gender: Gender,\n    birthDay: java.time.LocalDateTime,\n    company: Company,\n    cars: Seq[Car])\n```\n\nNow you have several ways to specify your schema.\n\n### In-Lined\nIn simple words in-lined mode means you will have no `definitions`. Type you want to use as source for schema will\nbe represented in json schema without reusable data blocks.  \n```scala\nimport json._\n\nval personSchema: json.Schema[Person] = Json.schema[Person]\n```\nAs result you will receive this:\n```json\n{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"type\": \"object\",\n  \"additionalProperties\": false,\n  \"properties\": {\n    \"middleName\": {\n      \"type\": \"string\"\n    },\n    \"cars\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"object\",\n        \"additionalProperties\": false,\n        \"properties\": {\n          \"name\": {\n            \"type\": \"string\"\n          },\n          \"manufacturer\": {\n            \"type\": \"object\",\n            \"additionalProperties\": false,\n            \"properties\": {\n              \"name\": {\n                \"type\": \"string\"\n              }\n            },\n            \"required\": [\n              \"name\"\n            ]\n          }\n        },\n        \"required\": [\n          \"name\",\n          \"manufacturer\"\n        ]\n      }\n    },\n    \"company\": {\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"name\"\n      ]\n    },\n    \"lastName\": {\n      \"type\": \"string\"\n    },\n    \"firstName\": {\n      \"type\": \"string\"\n    },\n    \"birthDay\": {\n      \"type\": \"string\",\n      \"format\": \"date-time\"\n    },\n    \"gender\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"Male\",\n        \"Female\"\n      ]\n    }\n  },\n  \"required\": [\n    \"company\",\n    \"lastName\",\n    \"birthDay\",\n    \"gender\",\n    \"firstName\",\n    \"cars\"\n  ]\n}\n```\n\n### Regular\nSchema generated in Regular mode will contain so many `definitions` so many separated definitions you provide.\nLets take a look at example code: \n\n```scala\nimport json._\n\nimplicit val genderSchema: json.Schema[Gender] = Json.schema[Gender]\n\nimplicit val companySchema: json.Schema[Company] = Json.schema[Company]\n\nimplicit val carSchema: json.Schema[Car] = Json.schema[Car]\n\nimplicit val personSchema: json.Schema[Person] = Json.schema[Person]\n```\nHere we defined, besides Person schema, gender, company and car schemas. \nThe result will be looking this way then.\n```json\n{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"type\": \"object\",\n  \"additionalProperties\": false,\n  \"properties\": {\n    \"middleName\": {\n      \"type\": \"string\"\n    },\n    \"cars\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"$ref\": \"#/definitions/com.github.andyglow.jsonschema.ExampleMsg.Car\"\n      }\n    },\n    \"company\": {\n      \"$ref\": \"#/definitions/com.github.andyglow.jsonschema.ExampleMsg.Company\"\n    },\n    \"lastName\": {\n      \"type\": \"string\"\n    },\n    \"firstName\": {\n      \"type\": \"string\"\n    },\n    \"birthDay\": {\n      \"type\": \"string\",\n      \"format\": \"date-time\"\n    },\n    \"gender\": {\n      \"$ref\": \"#/definitions/com.github.andyglow.jsonschema.ExampleMsg.Gender\"\n    }\n  },\n  \"required\": [\n    \"company\",\n    \"lastName\",\n    \"birthDay\",\n    \"gender\",\n    \"firstName\",\n    \"cars\"\n  ],\n  \"definitions\": {\n    \"com.github.andyglow.jsonschema.ExampleMsg.Company\": {\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"name\"\n      ]\n    },\n    \"com.github.andyglow.jsonschema.ExampleMsg.Car\": {\n      \"type\": \"object\",\n      \"additionalProperties\": false,\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\"\n        },\n        \"manufacturer\": {\n          \"$ref\": \"#/definitions/com.github.andyglow.jsonschema.ExampleMsg.Company\"\n        }\n      },\n      \"required\": [\n        \"name\",\n        \"manufacturer\"\n      ]\n    },\n    \"com.github.andyglow.jsonschema.ExampleMsg.Gender\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"Male\",\n        \"Female\"\n      ]\n    }\n  }\n}\n```\n\n## Definitions / References\nThere is a couple of ways to specify reference of schema.\n1. It could be generated from type name (including type args)\n2. You can do it yourself. It is useful when you want to provide couple of schemas with same type but with different validation rules.\n\nSo originally you use\n```scala\nimport json._\n\nimplicit val someStrSchema: json.Schema[String] = Json.schema[String]\n\nimplicit val someArrSchema: json.Schema[Array[String]] = Json.schema[Array[String]]\n\nprintln(JsonFormatter.format(AsValue.schema(someArrSchema)))\n``` \n\n```json\n{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"type\": \"array\",\n  \"items\": {\n    \"$ref\": \"#/definitions/java.lang.String\"\n  },\n  \"definitions\": {\n    \"java.lang.String\": {\n      \"type\": \"string\"\n    }\n  }\n}\n```\n\nSee that `java.lang.String`?\n\nTo use custom name, just apply it.\n```scala\nimport json._\n\nimplicit val someStrSchema: json.Schema[String] = Json.schema[String].toDefinition(\"my-lovely-string\")\n\nimplicit val someArrSchema: json.Schema[Array[String]] = Json.schema[Array[String]]\n\nprintln(JsonFormatter.format(AsValue.schema(someArrSchema, json.schema.Version.Draft04())))\n``` \n\n```json\n{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"type\": \"array\",\n  \"items\": {\n    \"$ref\": \"#/definitions/my-lovely-string\"\n  },\n  \"definitions\": {\n    \"my-lovely-string\": {\n      \"type\": \"string\"\n    }\n  }\n}\n```\n\nThere is, though, one circumstance that will make you think twice defining `implicit val someStrSchema: json.Schema[String] = Json.schema[String]` as it will influence all string fields or components of your schema.\nSay you want to use simple string along with validated string for ID representation.\nAs the library operates at compile time level it completely rely on type information and\nthus it limits us to only one solution: specify special types as types.\n\n### Use Value Classes.\n```scala\ncase class UserId(value: String) extends AnyVal\n\ncase class User(id: UserId, name: String)\n```\n\nThen you can do\n```scala\nimport json._\n\nimplicit val userIdSchema: json.Schema[UserId] = Json.schema[UserId].toDefinition(\"userId\")\n\nimplicit val userSchema: json.Schema[User] = Json.schema[User]\n\nprintln(JsonFormatter.format(AsValue.schema(someArrSchema)))\n``` \n\nand expect\n```json\n{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"type\": \"object\",\n  \"additionalProperties\": false,\n  \"properties\": {\n    \"id\": {\n      \"$ref\": \"#/definitions/userId\"\n    },\n    \"name\": {\n      \"type\": \"string\"\n    },\n    \"required\": [\n      \"id\",\n      \"name\"\n    ],\n    \"definitions\": {\n      \"userId\": {\n        \"type\": \"string\"\n      }\n    }\n  }\n}\n``` \n\n## Validation\nIt is also possible to add specific validation rules to our schemas.\n\nAvailable validations:\n- multipleOf\n- maximum\n- minimum\n- exclusiveMaximum\n- exclusiveMinimum\n- maxLength\n- minLength\n- pattern\n- maxItems\n- minItems\n- uniqueItems\n- maxProperties\n- minProperties\n\nExample\n```scala\nimport json._\nimport json.Validation._\n\nimplicit val vb = ValidationBound.mk[UserId, String]\n\nimplicit val userIdSchema: json.Schema[UserId] = Json.schema[UserId].toDefinition(\"userId\") withValidation (\n  `pattern` := \"[a-f\\\\d]{16}\"\n)\n``` \nDefinition will look then like\n```json\n{\n  \"userId\": {\n    \"type\": \"string\",\n    \"pattern\": \"[a-f\\\\d]{16}\"\n  }\n}\n```\n\n## Free objects\nSometimes you need to include some more relaxed structure like the json itself into your models.\nIn such cases you want your final schema would contain something like this:\n```json\n{\n  \"type\": \"object\",\n  \"additionalProperties\": true\n}\n```   \nIn order to get this, you can use `Schema.object.Free`. Like in this Play-Json based example:\n```scala\nimport play.api.libs.json._\n\n// model\ncase class Payload(id: String, name: String, metadata: JsObject)\n\n// metadata schema\nimplicit val metaSchema: json.Schema[JsObject] = json.Schema.`object`.Free[JsObject]()\n\n// or alternatively define a metadata Predef in case you need this to not go to definition section of json-schema\n// implicit val metaPredef: json.schema.Predef[JsObject] = json.schema.Predef(json.Schema.`object`.Free[JsObject]())\n\n// payload schema\nval payloadSchema: json.Schema[Payload] = Json.schema[Payload]\n``` \n\nAlso, there is API to make object definition Free (and vice versa, a Free definition Strict)\n```scala\ncase class Person(name: String, age: Int)\nval personSchema = Json.objectSchema[Person]\nval freePersonSchema = personSchema.free\nval strictPersonSchema = freePersonSchema.strict\n\nstrictPersonSchema == personSchema // equal\n```\n\n## Joda Time\nJoda Time Support allows you to use joda-time classes within your models.\nHere is an example.\n \n```scala\nimport com.github.andyglow.jsonschema.JodaTimeSupport._\nimport org.joda.time._\n\ncase class Event(id: String, timestamp: Instant)\n\nval eventSchema: Schema[Event] = Json.schema[Event]\n\nprintln(JsonFormatter.format(AsValue.schema(eventSchema)))\n```\nresults in\n```\n{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"type\": \"object\",\n  \"additionalProperties\": false,\n  \"properties\": {\n    \"id\": {\n      \"type\": \"string\"\n    },\n    \"timestamp\": {\n      \"$ref\": \"#/definitions/org.joda.time.Instant\"\n    }\n  },\n  \"required\": [\n    \"id\",\n    \"timestamp\"\n  ],\n  \"definitions\": {\n    \"org.joda.time.Instant\": {\n      \"type\": \"string\",\n      \"format\": \"date-time\"\n    }\n  }\n}\n```\n\n## Cats\nIn order to enable integration with `cats` we not only add it to dependencies, we also need tp import the integration package.\n```scala\nimport com.github.andyglow.jsonschema.CatsSupport._\n```\n// TODO: provide examples\n\n## Refined\nFor Refined types to get described accordingly we, besides adding integration to dependency list, need to import the integration package.\n```scala\nimport com.github.andyglow.jsonschema.RefinedSupport._\n```\n// TODO: provide examples\n\n## Enumeratum\nTo stitch Enumeratum support in we need to, add correcponding integration to dependencies, as well as import the integration package.\n```scala\nimport com.github.andyglow.jsonschema.EnumeratumSupport._\n```\n// TODO: provide examples\n\n## Json Libraries\nThe library uses its own Json model _com.github.andyglow.json.Value_ to represent Json Schema as JSON document.\nBut project contains additionally several modules which could connect it with library of your choice.\n\nCurrently supported:\n- Play Json\n- Spray Json\n- Circe\n- Json4s\n- uJson\n\nExample usage: _Play_\n```scala\nimport com.github.andyglow.jsonschema.AsPlay._\nimport json.schema.Version._\nimport play.api.libs.json._\n\ncase class Foo(name: String)\n\nval fooSchema: JsValue = Json.schema[Foo].asPlay(Draft04())\n``` \n\nExample usage: _Spray_\n```scala\nimport com.github.andyglow.jsonschema.AsSpray._\nimport json.schema.Version._\nimport spray.json._\n\ncase class Foo(name: String)\n\nval fooSchema: JsValue = Json.schema[Foo].asSpray(Draft04())\n``` \n\nExample usage: _Circe_\n```scala\nimport com.github.andyglow.jsonschema.AsCirce._\nimport json.schema.Version._\nimport io.circe._\n\ncase class Foo(name: String)\n\nval fooSchema: Json = Json.schema[Foo].asCirce(Draft04())\n``` \n\nExample usage: _Json4s_\n```scala\nimport com.github.andyglow.jsonschema.AsJson4s._\nimport json.schema.Version._\nimport org.json4s.JsonAST._\n\ncase class Foo(name: String)\n\nval fooSchema: JValue = Json.schema[Foo].asJson4s(Draft04())\n``` \n\nExample usage: _uJson_\n```scala\nimport com.github.andyglow.jsonschema.AsU._\nimport json.schema.Version._\n\ncase class Foo(name: String)\n\nval fooSchema: ujson.Value = Json.schema[Foo].asU(Draft04())\n``` \n\n## Enumerations\nA few words about enumeration support.\nMost of the time enumerations are enumerations, we don't need to know anything\nelse except allowed values, that's it. But.. sometimes we need something more. \nSometimes we need the specified values to show up some extra information.\nSome titles, descriptions, etc. `json-schema` doesn't support this, unfortunately.\nBut we can work around this. We can make macro to generate `oneof(const1, const2, const3, ...)` instead of `enum`.\nFor that you need to provide a special flag.\n\n```scala\nimplicit val jsonSchemaFlags: Flag with Flag.EnumsAsOneOf = null\n```\n\nthis should show up in implicit scope of the macro. \n\nExample.. Say we have a `Gender` enum specified like this\n```\nsealed trait Gender\nobject Gender {\n    case object Male extends Gender\n    case object Female extends Gender\n}\n```\n\nUsually `Json.schema[Gender]` returns something like this\n```json\n{\n  \"type\": \"string\",\n  \"enum\": [\n    \"Male\",\n    \"Female\"\n  ]\n}\n```\nBut after the flag added, what we have is\n```json\n{\n  \"oneOf\": [\n    { \"const\": \"Male\" },\n    { \"const\": \"Female\" }\n  ]\n}\n```\nWith this said, we can add some titles and descriptions into our models. \nFor example this model definition, with `EnumsAsOneOf` flag enabled\n```scala\n  sealed trait Gender\n  object Gender {\n    @title(\"The Male\") case object Male extends Gender\n    /** The Female\n      */\n    case object Female extends Gender\n  }\n```\nwill produce schema such as\n```json\n{\n  \"oneOf\": [\n    {\n      \"title\": \"The Male\",\n      \"const\": \"Male\"\n    },\n    {\n      \"description\": \"The Female\",\n      \"const\": \"Female\"\n    }\n  ]\n}\n```\nFor better explanation on how to apply documentation tags to the model please refer to the next chapter.\n\n## Documentation\nBy documentation, we mean extra information that can be carried along with the schema in\norder to improve its clarity. This all basically is about support of 2 fields: `title`, `description`.\nThere are 3 places where these fields may take a place.\n- `root` model level\n- `definition` level\n- `one-of` / `all-of` / `any-of` level\n\nWe have 3 ways to maintain documented models are supported.\n\n1. Annotations   \n2. Config\n3. Scaladoc\n\n### Annotations\nScala-JsonSchema specifies 2 annotations that can help you specify a model \n`@title` and `@description` as well as fields `@description`s.\n\nExample:\n```scala\nimport json._\nimport json.schema._\n\n@title(\"A Title\")\n@description(\"My perfect class\")\ncase class Model(\n    @description(\"A Param\") a: String,\n    @description(\"B Param\") b: Int)\n\nval schema = Json.objectSchema[Model]()\n```\nthis, being translated into json, gets you\n```json\n{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"My perfect class\",\n  \"title\": \"A Title\",\n  \"type\": \"object\",\n  \"additionalProperties\": false,\n  \"properties\": {\n    \"a\": {\n      \"type\": \"string\",\n      \"description\": \"A Param\"\n    },\n    \"b\": {\n      \"type\": \"integer\",\n      \"description\": \"B Param\"\n    }\n  },\n  \"required\": [\n    \"a\",\n    \"b\"\n  ]\n}\n```\n\n### Config\nAnother approach that you can use to keep your models concise, \nbut documented is to provide documentation separately. As config.\n\nHere is an example:\n```scala\nimport json._\n\ncase class Model(a: String, b: Int)\n\nval schema = Json.objectSchema[Model](\n  \"a\" -\u003e \"A Param\",\n  \"b\" -\u003e \"B Param\"\n) .withDescription(\"My perfect class\")\n  .withTitle(\"A Title\")\n```\nthis, being translated into json, gets you the same effect as annotation based approach\n```json\n{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"My perfect class\",\n  \"title\": \"A Title\",\n  \"type\": \"object\",\n  \"additionalProperties\": false,\n  \"properties\": {\n    \"a\": {\n      \"type\": \"string\",\n      \"description\": \"A Param\"\n    },\n    \"b\": {\n      \"type\": \"integer\",\n      \"description\": \"B Param\"\n    }\n  },\n  \"required\": [\n    \"a\",\n    \"b\"\n  ]\n}\n```\n\nThis approach also nicely fits when models are specified in separate module or external library.\n\n### Scaladoc\nAlso it is possible to infer descriptions from scaladoc. \nThis allows to reuse scaladoc that you might want to have anyways.\nThis approach has it's own drawbacks, though.\n- model classes must reside in the same module with schemas\n- it requires non-incremental build or full-rebuild to take effect \n\nExample:\n```scala\nimport json._\n\n/** My perfect class\n * \n * @param a A Param\n * @param b B Param\n */\ncase class Model(a: String, b: Int)\nval schema = Json.objectSchema[Model]()\n```\nthis, being translated into json, gets you\n```json\n{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"description\": \"My perfect class\",\n  \"type\": \"object\",\n  \"additionalProperties\": false,\n  \"properties\": {\n    \"a\": {\n      \"type\": \"string\",\n      \"description\": \"A Param\"\n    },\n    \"b\": {\n      \"type\": \"integer\",\n      \"description\": \"B Param\"\n    }\n  },\n  \"required\": [\n    \"a\",\n    \"b\"\n  ]\n}\n```\nOne little difference comparing to previous approaches is that this way you can't have `title` specified. \n\n### Combined approach\nAll these 3 techniques can be used all together.\nThe only thing you need to have in mind if going this way is that to extract different type \nof label Scala-JsonSchema will check certain sources in certain order.\n \n| Element                         | Order                                   |\n| ------------------------------- | --------------------------------------- |\n| case class `title`              | `Config` -\u003e `Annotation` -\u003e `Scaladoc`  |\n| case class `description`        | `Config` -\u003e `Annotation` -\u003e `Scaladoc`  |\n| case class field `description`  | `Config` -\u003e `Annotation` -\u003e `Scaladoc`  |\n\n## Annotations\n| Annotation     | Scope  | Description                                     |\n| -------------- | -------| ----------------------------------------------- |\n| @readOnly      | Field  | Adds `\"readOnly\": true` to property definition  |\n| @writeOnly     | Field  | Adds `\"writeOnly\": true` to property definition |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandyglow%2Fscala-jsonschema","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandyglow%2Fscala-jsonschema","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandyglow%2Fscala-jsonschema/lists"}