Skip to content

Instantly share code, notes, and snippets.

@kevinswiber
Last active March 17, 2022 21:02
Show Gist options
  • Save kevinswiber/4ee078f7bee175852587aca738377168 to your computer and use it in GitHub Desktop.
Save kevinswiber/4ee078f7bee175852587aca738377168 to your computer and use it in GitHub Desktop.
An example illustrating a use case of composition via templates.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/page.schema.json",
"title": "Page",
"description": "A page in a catalog",
"type": "object",
"properties": {
"title": {
"description": "A descriptive title for the page",
"type": "string"
},
"cursor": {
"description": "A unique pointer representing the page position."
"type": "string"
},
"count": {
"description": "The number of elements represented",
"type": "integer"
},
"previous": {
"description": "A link to the previous page",
"type": "string"
},
"next": {
"description": "A link to the next page",
"type": "string"
},
"items": {
"description": "Page elements",
"type": "array",
"items": {
"$ref": "<<<?????>>>"
},
"minItems": 1,
"uniqueItems": true
}
},
"required": [ "cursor", "count", "items" ]
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productId": {
"description": "The unique identifier for a product",
"type": "integer"
},
"productName": {
"description": "Name of the product",
"type": "string"
},
"price": {
"description": "The price of the product",
"type": "number",
"exclusiveMinimum": 0
},
"tags": {
"description": "Tags for the product",
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
},
"required": [ "productId", "productName", "price" ]
}
@webron
Copy link

webron commented Mar 16, 2022

@jdesrosiers thanks for this. Sorry for not jumping into all the references, but I'm curious, can you have multiple such dynamic references pointing to different schemas within the same top-level schema?

Think about it from the OpenAPI spec perspective. The Page schema is supposed to represent a paged result of list call, and say you have (overly simplified definition):

/foo:
  get:
    ...
    response:
      $ref: '#/defs/Page<foo>'
/bar:
  get:
    ...
    response:
      $ref: '#/defs/Page<bar>'

is this something you can represent this way? From your example, I get how to define one of those, but not two or more.

@kevinswiber
Copy link
Author

@webron I'm not qualified to answer on behalf of Jason on this subject matter, but I believe each reference would have to point to two different schemas that looks like:

{
  "$id": "https://example.com/foo-page.schema.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",

  "$ref": "page.schema.json",

  "$defs": {
    "page-content": {
      "$dynamicAnchor": "page-content",
      "$ref": "foo.schema.json"
    }
  }
}
{
  "$id": "https://example.com/bar-page.schema.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",

  "$ref": "page.schema.json",

  "$defs": {
    "page-content": {
      "$dynamicAnchor": "page-content",
      "$ref": "bar.schema.json"
    }
  }
}

I believe these gymnastics are necessary as the dynamic reference has to be resolvable within the same schema. The dynamic anchor is essentially acting as the generic type parameter.

@jdesrosiers
Copy link

Kevin's got the right idea. The two schemas need to be in separate Schema Resources or their dynamic anchors will clash. You can always create a new Schema Resource within a single document using $id. So all of these schemas can be bundled into components in an OpenAPI document.

paths: 
  /foo:
    get:
      ...
      response:
        $ref: 'schemas/foo-page.schema.json'
  /bar:
    get:
      ...
      response:
        $ref: 'schemas/bar-page.schema.json'

components:
  schemas:
    foo-page:
      $id: 'schemas/foo-page.schema.json'
      ...
    bar-page:
      $id: 'schemas/bar-page.schema.json'
      ...
    page:
      $id: 'schemas/page.schema.json'
      ...
    foo:
      $id: 'schemas/foo.schema.json'
      ...
    bar:
      $id: 'schemas/bar.schema.json'
      ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment