Express/Swagger pre validation function for end points - node.js

I am working on express js with swagger.
I have created some end points with defining respective controller and function call.
tabs/users:
# binds a127 app logic to a route
x-swagger-router-controller: tabs
get:
description: Returns list of all users
# used as the method name of the controller
operationId: getUsers
parameters:
- name: name
in: query
description: name
required: false
type: string
responses:
"200":
description: Success
schema:
# a pointer to a definition
$ref: "#/definitions/TabResponse"
# responses may fall through to errors
default:
description: Error
schema:
$ref: "#/definitions/ErrorResponse"
Like oprtionId getUsers, I have multiple functions.
Inside controller tabs.js I have functions like
function getUser(){
//business logic
}
Now I have one use case for every call to my end points I need to validate the token which user sent with each request is valid or not.
For this, I need to add validation function call to each controller function.
But I am looking for the central solution so that every call should go through validation function.
Please suggest your thoughts on it.

Related

Nest JS swagger API response body from third party package

I am writing a REST API swagger in Nest JS.
My code snippet looks like this:
#Get()
#ApiOperation({
summary: `Something`,
description: `Something`,
})
#ApiOkResponse({
description: 'The resources were returned successfully',
type: VpcV1,
isArray: true
})
#ApiForbiddenResponse({ description: 'Unauthorized Request' })
list() {
return this.service.list();
}
As you can see the the this.service.list() is returning ab object of type VpcV1.
I have added it as type in the #ApiOkResponse().
But as the VpcV1 is from third party package which I do not have any control, it's not a DTO.
In such a case how can I see the API response object such that when user will see the swagger, they can be able to see the Response Schema properly?

How to send array of strings in query parameters of get request in postman

I have postman mock server with collection, and one of the requests has parameter with type array.
Here is the definition for this query parameter in the API ymal file:
- name: departureAirports
required: false
in: query
explode: true
schema:
type: array
items:
type: string
pattern: ^[A-Z]{3}$
When I send this request from postman with value like this ["123"]
, I got this error:
The query parameter "departureAirports" needs to be of type array, but we found "["123"]"
So, How can I send array of strings in the query parameters in get request ?
You can send the value of parameter departureAirports array like
departureAirports[1]:1
departureAirports[2]:2
departureAirports[3]:3

openapi-generator codegen: Ajv cannot resolve reference to requestBodies from openapi 3.0.0

I created a server stub using my own openapi-3.0.0 template from openapi-generator.
While implementing the API logic for creating resource, I'm referencing a component declared under requestBodies as follows
components:
requestBodies:
SamyojyaUser:
content:
application/json:
schema:
$ref: '#/components/schemas/SamyojyaUser'
application/xml:
schema:
$ref: '#/components/schemas/SamyojyaUser'
description: Samyojya User object that needs to be added to the system
required: true
The API is declared as follows
paths:
/samyojya-user:
post:
operationId: addSamyojyaUser
requestBody:
content:
application/json:
schema:
$ref: '#/components/requestBodies/SamyojyaUser'
x-content-type: application/json
However, while processing the request Ajv complains saying
can't resolve reference #/components/requestBodies/SamyojyaUser from id #
Looking like there seems to be some issue with registering requestBodies component. I see the other components showing up in the Ajv when I debug. I am tempted to use the user component directly at the path object but I want to customize the request body further. Any thoughts on tweaking it further?
References to #/components/requestBodies/... can only be used directly under requestBody and not under schema:
paths:
/samyojya-user:
post:
operationId: addSamyojyaUser
requestBody:
$ref: '#/components/requestBodies/SamyojyaUser'
Also, the indentation in the request body component in wrong - the description and required: true must be on the same level as content.
components:
requestBodies:
SamyojyaUser:
content:
application/json:
schema:
$ref: '#/components/schemas/SamyojyaUser'
application/xml:
schema:
$ref: '#/components/schemas/SamyojyaUser'
# vvvv Note the indentation level
description: Samyojya User object that needs to be added to the system
required: true
Use https://editor.swagger.io (or other validators) to validate your OpenAPI definitions before generating code.

Swagger Updates Breaks API Usage

My API seems to no longer parse properly using swagger-parser and swagger-tools latest versions after we did a full npm update on all our deps last night. However, I cannot track down what is causing these failures to happen since the API follows proper formatting for the 2.0 spec according to the docs.
Some information on the current setup:
swagger-parser: v3.3.0
swagger-tools: v0.9.7
node: v4.2.1
npm: v2.14.7
We are making use of swagger-tools connect middleware to create a stand-alone API app. Our setup for the api looks like this:
var app = require('connect')();
var cors = require('cors');
var swaggerTools = require('swagger-tools');
var swaggerParser = require('swagger-parser');
app.use(cors());
app.initialize = function (done) {
swaggerParser.parse('./api/swagger.yaml', function (err, api) {
if (err) throw err;
swaggerTools.initializeMiddleware(api, function (middleware) {
app.use(middleware.swaggerMetadata());
app.use(middleware.swaggerValidator());
var options = {
controllers: './controllers',
useStubs: process.env.NODE_ENV === 'development' ? true : false
};
app.use(middleware.swaggerRouter(options));
app.use(middleware.swaggerUi());
typeof done === 'function' && done();
});
});
return app;
};
Prior to the updates on the deps everything worked fine like this. However, now when being initialized our API is throwing a bunch of errors when swaggerTools.initializeMiddleware is being called.
A few chunks of our API are as follows:
./api/swagger.yaml
swagger: '2.0'
info:
version: 0.0.1
title: Insert API Title Here
schemes:
- http
basePath: /api/v1
consumes:
- application/json
produces:
- application/json
paths:
/users:
$ref: './api/paths/users.yaml'
/users/{userId}:
$ref: './api/paths/users-userId.yaml'
definitions:
User:
$ref: './api/models/user.yaml'
parameters:
userId:
in: path
name: userId
description: The user id of the user object.
required: true
type: integer
offset:
name: offset
in: query
description: The record to start the return set at.
required: false
type: integer
default: 0
minimum: 0
limit:
name: limit
in: query
description: The quota to limit the return set to.
required: false
type: integer
default: 10
orderBy:
name: orderBy
in: query
description: The field to order by.
required: false
type: string
sort:
name: sort
in: query
description: The sort order of the return set.
required: false
type: string
enum: [desc, asc]
default: asc
./api/paths/users.yaml
x-swagger-router-controller: Users
get:
tags:
- users
summary: Gets a list of all users.
description: ''
operationId: getUsers
parameters:
- $ref: '#/parameters/offset'
- $ref: '#/parameters/limit'
- $ref: '#/parameters/orderBy'
- $ref: '#/parameters/sort'
responses:
200:
description: OK
schema:
$ref: '#/definitions/UserCollection'
401:
description: Not Authorized
The errors we are seeing are things like this now:
#/paths/~1users/get/parameters/1/name: Parameter already defined: undefined
#/paths/~1users/get/parameters/2/name: Parameter already defined: undefined
#/paths/~1users/get/parameters/3/name: Parameter already defined: undefined
#/paths/~1users~1{userId}/get: API requires path parameter but it is not defined: userId
#/paths/~1users~1{userId}/put/parameters/1/name: Parameter already defined: undefined
#/paths/~1users~1{userId}/put: API requires path parameter but it is not defined: userId
#/paths/~1users~1{userId}/delete: API requires path parameter but it is not defined: userId
#/paths/~1users~1{userId}~1profile/get: API requires path parameter but it is not defined: userId
#/paths/~1users~1{userId}~1profile/post/parameters/1/name: Parameter already defined: undefined
#/paths/~1users~1{userId}~1profile/post: API requires path parameter but it is not defined: userId
I'm not sure where to go from here since I have tried everything to keep the API layout the same (broken into multiple files) vs. having to resort to putting it all into a single file. Our API is rather large and it is much easier to maintain broken into parts like this which used to work fine without issue.
Is there something I am missing, a step that needs to be done differently with the updates to swagger-parser and swagger-tools? Any help is appreciated.
It seems the jump between v2 to v3 of Swagger-Parser has changed the functionality of .parse() to no longer resolve references. Because of this it was causing portions of the API to not validate properly. Switching to .validate() instead of .parse() has fixed this issue. A handful of adjustments had to be made to the .yaml files to make it work with the new 2.0 standards but all is working again.

Validation errors in custom instance or static methods in a Mongoose model

I have a basic Mongoose model with a Meeting and Participants array:
var MeetingSchema = new Schema({
description: {
type: String
},
maxNumberOfParticipants: {
type: Number
},
participants: [ {
type: Schema.ObjectId,
ref: 'User'
} ]
});
Let's say I want to validate that the number of participants added doesn't exceed the maxNumberOfParticipants for that meeting.
I've thought through a few options:
Custom Validator - which I can't do because I have to validate one attribute (participants length) against another (maxNumberOfParticipants).
Middleware - i.e., pre-save. I can't do this either because my addition of participants occurs via a findOneAndUpdate (and these don't get called unless I use save).
Add validation as part of my addParticipants method. This seems reasonable, but I'm not sure how to pass back a validation error from the model.
Note that I don't want to implement the validation in the controller (express, MEAN.js stack) because I'd like to keep all logic and validations on the model.
Here is my addParticipants method:
MeetingSchema.methods.addParticipant = function addParticipant(params, callback) {
var Meeting = mongoose.model('Meeting');
if (this.participants.length == this.maxNumberOfParticipants) {
// since we already have the max length then don't add one more
return ????
}
return Meeting.findOneAndUpdate({ _id: this.id },
{ $addToSet: { participants: params.id } },
{new: true})
.populate('participants', 'displayName')
.exec(callback);
};
Not sure how to return a validation error in this case or even if this pattern is a recommended approach.
I wouldn't think that's it's common practice for this to be done at the mongoose schema level. Typically you will have something in between the function getting called and the database layer (your schema) that performs some kind of validation (such as checking max count). You would want your database layer to be in charge of just doing simple/basic data manipulation that way you don't have to worry about any extra dependencies when/if anything else calls it. This may mean you'd need to go with route 1 that you suggested, yes you would need to perform a database request to find out what your current number of participants but I think it the long run it will help you :)

Resources