Integration strategy with ajv library for parsing "Date" fields
See original GitHub issueThis issue is more about the use of the ajv library rather than typescript-json-schema, but I figured it would be appropriate to ask here, due to the specific interaction with typescript-json-schema.
For the following interface, typescript-json-schema creates a perfect schema:
export interface Breakfast {
location: string
scheduled: Date;
}
{
"type": "object",
"properties": {
"location": {
"type": "string"
},
"scheduled": {
"description": "Enables basic storage and retrieval of dates and times.",
"type": "string",
"format": "date-time"
}
},
"required": [
"location",
"scheduled"
],
"$schema": "http://json-schema.org/draft-04/schema#"
}
Notice that the field “scheduled” of type “Date” gets serialized as a “string” (with format “date-time”).
This works perfectly when we JSON.stringify a Breakfast object. But when we try to JSON.parse it back in, it will pass schema validation via ajv, but we will actually end up with our “scheduled” field set as a string rather than a Date.
Does anyone have any suggestions for how to end up with with a genuine “Date” object for all Date fields?
ajv is able to apply modifications to objects as it parses them. Here is a discussion titled “Custom coerce types/functions” where there are some leads on how this could work: https://github.com/epoberezkin/ajv/issues/141. I tried the approach described there but was unable to get it working. I think the way to go is to have typescript-json-schema write a custom keyword for all “Date” fields, and then figure out how to have ajv recognize this keyword and convert the strings to Dates.
But I might be missing something very obvious. I would be very happy to hear how others are dealing with this issue
Issue Analytics
- State:
- Created 7 years ago
- Reactions:7
- Comments:5 (2 by maintainers)
Top GitHub Comments
Here is a system I found that works pretty well. It uses a JSON schema custom keyword.
The following example will use the “Date” type, but this system can be used for any other custom type or type from a library.
1. Create type aliases
For each non-primitive type you want to use, create a type alias in the following way:
CustomTypes.ts
(We use TypeScript
interface
instead oftype
, since “typescript-json-schema” won’t work properly withtype
)2. Use the type alias in your interface
3. Generate your JSON Schema
Make sure you are using a recent version of “typescript-json-schema”. I am using version 0.20.0.
Use “typescript-json-schema” as usual to generate your JSON schema, but use the
validationKeywords
option to add the “xreviver” keyword (note that it was used above):If instead of the API, you are using the “typescript-json-schema” command line program, then use the
--validationKeywords
option (giving it the value “xreviver”)If you are curious, scroll down to the end to see the resulting JSON schema.
4. Convert your data structure to JSON
Nothing special needs to be done here:
Note: Our system assumes that your custom types all have a
toJSON()
method that will output a string. This holds for the regularDate
object, but make sure it also holds for other types you plan to use.5. Create your “reviver” functions
Note that the key in the reviver dictionary (“JsonDate”) matches the string we wrote above in CustomTypes.ts (
@xreviver JsonDate
).If you have additional types, then use different “@xreviver” values, and add a parser for each one to the “revivers” dictionary. Each custom type you use should have a unique “@xreviver” value.
Note that as you can see in the “JsonDate” parser above, your parser functions should “throw new Error(…)” if there is a parse error.
6. Get ajv ready
Make sure you are using a recent version of ajv, since older versions will not work correctly for us. I am using version 5.5.1.
Note that there is currently an annoying incompatibility between “typescript-json-schema” and versions of “ajv” >= 5.0.0. So make sure to follow the instructions in these ajv release notes (The section: “If you need to continue using draft-04 schemas”)
Once you have your “ajv” object we need to tell it about our custom keyword:
The above code should be used exactly as is. (But just in case you need it, here is the reference for ajv custom validation: https://github.com/epoberezkin/ajv/blob/master/CUSTOM.md#define-keyword-with-validation-function)
7. Validate and “Revive” your JSON
Now use ajv normally:
The End and Good Luck!
Bonus
If you are curious, here is the JSON Schema that is generated. Notice that the “scheduled” field has a ref to “JsonDate”, which has type string, and our custom “xreviver” keyword attached:
For anyone ending up here, I’ve updated @benny-medflyt’s excellent answer for changes to ajv and added unit tests. This version supports
Date
andBuffer
encoding and decoding, including a concrete usage example withtypescript-json-schema
.Check out the source and tests for example usage.