Swagger - No data sent in body (swagger-jsdocs, swagger-ui-express) - node.js

for an nodejs-project I am using swagger-ui-express and swagger-jsdocs for the Swagger API. When I try to call an POST-Endpoint of my application with Swagger then there is no data sent with. What could be the problem? My whole relevant code is following:
const swaggerOptionsJSDocs = {
swaggerDefinition: {
openapi: '3.0.1', //tried with 3.0.0 as well
info: {
title: "Testproject",
description: "Middleware for bla bla ",
contact: {
name: "John Doo"
}
}
},
apis: ["index.js"]
};
const swaggerDocs = swaggerJsDoc(swaggerOptionsJSDocs);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocs));
**
* #swagger
* /user/upload:
* post:
* description: Receives a zipped and base64 encoded user
* consumes:
* - application/json
* parameters:
* - in: body
* name: fullRequest // name here doesn't matter
* description: ...
* schema:
* type: object
* required:
* - user
* properties:
* user:
* type: string
* jobId:
* type: string
* responseUrl:
* type: string
* inaugurationDate:
* type: string
* responses:
* '201':
* description: user received and uploaded successfully
* '400':
* description: user data is missing or invalid
* '500':
* description: Internal server error
*
*
*
*/
app.post('/user/upload', function(req, res) {
....
}
Swagger is performing get request but when it comes to send data, the d-flag is empty. Does anyhone have an idea?
Best regards

Parameters 'in:body' is not valid. In Open API 3, you have to pass the requestBody as a separate chunk.
Also, you have to use #openapi to use Open API.
Refer here, to see examples of requestBody object.
**
* #openapi
...
* requestBody:
* description: ...
* schema:
* type: object
* required:
* - user
* properties:
* user:
* type: string
* jobId:
* type: string
* responseUrl:
* type: string
* inaugurationDate:
* type: string
....

Related

Why the values of the parameter are not consoled at my function?

What im trying to do is to receive two parameters in req.params.
swagger
/**
* #swagger
* /clients/removeClients/{user_id}/{client_id}:
* put:
* summary: removing clients
* tags: [Clients]
* parameters:
* - name: user id
* description: User id
* type: string
* in: path
* required: true
* - name: client id
* description: client id
* type: string
* in: path
* required: true
* responses:
* 200:
* description: done
* 500:
* description: Some server error
*/
router.put("/removeTrustee/:user_id/:client_id", removeClient);
controller
exports.removeTrustee = asyncHandler(async (req, res, next) =>{
console.log(req.params)
res.status(200).json({
success: true,
data: {}
})
})
When I console.log the params in my terminal is showed like this:
{ user_id: '{user_id}', client_id: '{client_id}' }
and when I access one of them: console.log(req.params.user_id)
it will console just user_id
How can I receive the values that I put in the parameters?

How can I make an request params to mongo db from node js and swagger?

What I have tried is to get all the data by createdBy param. createdBy has a user phone number value.
controller
exports.getLocation = asyncHandler(async (req, res, next) => {
const createdBy = req.params.createdBy
console.log('created', createdBy) // its empty
const getLocation = await Location.find( {createdBy: createdBy} )
res.status(200).json({
success: true,
msg: "Getting all the locations of the user",
data: getLocation
})
})
routes
/**
* #swagger
* /location/getLocation/:createdBy:
* get:
* summary: getting the location of the user by phone number
* tags: [Location]
* requestBody:
* required: false
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Location'
*
* responses:
* 200:
* description: the location has been recivied
* 500:
* description: Some server error
*/
router.get("/getLocation/:createdBy", getLocation)
The idea is to put the param in a request body, to get all the data of the createdBy key in the database. The get method doesn't accept a request body.
How can I put a param so I can get the data from the database?
To let you know, I'm using the swagger request body to execute the API, and this API is for a react-native application.
You have to correct your swagger annotation for createdBy property,
use {createdBy} instead of :createdBy in URL
use parameters property of swagger and in that declare the createdBy property with path type
requestBody is not required because you are using GET request type
/**
* #swagger
* /location/getLocation/{createdBy}:
* get:
* summary: getting the location of the user by phone number
* tags: [Location]
* parameters:
* - name: createdBy
* description: Created By
* in: path
* required: true
* responses:
* 200:
* description: the location has been recivied
* 500:
* description: Some server error
*/
router.get("/getLocation/:createdBy", getLocation);

NodeJs Iterate over req.files from swagger array having format type as binary

I am using swagger with Node and now stuck at multiple file upload part as i am able to get my files on server using swagger-fileupload-docs document page.
middleware is multer and i use below settings in my server.ts file or in the main file from where execution starts
import 'reflect-metadata';
import bodyParser from 'body-parser';
import cors from 'cors';
import express from 'express';
import bunyanMiddleware from 'express-bunyan-logger';
import fg from 'fast-glob';
import helmet from 'helmet';
import { createConnection } from 'typeorm';
import config from './config';
import ErrorHandler from './middlewares/errorHandler';
import logger from './utils/logger';
async function start(): Promise<void> {
logger.info('Starting server...');
await createConnection();
const app = express();
// Register middlewares
const appUrl = new URL(config.app.url);
app.use(cors({
origin: config.env === 'production' ? appUrl.origin : '*',
}));
app.use(helmet());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(bunyanMiddleware({
logger,
parseUA: false,
excludes: ['response-hrtime', 'req-headers', 'res-headers'],
format: ':incoming :method :url :status-code',
}));
// Register routes
const routes = await fg('./routes/*.(ts|js)', { cwd: __dirname });
for (const routePath of routes) {
const { default: router } = await import(routePath);
if (typeof (router) === 'function') app.use(config.server.basePath, router);
}
// Error handler must come last...
app.use(ErrorHandler);
// Kick it off!
app.listen(config.server.port, async () => {
logger.info({ port: config.server.port }, 'Hey! I\'m listening...');
});
}
start();
and now in the ROUTE file for product.ts code is given below using multer
import Joi from '#hapi/joi';
import express, { Router } from 'express';
import { ProductStatus, Role, } from '../models/enums';
import { authorize } from '../middlewares/authorize';
import { wrapAsync } from '../utils/asyncHandler';
import { Request, isUserReq } from './interfaces';
import { createBrand, deleteBrand, getAllBrands, updateBrand } from '../services/brand';
import multer from 'multer';
import { createProduct, deleteProduct, getAllProducts, updateProduct } from '../services/product';
const upload = multer({ dest: '/tmp/' })
const router = Router();
router.post('/products', authorize(), upload.array('imagesPath'), wrapAsync(async (req: Request, res: express.Response) => {
var files = req.files;
const { name, price, status, categoryId, vendorId } = await Joi
.object({
name: Joi.string().trim().min(3).max(50).required().label('Name'),
price: Joi.number().min(1).max(10000).required().label('Price'),
status: Joi.string().valid(ProductStatus.IN_STOCK, ProductStatus.OUT_OF_STOCK, ProductStatus.RUNNING_LOW).required().label('Status'),
categoryId: Joi.string().trim().uuid().required().label('Category ID'),
vendorId: Joi.string().trim().uuid().required().label('Vendor ID'),
})
.validateAsync(req.body);
But i am not able to iterate over req.files as it is giving below error
and my swagger doc are as follow.
/**
* #swagger
* /products:
* post:
* tags:
* - Product
* summary: Create a product
* consumes:
* - multipart/form-data
* security:
* - JWT: []
* requestBody:
* required: true
* content:
* multipart/form-data:
* schema:
* type: object
* properties:
* name:
* description: Product name
* type: string
* price:
* description: Product price
* type: string
* status:
* description: Product status
* type: string
* enum: [OUT_OF_STOCK, IN_STOCK, RUNNING_LOW]
* imagesPath:
* description: Product logo
* type: array
* items:
* type: string
* format: binary
* categoryId:
* type: string
* vendorId:
* type: string
* produces:
* - multipart/form-data
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Product'
* example:
* id: 2efa52e2-e9fd-4bd0-88bc-0132b2e837d9
* name: Product 1
* price: 25
* status: IN_STOCK
* imagesPath: ['https://${config.s3.Images}.s3.amazonaws.com/${req.file.originalname}']
* categoryId: 2efa52e2-e9fd-4bd0-88bc-0132b2e837d9
* vendorId: 4efa52e5-e6fd-4bd0-68bc-0132b2e83ww49
* 401:
* $ref: '#/components/responses/UnauthorizedError'
* 409:
* $ref: '#/components/responses/ConflictError'
* 500:
* $ref: '#/components/responses/InternalError'
*/
OPENAPI POST DEFINATIONS that i am using for my api and using format as binary.
use typeof req.files to check if its array
if its not array then you can use any of these to convert it to array and then use forEach:
Array(req.files).forEach(f => console.log(f))
Array.from(req.files).forEach(f => console.log(f))
[].forEach.call(req.files, console.log)

Multer and Joi compatibility

I am trying to do uploading of files in expressJS using multer. I am using postman and set the header to multipart/form-data I need to validate the request body first using Joi but when I tried to place the Joi validation middleware first, it doesn't work. And when I placed the multer middleware first, the upload worked even if the request body didn't pass the validations of the Joi middleware. How can I fix this?
I had a similar problem and after some search and try and error, this solved it to me. The thing to keep in mind is to put the Joi validator after multer upload and change the validation scheme a bit.
I've condensed the code into one file to make it a little clearer, so it's missing its dependencies, I hope you get the idea:
const createFile = {
body: {
name: Joi.string().required(),
description: Joi.string(),
protected: Joi.boolean().required()
},
file: Joi.string().required()
};
router
.route('/files')
.post(upload.single('file'), validate(createFile), (req, res, next) => {
//controller logic
}
);
/**
* #swagger
* path:
* /files:
* post:
* summary: Upload a file and its metadata to the server.
* description: Create a file.
* consumes:
* - multipart/form-data
* tags: [Files]
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* multipart/form-data:
* schema:
* type: object
* required:
* - name
* - protected
* - file
* properties:
* name:
* type: string
* description:
* type: string
* protected:
* type: boolean
* default: false
* file:
* type: string
* format: binary
* responses:
* "201":
* description: Created
* content:
* application/json:
* schema:
* type: object
* properties:
* success:
* type: boolean
* message:
* type: string
* data:
* type: object
* $ref: '#/components/schemas/File'
* "401":
* $ref: '#/components/responses/Unauthorized'
* "403":
* $ref: '#/components/responses/Forbidden'
*/

In swagger-api code i am getting paths{},description{} and response{} etc as empty

I am using Express and Node. I am following the below link to get my swagger documentation for the APIs: http://mherman.org/blog/2016/05/26/swagger-and-nodejs/#.We8gq2iCzDc. I have the same project structure. I am sure there is something missing yet I am unable to find the mistake. Any help is appreciated.
This is my app.js:
import express from 'express';
import path from 'path';
var routes = require('./routes/routes');
var swaggerJSDoc = require('swagger-jsdoc');
var bodyParser = require('body-parser');
var swaggerDefinition = {
info: {
title: 'Node Swagger API',
version: '1.0.0',
description: 'Demonstrating how to describe a RESTful API with Swagger',
},
host: 'localhost:3000',
basePath: '/',
};
var options = {
swaggerDefinition: swaggerDefinition,
apis: ['./routes/routes.js']
};
var swaggerSpec = swaggerJSDoc(options);
class Server {
constructor() {
this.app = express();
}
configureApp() {
this.app.set('port', (process.env.PORT || 3000));
this.app.use(bodyParser.json());
this.app.use(bodyParser.urlencoded({ extended: true }));
this.app.use(bodyParser());
this.app.use(express.static(path.join(__dirname, 'public')));
this.app.use('/', routes);
}
configureCORS() {
this.app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST, PUT, DELETE, GET');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With');
res.setHeader('Cache-Control', 'no-cache');
next();
});
}
configureRoutes() {
this.app.post('/api/doctorPost', doctor.post);
this.app.put('/api/doctorEdit/:id', doctor.put);
this.app.delete('/api/doctorDelete/:id', doctor.delete);*/
this.app.get('/swagger.json', function(req, res) {
res.setHeader('Content-Type', 'application/json');
res.send(swaggerSpec);
});
}
listen(port) {
this.app.listen(port, () => {
console.log(`Server started: http://localhost:${port}/`);
});
}
run() {
this.configureApp();
this.configureCORS()
this.configureRoutes();
this.listen(this.app.get('port'));
}
}
export default Server;
This is my routes.js:
var express = require('express');
var router = express.Router();
var api = require('../doctor.api');
/**
* #swagger
* definition:
* doctor:
* type: object
* properties:
* id:
* type: integer
* name:
* type: string
* picUrl:
* type: string
* briefDescription:
* type: string
* speciality:
* type: string
* exprience:
* type: string
* description:
* type: string
* contact:
* type: string
* email:
* type: string
* phoneno:
* type: integer
* status:
* type: string
* description: doctor Status
* enum:
* - available
* - pending
* - not exists
* waitingTime:
* type: integer
* format: int64
* rating:
* type: integer
* format: int64
* videoUrl:
* type: string
* appearUrl:
* type: string
* collapseId:
* type: string
* thumbnailUrl:
* type: string
* lastUpdateTime:
* type: integer
* format: int64
*/
/**
* #swagger
* /api/doctorGet:
* get:
* tags:
* - doctor
* description: Returns all doctor
* produces:
* - application/json
* responses:
* 200:
* description: An array of doctor
* schema:
* $ref: '#/definitions/doctor'
*/
router.get('/api/doctorGet', api.getDoctors);
/**
* #swagger
* /api/doctorPost:
* post:
* tags:
* - doctor
* summary: Add a new doctor to the list
* description: New doctor added
* operationId: addDoctor
* consumes:
* - application/json
* - application/xml
* produces:
* - application/xml
* - application/json
* parameters:
* - in: body
* name: body
* description: Doctor object that needs to be added to the list
* required: true
* schema:
* $ref: '#/definitions/doctor'
* responses:
* '405':
* description: Invalid input
* security:
* - doctor_auth:
* - 'write:doctor'
* - 'read:doctor'
*/
router.post('/api/doctorPost', api.createDoctor);
/**
* #swagger
* /api/doctorEdit/{id}:
* put:
* tags:
* - doctor
* description: Updates a single doctor
* produces:
* - application/json
* parameters:
* - name: id
* description: doctor's id
* in: path
* required: true
* type: integer
* - name: puppy
* description: doctor object
* in: body
* required: true
* schema:
* $ref: '#/definitions/doctor'
* responses:
* 200:
* description: Successfully updated
*/
router.put('/api/doctorEdit/:id', api.updateDoctor);
/**
* #swagger
* /api/doctorDelete/{id}:
* delete:
* tags:
* - doctor
* description: Deletes a single doctor
* produces:
* - application/json
* parameters:
* - name: id
* description: doctor's id
* in: path
* required: true
* type: integer
* responses:
* 200:
* description: Successfully deleted
*/
router.delete('/api/doctorDelete/:id', api.deleteDoctor);
module.exports = router;
My output is:
{"info":{"title":"Node Swagger
API","version":"1.0.0","description":"Demonstrating how to describe a
RESTful API with Swagger"},"host":"localhost:3000","basePath":"/","swagger":"2.0","paths":
{},"definitions":{},"responses":{},"parameters":{},"securityDefinitions":{}}
Expected output would be something like this:
{"info":{"title":"Node Swagger
API","version":"1.0.0","description":"Demonstrating how to desribe a RESTful API with Swagger"},"host":"localhost:3000","basePath":"/","swagger":"2.0","paths":{"/api/puppies":{"get":{"tags":["Puppies"],"description":"Returns all puppies","produces":["application/json"],"responses":{"200":{"description":"An array of puppies","schema":{"$ref":"#/definitions/Puppy"}}}},"post":{"tags":["Puppies"],"description":"Creates a new puppy","produces":["application/json"],"parameters":[{"name":"puppy","description":"Puppy object","in":"body","required":true,"schema":{"$ref":"#/definitions/Puppy"}}],"responses":{"200":{"description":"Successfully created"}}}},"/api/puppies/{id}":{"get":{"tags":["Puppies"],"description":"Returns a single puppy","produces":["application/json"],"parameters":[{"name":"id","description":"Puppy's id","in":"path","required":true,"type":"integer"}],"responses":{"200":{"description":"A single puppy","schema":{"$ref":"#/definitions/Puppy"}}}},"put":{"tags":["Puppies"],"description":"Updates a single puppy","produces":["application/json"],"parameters":[{"name":"id","description":"Puppy's id","in":"path","required":true,"type":"integer"},{"name":"puppy","description":"Puppy object","in":"body","required":true,"schema":{"$ref":"#/definitions/Puppy"}}],"responses":{"200":{"description":"Successfully updated"}}},"delete":{"tags":["Puppies"],"description":"Deletes a single puppy","produces":["application/json"],"parameters":[{"name":"id","description":"Puppy's id","in":"path","required":true,"type":"integer"}],"responses":{"200":{"description":"Successfully deleted"}}}}},"definitions":{"Puppy":{"properties":{"name":{"type":"string"},"breed":{"type":"string"},"age":{"type":"integer"},"sex":{"type":"string"}}}},"responses":{},"parameters":{},"securityDefinitions":{},"tags":[]}

Resources