question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

import { Post, Param, Delete, Put, Get, Res, Body, HttpStatus } from "@nestjs/common";
import { ApiResponse, ApiOperation } from "@nestjs/swagger";
import { Response } from 'express';
import { CRUDService } from "./crud.service";
import { Document } from 'mongoose';

export abstract class CRUDController<M extends Document, C, U, T extends CRUDService<M, C, U>> {
  constructor ( protected readonly service: T ) { }

  @Post()
  @ApiOperation( { title: 'Create' } )
  @ApiResponse( { status: 201, description: 'Object created.' } )
  @ApiResponse( { status: 400, description: 'Validation failed.' } )
  async create ( @Body() post: C, @Res() res: Response ): Promise<void> {
    const result = await this.service.create( post );
    res.status( result ? HttpStatus.OK : HttpStatus.NOT_FOUND ).send( result );
  }

  @Get()
  @ApiOperation( { title: 'Find All' } )
  @ApiResponse( { status: 200, description: 'Objects returned.' } )
  @ApiResponse( { status: 400, description: 'Validation failed.' } )
  async findAll ( @Res() res: Response ): Promise<void> {
    const result = await this.service.findAll();
    res.status( result ? HttpStatus.OK : HttpStatus.NOT_FOUND ).send( result );
  }

  @Get( ':id' )
  @ApiOperation( { title: 'Find by Id' } )
  @ApiResponse( { status: 200, description: 'Object found.' } )
  @ApiResponse( { status: 400, description: 'Validation failed.' } )
  @ApiResponse( { status: 404, description: 'Object not found.' } )
  async findById ( @Param( 'id' ) id: string, @Res() res: Response ): Promise<void> {
    const result = await this.service.findById( id );
    res.status( result ? HttpStatus.OK : HttpStatus.NOT_FOUND ).send( result );
  }

  @Put( ':id' )
  @ApiOperation( { title: 'Update' } )
  @ApiResponse( { status: 200, description: 'Post updated.' } )
  @ApiResponse( { status: 400, description: 'Validation failed.' } )
  @ApiResponse( { status: 404, description: 'Post not found.' } )
  async update ( @Param( 'id' ) id: string, @Body() updatePostDto: U, @Res() res: Response ): Promise<void> {
    const result = await this.service.update( id, updatePostDto );
    res.status( result ? HttpStatus.OK : HttpStatus.NOT_FOUND ).send( result );
  }

  @Delete( ':id' )
  @ApiOperation( { title: 'Remove' } )
  @ApiResponse( { status: 204, description: 'Object removed.' } )
  @ApiResponse( { status: 400, description: 'Validation failed.' } )
  @ApiResponse( { status: 404, description: 'Object not found.' } )
  async remove ( @Param( 'id' ) id: string, @Res() res: Response ): Promise<void> {
    const result = await this.service.remove( id );
    res.status( result ? HttpStatus.NO_CONTENT : HttpStatus.NOT_FOUND ).send( result );
  }
}

This will produce the following error in the console of the browser.

swagger-ui-init.js:30 Uncaught SyntaxError: Unexpected identifier

Here is swagger-ui-init.js:

window.onload = function() {
  // Build a system
  var url = window.location.search.match(/url=([^&]+)/);
  if (url && url.length > 1) {
    url = decodeURIComponent(url[1]);
  } else {
    url = window.location.origin;
  }
  var options = {
  "swaggerDoc": {
    "swagger": "2.0",
    "info": {
      "description": "Bitea API",
      "version": "1.0",
      "title": "Bitea API"
    },
    "basePath": "/",
    "tags": [],
    "schemes": [
      "http"
    ],
    "securityDefinitions": {},
    "paths": {
      "/posts": {
        "post": {
          "summary": "Create",
          "parameters": [
            {
              "type": function Object() { [native code] },
              "name": "Object",
              "required": true,
              "in": "body",
              "schema": {
                "$ref": "#/definitions/Object"
              }
            }
          ],
          "responses": {
            "201": {
              "description": "Object created."
            },
            "400": {
              "description": "Validation failed."
            }
          },
          "tags": [
            "Posts"
          ],
          "produces": [
            "application/json"
          ],
          "consumes": [
            "application/json"
          ]
        },
        "get": {
          "summary": "Find All",
          "responses": {
            "200": {
              "description": "Objects returned."
            },
            "400": {
              "description": "Validation failed."
            }
          },
          "tags": [
            "Posts"
          ],
          "produces": [
            "application/json"
          ],
          "consumes": [
            "application/json"
          ]
        }
      },
      "/posts/{id}": {
        "get": {
          "summary": "Find by Id",
          "parameters": [
            {
              "type": "string",
              "name": "id",
              "required": true,
              "in": "path"
            }
          ],
          "responses": {
            "200": {
              "description": "Object found."
            },
            "400": {
              "description": "Validation failed."
            },
            "404": {
              "description": "Object not found."
            }
          },
          "tags": [
            "Posts"
          ],
          "produces": [
            "application/json"
          ],
          "consumes": [
            "application/json"
          ]
        },
        "put": {
          "summary": "Update",
          "parameters": [
            {
              "type": function Object() { [native code] },
              "name": "Object",
              "required": true,
              "in": "body",
              "schema": {
                "$ref": "#/definitions/Object"
              }
            },
            {
              "type": "string",
              "name": "id",
              "required": true,
              "in": "path"
            }
          ],
          "responses": {
            "200": {
              "description": "Post updated."
            },
            "400": {
              "description": "Validation failed."
            },
            "404": {
              "description": "Post not found."
            }
          },
          "tags": [
            "Posts"
          ],
          "produces": [
            "application/json"
          ],
          "consumes": [
            "application/json"
          ]
        },
        "delete": {
          "summary": "Remove",
          "parameters": [
            {
              "type": "string",
              "name": "id",
              "required": true,
              "in": "path"
            }
          ],
          "responses": {
            "204": {
              "description": "Object removed."
            },
            "400": {
              "description": "Validation failed."
            },
            "404": {
              "description": "Object not found."
            }
          },
          "tags": [
            "Posts"
          ],
          "produces": [
            "application/json"
          ],
          "consumes": [
            "application/json"
          ]
        }
      }
    },
    "definitions": {
      "Object": {
        "type": "object",
        "properties": {}
      }
    }
  },
  "customOptions": {}
};
  url = options.swaggerUrl || url
  var customOptions = options.customOptions
  var spec1 = options.swaggerDoc
  var swaggerOptions = {
    spec: spec1,
    url: url,
    dom_id: '#swagger-ui',
    deepLinking: true,
    presets: [
      SwaggerUIBundle.presets.apis,
      SwaggerUIStandalonePreset
    ],
    plugins: [
      SwaggerUIBundle.plugins.DownloadUrl
    ],
    layout: "StandaloneLayout"
  }
  for (var attrname in customOptions) {
    swaggerOptions[attrname] = customOptions[attrname];
  }
  var ui = SwaggerUIBundle(swaggerOptions)

  if (customOptions.oauth) {
    ui.initOAuth(customOptions.oauth)
  }

  if (customOptions.authAction) {
    ui.authActions.authorize(customOptions.authAction)
  }

  window.ui = ui
}

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:13 (3 by maintainers)

github_iconTop GitHub Comments

9reactions
XBeg9commented, Jul 12, 2019

Solution using Mixin:

export type ClassType<T = any> = new (...args: any[]) => T;

interface IPaginated {
  limit?: number;
  offset?: number;
}

export function PaginatedRequestDto<T extends ClassType>(ResourceCls: T) {
  class Paginated extends ResourceCls implements IPaginated {
    @ApiModelPropertyOptional({ default: 100 })
    public limit?: number;

    @ApiModelPropertyOptional({ default: 0 })
    public offset?: number;
  }

  return Paginated;
}

and then use it like this:

class PaginatedSearchRequestDto extends PaginatedRequestDto(SearchRequestDto) {}

I’ve also verified this with swagger docs shows both definitions from SearchRequestDto and Paginated.

1reaction
cojackcommented, Jun 8, 2018

@kamilmysliwiec so maybe we’ll add some additional decorator for class definition that will cover generic output, something like:

@ApiInputOutput(Class)

fe Im using TypeORM, and using generic RestController with methods like:

@Post()
public async update(partial: DataPartial<T>): Promise<T> {
  return this.service.update(partial);
}

This produce and empty POST params in swagger, by this, swagger is useless.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Tutorial: Getting started with generics - The Go Programming ...
This tutorial introduces the basics of generics in Go. With generics, you can declare and use functions or types that are written to...
Read more >
Generics support : GO-9515 - YouTrack
Implement type inference for generics (GO-9686). Available in 2021.3. Wrong highlighting of generic function invocation (GO-11956). Support underlying type ...
Read more >
What Golang generics support means for code structure
Go, a language known for its strong and static typing, now supports generic types. Learn how Golang generics can create more concise, ...
Read more >
Why Use Generics? (The Java™ Tutorials > Learning the Java ...
In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar ......
Read more >
How To Use Generics in Go | DigitalOcean
Finally, you will create a function that uses your cards and supports generic types. Prerequisites. To follow this tutorial, you will need: Go ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found