How do you define generic-like schemas? #230
-
Suppose I would like to create an equivalent of this generic type but in schema: interface IAPIResponseSuccess<DataType> {
ok: true
data: DataType
}
interface IAPIResponseFailure {
ok: false
errors: string[]
}
type IAPIResponse<DataType> = IAPIResponseSuccess<DataType> | IAPIResponseFailure I presume without generics it would look like this: {
"$id": "api-response"
"title": "APIResponse",
"type": "object",
"required": ["ok"],
"additionalProperties": false,
"oneOf": [
{
"properties": {
"ok": {
"const": true
}
}
},
{
"properties": {
"ok": {
"const": false
},
"errors": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
]
} And the schema at some endpoint like this (skipping all request/response related properties and only focus on body): {
"allOf": [
{
"$ref": "api-response"
},
"data": {
"$ref": "some-other-schema"
}
]
} It doesn't exactly match the generic behaviour, but the top level can be processed by a decorator to figure out if it's a failure or a success interface, so not too much boilerplate. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 14 replies
-
The general schema approach (mix in the specific component of the generic at point-of-use with |
Beta Was this translation helpful? Give feedback.
-
I've actually been considering doing a blog post on this. This is a perfect application for 2020-12's Let's start with the generic definition. interface IAPIResponseSuccess<DataType> {
ok: true
data: DataType
} For this, we want to create the wrapper without knowing what {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://my.server/IAPIResponseSuccess",
"type": "object",
"$defs": {
"DataType": {
"$dynamicAnchor": "DataType",
"not": true
}
},
"properties": {
"ok": { "const": true },
"data": { "$dynamicRef": "#DataType" }
},
"required": [ "ok", "data" ]
} So this schema defines an object with an Now it gets interesting. Let's fill in the data. For simplicity, suppose we want the data to simply be an string: {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://my.server/IAPIResponseSuccessOfString",
"$defs": {
"DataType": {
"$dynamicAnchor": "DataType",
"type": "string"
}
},
"$ref": "https://my.server/IAPIResponseSuccess"
} Then you validate JSON data where you expect The way this works (and @handrews or @jdesrosiers can probably explain this better) is that your "dynamic scope" starts with the root schema ( So now this instance will pass: {
"ok": true,
"data": "some string"
} To get the union with |
Beta Was this translation helpful? Give feedback.
I've actually been considering doing a blog post on this.
This is a perfect application for 2020-12's
$dynamicAnchor
and$dynamicRef
.Let's start with the generic definition.
For this, we want to create the wrapper without knowing what
DataType
is.So this schema …