sylbru
sylbru

Reputation: 1609

Can I compose two JSON Schemas in a third one?

I want to describe the JSON my API will return using JSON Schema, referencing the schemas in my OpenAPI configuration file.

I will need to have a different schema for each API method. Let’s say I support GET /people and GET /people/{id}. I know how to define the schema of a "person" once and reference it in both /people and /people/{id} using $ref.

[EDIT: See a (hopefully) clearer example at the end of the post]

What I don’t get is how to define and reuse the structure of my response, that is:

{
   "success": true,
   "result" : [results]
}

or

{
   "success": false,
   "message": [string]
}

Using anyOf (both for the success/error format check, and for the results, referencing various schemas (people-multi.json, people-single.json), I can define a "root schema" api-response.json, and I can check the general validity of the JSON response, but it doesn’t allow me to check that the /people call returns an array of people and not a single person, for instance.

How can I define an api-method-people.json that would include the general structure of the response (from an external schema of course, to keep it DRY) and inject another schema in result?

EDIT: A more concrete example (hopefully presented in a clearer way)

I have two JSON schemas describing the response format of my two API methods: method-1.json and method-2.json.

I could define them like this (not a schema here, I’m too lazy):

method-1.json :

{
  success: (boolean),
  result: { id: (integer), name: (string) }
}

method-2.json :

{
  success: (boolean),
  result: [ (integer), (integer), ... ]
}

But I don’t want to repeat the structure (first level of the JSON), so I want to extract it in a response-base.json that would be somehow (?) referenced in both method-1.json and method-2.json, instead of defining the success and result properties for every method.

In short, I guess I want some kind of composition or inheritance, as opposed to inclusion (permitted by $ref).

Upvotes: 2

Views: 649

Answers (1)

sylbru
sylbru

Reputation: 1609

So JSON Schema doesn’t allow this kind of composition, at least in a simple way or before draft 2019-09 (thanks @Relequestual!).

However, I managed to make it work in my case. I first separated the two main cases ("result" vs. "error") in two base schemas api-result.json and api-error.json. (If I want to return an error, I just point to the api-error.json schema.)

In the case of a proper API result, I define a schema for a given operation using allOf and $ref to extend the base result schema, and then redefine the result property:

{
  "$schema: "…",
  "$id": "…/api-result-get-people.json",
  "allOf": [{ "$ref": "api-result.json" }],
  "properties": {
    "result": {
       …
    }
  }
}

(Edit: I was previously using just $ref at the top level, but it doesn’t seem to work)

This way I can point to this api-result-get-people.json, and check the general structure (success key with a value of true, and a required result key) as well as the specific form of the result for this "get people" API method.

Upvotes: 1

Related Questions