how to define type Date in jsonSchemaType? - jsonschema

I have an interface (using typescript) that I am building a Json schema for.
export interface IMyDate{
FromDateUtc: Date,
ToDateUtc: Date
}
this is how I defined the schema:
JSONSchemaType<IMyDate> = {
type: "object",
properties: {
FromDateUtc: {
type: "string",
format: "date-time",
},
ToDateUtc: {
type: "string",
format: "date-time",
},
required: [
"FromDateUtc",
"ToDateUtc",
],
additionalProperties: false,
};
I am getting this error:
The types of 'properties.FromDateUtc' are incompatible between these types.
Type '{ type: "string"; format: string; }' is not assignable to type '{ $ref: string; } | (UncheckedJSONSchemaType<Date, false> & { const?: Date | undefined; enum?: readonly Date[] | undefined; default?: Date | undefined; })'.
Any ideas why and how I can fix this?

In json-schema-to-typescript, We can use the tsType property in our JSON schema to override the type. tsType Overrides the type that's generated from the schema. Helpful in forcing a type to any or when using non-standard JSON schema extensions.
For Example, the JSON schema given below generates a type birthday with date as it's type.
const birthday = {
name: `birthday `,
type: `string`,
tsType: `Date`,
format: `date-time`,
}
export type birthday = Date;

date-time:
A string instance is valid against this attribute if it is a valid representation according to the "date-time' ABNF rule
From json-schema-validation spec
So the string might be valid against this format but it is still a string.
Try this:
export interface IMyDate {
FromDateUtc: string;
ToDateUtc: string;
}
According to JSON Schema Online Validator, the following is a valid JSON Schema:
{
"title": "IMyDate",
"type": "object",
"properties": {
"FromDateUtc": {
"type": "string",
"format": "date-time"
},
"ToDateUtc": {
"type": "string",
"format": "date-time"
},
"required": [
"FromDateUtc",
"ToDateUtc"
],
"additionalProperties": false
}
}
You could now use json-schema-to-typescript
to extract the interface. The documentation of this tool states that format is "not expressible in TypeScript" and therefore the generated interface is the same as given above (with attributes of type string).
Note that there are several ways to convert a Date into a properly fomatted string.

Related

Loopback 4 auto generated model with required id failing validation

I'm using an automated script that runs an auto-generation model using lb4 cli.
Looks like validation expects id to be provided, but swagger missing it in its schema. Why I can't see the id property in swagger?
PLEASE NOTE! I don't want to modify manually my models
lb4 model activity --dataSource DS --table activity
Created model:
export class Activity extends Entity {
#property({
type: 'string',
required: true,
id: 1,
postgresql: {
columnName: 'id',
dataType: 'uuid',
dataLength: null,
dataPrecision: null,
dataScale: null,
nullable: 'NO',
},
})
id: string;
...
}
When I run the swagger tool and try to POST new activity, it missing the id field and returns the following error:
{
"error": {
"statusCode": 422,
"name": "ValidationError",
"message": "The `Activity` instance is not valid. Details: `id` can't be blank (value: undefined).",
"details": {
"context": "Activity",
"codes": {
"id": [
"presence"
]
},
"messages": {
"id": [
"can't be blank"
]
}
}
}
}
If I add a property id manually, then it throws a validation error:
{
"error": {
"statusCode": 422,
"name": "UnprocessableEntityError",
"message": "The request body is invalid. See error object `details` property for more info.",
"code": "VALIDATION_FAILED",
"details": [
{
"path": "",
"code": "additionalProperties",
"message": "must NOT have additional properties",
"info": {
"additionalProperty": "id"
}
}
]
}
}
Change your #model() by #model({settings: {strict: false}}) and add this line [prop: string]: any; into your model
#model({settings: {strict: false}})
[prop: string]: any;

Finding record which doesn't contain some value in array fields

I am using sequelize + typescript over node (with postgresql db) and I have the following model:
id: number,
someField: string,
arr1: number[],
arr2: number[]
and I'm trying to find all records in which arr1 and arr2 don't contain a certain value.
As far as I've seen my only option in one query is a mix between Op.not and Op.contains,
so I've tried the following queries:
/// Number 1
where: {
arr1: {
[Op.not] : {[Op.contains]: [someValue]}
},
arr2: {
[Op.not] : {[Op.contains]: [soemValue]}
}
},
/// Number 2
where: {
[Op.not]: [
{arr1: {[Op.contains]: [someValue]}},
{arr2: {[Op.contains]: [someValue]}}
]
},
Now, number 1 does compile in typescript but when trying to run it the following error returns:
{
"errorId": "db.failure",
"message": "Database error occurred",
"innerError":
{
"name": "SequelizeValidationError",
"errors":
[
{
"message": "{} is not a valid array",
"type": "Validation error",
"path": "arr1",
"value": {},
"origin": "FUNCTION",
"instance": null,
"validatorKey": "ARRAY validator",
"validatorName": null,
"validatorArgs": []
}
]
}
}
So I tried number 2, which didn't compile at all with the following TS error:
Type '{ [Op.not]: ({ arr1: { [Op.contains]: [number]; }; } | { arr2: { [Op.contains]: [number]; }; })[]; }' is not assignable to type 'WhereOptions<any>'.
Types of property '[Op.not]' are incompatible.
Type '({ arr1: { [Op.contains]: [number]; }; } | { arr2: { [Op.contains]: [number]; }; })[]' is not assignable to type 'undefined'
So the question is what am I doing wrong, or in other words, how can I make that query without querying all records and filter using code
Thanks!
You have to use notIn and not contain maybe then it will work:
Official Docs: https://sequelize.org/master/manual/model-querying-basics.html
where: {
arr1: {
[Op.notIn]: someValueArray
},
arr2: {
[Op.notIn]: someValueArray
}
},
Apparently the second option is the correct one, but what was incorrect was the types of sequelize, #ts-ignore fixes the problem

JSON Schema: Can I use "if" deeper than root of schema?

I want to validate objects like this
{
type: "user",
data: {id: 1},
}
and
{
type: "account",
data: {uuid: "xxxx"},
}
I thought I can write schema like this
{
type: "object",
properties: {
type: {enum: ["user", "account"]},
data: {
"if": {properties: {type: {const: "user"}}},
"then": {
type: "object",
properties: {
id: {type: "number"}
}
},
"else": {
type: "object",
properties: {
uuid: {type: "string"}
}
},
}
}
}
but it looks like I can't refer to root type field from context of data field. So I have two questions. Can I use if deeper than root? If I can then how to refer to parent or root object from nested object? I'm using node ajv for validation.
You're correct, you cannot apply validation to a different part of your data than where your subschems is being applied. Let me explain a little.
The first thing that happens when processing a JSON Schema is the Schema as a whole is "applied" to the instance as a whole.
properties is an applicator keyword, in that it doesn't assert any validation rules by itself. The VALUES of a properties object are subschemas (which are Schemas in their own right) which are APPLIED to the instance location value when the associated KEY matches.
To give you an exanple, in your Schema, the subschema at properties > type is applied to instance location type, which means the VALUE of the object key type. If type didn't exist in your data, the subschema in your Schema wouldn't do anything (it wouldn't be applied anywhere).
This is broadly the processing model of a Schema against an instance. Hopefully this explains why you can't work in the way you're expecting. However it's still possible to achive what you want.
then and else are conditional applicator keywords, and so need to be applied following the same model.
What you need to do is use if, then, else at the top level, but have deep / nested application of the validation you want to do.
Here's a demo with a new Schema and instance
https://jsonschema.dev/s/sejHF
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"properties": {
"type": {
"enum": [
"user",
"account"
]
},
"data": {}
},
"if": {
"properties": {
"type": {
"const": "user"
}
}
},
"then": {
"type": "object",
"properties": {
"data": {
"properties": {
"id": {
"type": "number"
}
}
}
}
},
"else": {
"type": "object",
"properties": {
"data": {
"properties": {
"uuid": {
"type": "string"
}
}
}
}
}
}
If you also want to make sure that id is present when type is user, then you also need to add required: ['id'] in the then subschema. (You'll need to do similar in the else clause if you want to check for uuid too.

How to define data type for Expand API in RAML

I am designing an API operation and am going to use the expand standard.
Here is an example of my first API response....
{
"id": "000000001",
"createdDateTime": "2017-12-19T16:39:57-08:00",
"lastUpdatedDateTime": "2017-12-19T16:45:57-08:00",
"holdingDetails": {
"status": "SUCCESSFUL",
"instrument": "/api/v1//instruments/123456789"
}
}
Here is an example of my second API response....
{
"id": "000000001",
"createdDateTime": "2017-12-19T16:39:57-08:00",
"lastUpdatedDateTime": "2017-12-19T16:45:57-08:00",
"holdingDetails": {
"status": "SUCCESSFUL",
"instrument": {
"instrumentId":"123456789",
"nickName":"My NickName",
"type": "BLAH"
}
}
}
In my raml I would like to define a type for this i'm not sure what is would look like...
#%RAML 1.0 DataType
type: object
properties:
id?:
type: string
createdDateTime?:
type: datetime
lastUpdatedDateTime?:
type: datetime
What goes next? i.e. How do I say it can be either listed below
instrument?:
type: string
description: A link to the instrument
instrument?:
type: !include instrument.raml
You can use an union
e.g.:
instrument?:
type: string | InstrumentType
and of course also define InstrumentType, for example with something like this:
InstrumentType:
properties:
instrumentId:
nickName:
type:

Is there a way to set property value format requirements based on a condition of the property name?

I have a simple JSON schema:
{
"properties": {
"name": {
"type": "string"
}
},
"type": "object"
}
It requires that name property is a string. This schema does not restrict additional properties, e.g.
{
name: 'foo',
url: 'http://foo'/
}
The latter is a valid input.
Is there a way to set a property value format requirement based on a conditional property name match?, e.g. any property that contains url string in it must correspond to the following schema:
{
"type": "string",
"format": "url"
}
Therefore, an input:
{
name: 'foo',
location_url: 'not-a-valid-url'
}
would cause an error because location_url does not contain a valid URL?
I'd imagine, a schema for something like this would look like:
{
"properties": {
"name": {
"type": "string"
}
},
"matchProperties": {
"/url/i": {
"type": "string",
"format": "url"
}
}
"type": "object"
}
where matchProperties is a keyword I made up.