OpenAPI: Mandatory properties of an Optional Property - node.js

Pretty much what the title says. I have an optional object in the request body. However, if that object is given, it should mandatorily contain a few child properties.
My OpenAPI component config looks like this:
UserDetails:
type: object
properties:
surname:
type: string
givenName:
type: string
dob:
type: string
format: date
gender:
type: string
enum:
- male
- female
- others
partner:
type: object
properties:
name:
type: string
phone:
type: string
maxLength: 10
minLength: 10
pattern: ^[1-9]+[0-9]{9}$
required: [name, phone]
required:
- surname
- givenName
- dob
I am using express-openapi-validator to validate this. Now, I don't understand if this is the problem of the express-openapi-validator package or not, but the required fields (name, phone) of the optional field (partner) is never validated. I can just provide partner: {} and it slips in right through, or even, partner: { name: 'some name', phone: '123' }. Phone number should be validated for the length and the regex.
Am I missing anything in the definition?

There does not seem to be a solution to this, but I am closing this just for peace to my mind.
like what #Helen has replied, this seems to be an issue with the library itself.
In the process of developing my application, I discovered more problems, which make the the library express-openapi-validator and another library swagger-express-middleware I used, even lesser reliable for validating requests.
The other problem that I discovered was that a value is validated with a provided enum only if it is provided as an array:
eg. The following is validated correctly:
UserLiabilities:
type: object
properties:
liabilities:
type: object
properties:
creditCards:
type: array
items:
allOf:
- $ref: '#/components/schemas/Provider'
- type: object
properties:
limit:
type: number
minimum: 0
Here Provider is:
Provider:
type: object
properties:
provider:
type: string
enum: ['ABC', 'DEF', 'GHI', 'Others']
However, if I need provider as a plain string in an object (not in an array like above), it is not validated. And, it allows any arbitrary string:
homeLoan:
allOf:
- $ref: '#/components/schemas/Provider'
- type: object
properties:
amount:
type: number
minimum: 0
This behavior is consistent with atleast two libraries that I have tried and mentioned above. I am not sure I am doing something wrong here, but I have lost enough time trying to debug this and had to finally resolve this in my server itself.

Related

Add multiple object examples for multipart/form-data in Swagger docs

I hava a POST API using multipart/form-data to send data (requestBody including a binary file, string and object data).
I want to add more than one example for object parameter, but I found using enum is not working:
here is my swagger docs:
post:
tags:
- user
summary: xxx
description: xxx
requestBody:
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/User4'
User4:
type: object
properties:
thisIsAString:
type: string
default: 'testStr'
enum:
- testStr
- testStr2
thisIsAObj:
type: object
default: obj1
enum:
- obj1:
oneOfEx: 'bbb'
- obj2:
oneOfEx2: 'aaa'
file:
type: string
format: binary
What I want is make the eample of thisIsAObj parameter can be changed by a Drop-down list.
Or can I separate the binary file and object data like this?
Thank you.

JOI - Made object key not allowed base on the value of another key

I have an object like this:
type A = {
type: 'user' | 'technical',
name: string,
vat?: string
};
I use joi to validate the user request. I would like a validation that if the type is technical then the vat is required() otherwise it's become an not allowed field.
For now, this is my validation where if type is user the field become optional:
type: Joi.valid('user', 'technical').required(),
name: Joi.string().min(2).max(30).required(),
vat: Joi.string().regex(new RegExp(REGEX_CONSTANTS.VAT_NUMBER)).when('type', { is: 'user', then: Joi.optional() }).required()

How do I create a mutation schema on a nested object with GraphQL?

I'm trying to create a graphql mutation to update an object field with an array of other objects. Here is my schema:
"url":
post:
summary: Saves user properties
operationId: saveProperties
consumes:
- application/json
produces:
- application/json
parameters:
- in: body
name: request
description: request
required: true
schema:
"$ref": "#/definitions/SavePropertiesDto"
originalRef: SavePropertiesDto
SavePropertiesDto:
type: object
required:
- saveProperties
properties:
saveProperties:
type: array
items:
"$ref": "#/definitions/SavePropertyDto"
originalRef: SavePropertyDto
SavePropertyDto:
type: object
required:
- agree
- Id
properties:
agree:
type: boolean
Id:
type: string
title: SavePropertyDto
I wanna to query saveProperties and my query looks like this:
mutation someFunc($requestBody: [SavePropertyInput!]) {
saveProperties(requestBody: $requestBody) {
agree
Id
}
I'm getting errors
Field \"saveProperties\" must not have a selection since type \"JSON\" has no subfields
when I execute this request. Also I don't wait for response to this query and wait for only 204 code. As i understood I need to pass SavePropertyInput as a variable to query request. Sorry for visuality, I used yml format for data. Thanks in advance.

use mongoose schema over multiple microservices

my application is split into multiple microservices that are running on heroku dynos (they can't access each others files). Sometimes, there are multiple microservices working with one collection. Therefore, both of the microservices need the according mongoose schema.
However, not both microservices need the full schema. For example, microservice A needs the full schema whereas microservice B only needs a few fields of that schema.
Example schema inside microservice A:
var AccountSchema = mongoose.Schema({
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
phone: { type: String, required: true, unique: true },
forename: { type: String, required: true },
surname: { type: String, required: true },
middleInitals: { type: String, required: false },
failedLoginAttempts: { type: Number, required: true, default: 0 },
lockUntil: { type: Number },
createdAt: { type: Date, default: Date.now }
})
Example Schema inside microservice B:
var AccountSchema = mongoose.Schema({
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
failedLoginAttempts: { type: Number, required: true, default: 0 },
lockUntil: { type: Number },
createdAt: { type: Date, default: Date.now }
})
My approach
I would just go ahead and create a new schema in each microservice, containing only the needed fields. However, I am not sure if there will be any problems when multiple microservices register a new schema to the MongoDB database? For example, both microservices would attempt to create an index for the unique field. Will there be any performance issues?
Does anybody have a different approach I could use? Is this even a valid approach to go with?
Thanks in advance :)
It's a valid approach. you can have 2 schemas pointing to the same collection. i have tested it and it works.
Mongoose is an Object Data Modeling (ODM) library, and you can have 2 objects looking at the same collection /(Table or view in SQL) - no problem with that.
No reason for performance problems, so long you got the right index. no relation to Object Data Modeling.
You might want to add some type key, so you can find only type1/type2 accounts on get request. On find, you can restrict getting the right fields with projection.
I think you should have only 2 keys in the index – email + password. If you have phone index and microservice B: don't include a phone –you will have a violation at the unique index of phone.
But if you really want a unique phone index you can make an override. You can generate temp unique value for phone for mircoservice B (using auto-Generated or duplicate the email value), you will ignore this value on mircoservice B and only find/ update / present phone in microsaervice A, where you have a valid phone. When user change from accountB type to accountA type – you must make sure to replace the wrong phone number with a valid one.
I see no problem in 2 schemas to same collection - you just need to mange your indexes the right way – to avoid collisions, and to insure you can differentiate the different accounts type in the collection.
As far as I can see there is no reason you simply can't use the same schema, maybe use some sort of privilege system and have it only return the right information between these separate micro services. You could have a fetch request tell it from which service its coming from and return a which items using a simple conditional.

How to handle non-required parameters in Swagger to avoid missing positional argument error?

I have a Swagger file for my endpoints, one of my endpoints has several parameters. How do you handle non-required parameters? I'm having a challenge on how to handle it on my Python file if the non-required parameters have empty value.
Here is my Swagger definition:
/surveyData:
get:
operationId: "surveyData.read_surveydata"
summary: Gets the survey data for the client insights tracker.
parameters:
- in: query
name: startDate
type: string
required: true
description: The start date of the survey data.
- in: query
name: endDate
type: string
required: true
description: The end date of the survey data.
- in: query
name: country
type: string
description: The countries from which you would like to filter the survey data.
- in: query
name: market
type: string
and here is my function which is written in Python (using Connexion):
def read_surveydata(startDate, endDate, country, market):
You can add the "Default" tag for example:
parameters:
- name: filtros
in: "query"
required: false
description: Filter to query
type: "string"
default: "bndu"
Or add a default argument
def read_surveydata(startDate, endDate, country, market='store'):

Resources