Exporting Swagger/OpenAPI to Postman collection with examples - swagger

I have a large codebase in NestJS for which I have used Swagger to document the API routes ("#nestjs/swagger": "^3.1.0"). However, the Swagger UI seems to be underpowered for such large projects and I would like to migrate to Postman. Here is what happens:
Take for example this model structure:
export class IApiGenericRequest {
#ApiModelProperty({
example: null,
default: 0
})
appVersionCode: number;
#ApiModelProperty({
example: false,
default: false
})
testerMode: boolean;
#ApiModelProperty({
example: 1,
default: 1
})
appId: number;
}
export class IApiGenericRequestUserId extends IApiGenericRequest {
#ApiModelProperty({
example: 1,
default: 1
})
userId: number;
}
class IApiEventsV2UserDetails extends IApiGenericRequestUserId {
#ApiModelProperty({
example: 1
})
eventId: number;
#ApiModelProperty({
example: false
})
loadMap: boolean;
}
Example route:
#Post('details')
#ApiResponse({
status: 200,
description: 'Get event user details',
type: null
})
async details(#Res() res: Response, #Body() body: IApiEventsV2UserDetails) {
// call service
}
In Swagger UI the request example is shown properly:
{
"appVersionCode": null,
"testerMode": false,
"appId": 1,
"userId": 25,
"eventId": 5,
"loadMap": false
}
When imported in Postman it looks like this:
{
"appVersionCode": "<number>",
"testerMode": "<boolean>",
"appId": 1,
"userId": 25,
"eventId": "<number>",
"loadMap": "<boolean>"
}
I can't figure out what happens here and how can it be fixed.

Related

How can I display multiple ResponseDTOs' schemas in Swagger/NestJS?

I have this route which can return one of these two different DTOs:
#Get()
#ApiQuery({ name: 'legacy', description: "'Y' to get houses legacy" })
async findAllHouses(
#Query('legacy') legacy: string,
): Promise<HousesDto[] | HousesLegacyDto[]> {
...
}
I want to display both of these ResponseDTOs in swagger.
I've tried this decorator:
#ApiOkResponse({
schema: { oneOf: refs(HousesDto, HousesLegacyDto) },
})
// OR
#ApiOkResponse({
schema: {
oneOf: [
{ $ref: getSchemaPath(HousesDto) },
{ $ref: getSchemaPath(HousesLegacyDto) },
],
},
})
with #ApiExtraModels() on top of DTO classes and #ApiProperty() on each properties.
But I still get empty objects in Swagger and I suppose it would not have even taken array types in consideration.
How can I display both of these schemas properly?
Seems to me like a lot of very obscure solutions have been posted here and there, so I will try to clarify what needs to be done.
You have two DTOs:
export class SomeStatusDto {
#ApiProperty({
description: 'Id',
example: 1,
})
#IsNumber()
id: number;
#ApiProperty({
description: 'Status',
example: 'in_progress',
})
#IsString()
status: string;
}
export class ErrorStatusDto {
#ApiProperty({
description: 'Id',
example: 1,
})
#IsNumber()
id: number;
#ApiProperty({
description: 'Error',
example: 'Some error string',
})
#IsString()
error: string;
}
Then you have your controller:
#UseGuards(AccountTypesGuard)
#ApiOperation({ summary: 'Get status of...' })
#Get('status')
#ApiExtraModels(SomeStatusDto, ErrorStatusDto)
#ApiOkResponse({
schema: { anyOf: refs(SomeStatusDto, ErrorStatusDto) },
})
async getPullStatus(
#Request() req,
#Param('id', ParseIntPipe) someId: number,
): Promise<SomeStatusDto | ErrorStatusDto> {
// check if someId belongs to user
const idBelongsToUser = await this.myService.validateSomeId(
req.user.id,
someId,
);
if (!idBelongsToUser) {
throw new ForbiddenException(
`SomeId does not belong to user (someId=${someId}, userId=${req.user.id})`,
);
}
const key = `status-${someId}`;
const response = await this.redisService.getByKey(key);
return response ? response : {};
}
Note the solution below. You need to reference the DTOs as #ApiExtraModels() and then you can add them as anyOf: refs(...) in your schema.
#ApiExtraModels(SomeStatusDto, ErrorStatusDto)
#ApiOkResponse({
schema: { anyOf: refs(SomeStatusDto, ErrorStatusDto) },
})
Hope this helps somebody :)
so I encountered a similar issue and this is how you could get the output shown in the image above.
Using the #ApiResponse decorator you could set the two responses using the examples property, try the code sample below
#ApiResponse({
status: 200,
description: 'Successful response',
content: {
'application/json': {
examples: {
HousesDto: { value: HousesDto },
HousesLegacyDto: { value: HousesLegacyDto },
},
},
},
})

Decimal field is transformed to string using createQueryBuilder

This is my table:
#Entity('products')
export class Products {
#PrimaryGeneratedColumn()
#IsNumber()
public id: number;
#Column('decimal', {
precision: 20,
scale: 2,
transformer : {
to (value) {
return value ;
},
from (value) {
return parseFloat (value) ;
},
},
})
#IsNotEmpty()
price: number;
}
In my ormconfig file I have:
...
bigNumberStrings: false,
supportBigNumbers: true,
If I do:
return await this.repository.find();
Everything works correctly. The price field returns it as a decimal.
But if I use createQueryBuilder it brings it back as a string:
return await this.repository.createQueryBuilder("products")
.select([
'products.id AS id',
'products.price AS price'])
.getRawMany();
Please, could someone tell me how I can fix it?

Loopback POST array of entry?

I want to insert 10 entries with one query against 10 queries.
I read that it's possible to do it by sending an array like this :
But I get this error:
Do I need to set something? I don't know what to do at all.
Repo with a sample : https://github.com/mathias22osterhagen22/loopback-array-post-sample
Edit:
people-model.ts:
import {Entity, model, property} from '#loopback/repository';
#model()
export class People extends Entity {
#property({
type: 'number',
id: true,
generated: true,
})
id?: number;
#property({
type: 'string',
required: true,
})
name: string;
constructor(data?: Partial<People>) {
super(data);
}
}
export interface PeopleRelations {
// describe navigational properties here
}
export type PeopleWithRelations = People & PeopleRelations;
The problem with your code was :
"name": "ValidationError", "message": "The People instance is not
valid. Details: 0 is not defined in the model (value: undefined);
1 is not defined in the model (value: undefined); name can't be
blank (value: undefined).",
Here in above as in your #requestBody schema, you are applying to insert a single object property, where as in your body are sending the array of [people] object.
As you can see in your people.model.ts you have declared property name to be required, so system finds for the property "name", which obviously not available in the given array of object as primary node.
As you are passing index array, so its obvious error that you don't have any property named 0 or 1, so it throws error.
The below is the code hat you should apply to get insert the multiple, items of the type.
#post('/peoples', {
responses: {
'200': {
description: 'People model instance',
content: {
'application/json': {
schema: getModelSchemaRef(People)
}
},
},
},
})
async create(
#requestBody({
content: {
'application/json': {
schema: {
type: 'array',
items: getModelSchemaRef(People, {
title: 'NewPeople',
exclude: ['id'],
}),
}
},
},
})
people: [Omit<People, 'id'>]
): Promise<{}> {
people.forEach(item => this.peopleRepository.create(item))
return people;
}
You can also use this below
Promise<People[]> {
return await this.peopleRepository.createAll(people)
}
You can pass the array of your people model by modifying the request body.If you need more help you can leave comment.
I think you have a clear solution now. "Happy Loopbacking :)"

"Client network socket disconnected before secure TLS connection was established" - Neo4j/GraphQL

Starting up NestJS & GraphQL using yarn start:dev using await app.listen(3200);. When trying to connect to my Neo4J Desktop, I get this error trying to get my queries at localhost:3200/graphQL:
"errors": [
{
"message": "Client network socket disconnected before secure TLS connection was established",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"getMovies"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"code": "ServiceUnavailable",
"name": "Neo4jError"
}
}
}
],
"data": null
}
So I figured my local Neo4J desktop graph is not running correctly, but I can't seem to find any answer how to solve it.. Currently I have a config.ts file which has:
export const HOSTNAME = 'localhost';
export const NEO4J_USER = 'neo4j';
export const NEO4J_PASSWORD = '123';
and a file neogql.resolver.ts:
import {
Resolver,
Query,
Args,
ResolveProperty,
Parent,
} from '#nestjs/graphql';
import { HOSTNAME, NEO4J_USER, NEO4J_PASSWORD } from '../config';
import { Movie } from '../graphql';
import { Connection, relation, node } from 'cypher-query-builder';
import { NotFoundException } from '#nestjs/common';
const db = new Connection(`bolt://${HOSTNAME}`, {
username: NEO4J_USER,
password: NEO4J_PASSWORD,
});
#Resolver('Movie')
export class NeogqlResolver {
#Query()
async getMovies(): Promise<Movie> {
const movies = (await db
.matchNode('movies', 'Movie')
.return([
{
movies: [{ id: 'id', title: 'title', year: 'year' }],
},
])
.run()) as any;
return movies;
}
#Query('movie')
async getMovieById(
#Args('id')
id: string,
): Promise<any> {
const movie = (await db
.matchNode('movie', 'Movie')
.where({ 'movie.id': id })
.return([
{
movie: [{ id: 'id', title: 'title', year: 'year' }],
},
])
.run<any>()) as any;
if (movie.length === 0) {
throw new NotFoundException(
`Movie id '${id}' does not exist in database `,
);
}
return movie[0];
}
#ResolveProperty()
async actors(#Parent() movie: any) {
const { id } = movie;
return (await db
.match([node('actors', 'Actor'), relation('in'), node('movie', 'Movie')])
.where({ 'movie.id': id })
.return([
{
actors: [
{
id: 'id',
name: 'name',
born: 'born',
},
],
},
])
.run()) as any;
}
}
Be sure to pass the Config object like this:
var hostname = this.configService.get<string>('NEO4J_URL');
var username = this.configService.get<string>('NEO4J_USERNAME');
var password = this.configService.get<string>('NEO4J_PASSWORD');
db = new Connection(`${hostname}`, {
username: username,
password: password,
}, {
driverConfig: { encrypted: "ENCRYPTION_OFF" }
});
I had the same problem with grandSTACK when running against a neo4j version 4 server. According to Will Lyon this is due to mismatched encryption defaults between driver and database: https://community.neo4j.com/t/migrating-an-old-grandstack-project-to-neo4j-4/16911/2
So passing a config object with
{ encrypted: "ENCRYPTION_OFF"}
to the Connection constructor should do the trick.

Google Cloud Print Node API TICKET not working

This is my code and I am using npm node-gcp and sadly, the ticket is not working, I tried to make the copies = 3 to see if the printer will print 3 and to see if the ticket is working or not, But it's not working :(
I tried all the resources i can find, php ticket, c# ticket, But all are not working,
I am inside the code of npm node-gcp and I am trying to modify its code and see what will work and not, because the original code is he is not passing any ticket.
return preq({
method: "POST",
uri: "https://www.google.com/cloudprint/submit",
form: {
title: "Print job title",
content:
"test print",
ticket: {
version: "1.0",
print: {
copies: {
copies: 3
},
page_orientation: {
type: 0
},
margins: {
top_microns: 0,
bottom_microns: 0,
left_microns: 0,
right_microns: 0
}
}
},
contentType: "url", //optional, default = url
printerid: xxxxxxxxxxxxx,
tags: ["tag1", "tag2"] //optional, default = [],
},
headers: {
"X-CloudPrint-Proxy": "node-gcp",
Authorization: "OAuth " + this.options.accessToken
},
json: true
})
.then(function(result) {
return result;
})
.nodeify(cb);
});
i am expecting a response of number of pages is 3 but all I am getting is 1 piece of paper.
I just had to deal with this issue and discovered that ticket needs to be sent as a stringified json object.
For form, try this instead:
form: {
title: "Print job title",
content:
"test print",
ticket: JSON.stringify({
version: "1.0",
print: {
copies: {
copies: 3
},
page_orientation: {
type: 0
},
margins: {
top_microns: 0,
bottom_microns: 0,
left_microns: 0,
right_microns: 0
}
})
},

Resources