kongchen / swagger-maven-plugin

JAX-RS & SpringMVC supported maven build plugin, helps you generate Swagger JSON and API document in build phase.
http://kongchen.github.io/swagger-maven-plugin/
Apache License 2.0
763 stars 451 forks source link

Generated Swagger Files Missing FormData Parameters #352

Open jencodingatwork opened 8 years ago

jencodingatwork commented 8 years ago

I am using version 3.1.3 of the Swagger-Maven-Plugin to generate a yaml file from my api annotations, however the FormData parameters are not being generated and an incorrect body is.

Here are the annotations:

@POST 
    @Produces({ "application/json", "application/xml", "application/avro" })
    @Consumes({"multipart/form-data"})
    @io.swagger.annotations.ApiOperation(value = "Upload plugin", notes = "This can only be done by the logged in user.", response = void.class, tags={ "plugin", })
    @io.swagger.annotations.ApiResponses(value = { 
        @io.swagger.annotations.ApiResponse(code = 200, message = "successful operation", response = void.class) })
    public Response createPlugin(@ApiParam(value = "Json string containing plugin information", required=true)
            @FormDataParam("json")  String pluginJson,
            @FormDataParam("jarfile") InputStream jarInputStream,
            @FormDataParam("jarfile") FormDataContentDisposition jarFileDetail,
            @FormDataParam("configfile") InputStream configInputStream,
            @FormDataParam("configfile") FormDataContentDisposition configFileDetail,@Context SecurityContext securityContext)
    throws NotFoundException {
        return delegate.createPlugin(pluginJson, jarInputStream, jarFileDetail, configInputStream, configFileDetail,securityContext);
    }

Here is the corresponding section of the generated yaml file:


paths:
  /plugin:
    post:
      tags:
      - "plugin"
      summary: "Upload plugin"
      description: "This can only be done by the logged in user."
      operationId: "createPlugin"
      consumes:
      - "multipart/form-data"
      produces:
      - "application/json"
      - "application/xml"
      - "application/avro"
      parameters:
      - in: "body"
        name: "body"
        description: "Json string containing plugin information"
        required: true
      responses:
        200:
          description: "successful operation"

It should be:

paths:
  /plugin:
    post:
      tags:
        - plugin
      summary: Upload plugin
      description: This can only be done by the logged in user.
      operationId: createPlugin
      consumes:
      - "multipart/form-data"
      produces:
        - application/json
        - application/xml
        - application/avro
      parameters:
        - in: formData
          name: json
          description: Json string containing plugin information
          required: true
          type: string
        - in: formData
          name: jarFile
          description: Jar File to upload
          required: true
          type: file
        - in: formData
          name: configFile
          description: config File to upload
          required: true
          type: file
      responses:
        200:
          description: successful operation
ghost commented 8 years ago

Same problem here.

This is an excerpt of a swagger.yaml file generated on the server:

 /admin/v1/upload:
    post:
      tags:
      - "admin v1"
      summary: "Uploads a zip file with PDM containers. Returns an object of type\
        \ AdminResponse.If the errorCode is 'ok', then the upload operation finished\
        \ successfuly. Otherwise, the errorMessage will contain the description of\
        \ the problem."
      description: ""
      operationId: "upload"
      consumes:
      - "multipart/form-data"
      produces:
      - "application/json"
      parameters:
      - name: "userName"
        in: "query"
        description: "user name (Q-number)"
        required: true
        type: "string"
      - name: "file"
        in: "formData"
        description: "file to upload"
        required: false
        type: "file"
      responses:
        200:
          description: "successful operation"
          schema:
            $ref: "#/definitions/PdmAdminResponse"

And this is the same method, generated by swagger-maven-plugin:

/admin/v1/upload:

    post:
      tags:
      - "admin v1"
      summary: "Uploads a zip file with PDM containers. Returns an object of type\
        \ AdminResponse.If the errorCode is 'ok', then the upload operation finished\
        \ successfuly. Otherwise, the errorMessage will contain the description of\
        \ the problem."
      description: ""
      operationId: "upload"
      consumes:
      - "multipart/form-data"
      produces:
      - "application/json"
      parameters:
      - name: "userName"
        in: "query"
        description: "user name (Q-number)"
        required: true
        type: "string"
      - in: "body"
        name: "body"
        description: "file to upload"
        required: false
        schema:
          $ref: "#/definitions/InputStream"
      - in: "body"
        name: "body"
        description: "file detail"
        required: false
        schema:
          $ref: "#/definitions/FormDataContentDisposition"
      responses:
        200:
          description: "successful operation"
          schema:
            $ref: "#/definitions/PdmAdminResponse"
philipdnichols commented 8 years ago

Bump for this - we got around it by using @ApiImplicitParams however.

jencodingatwork commented 8 years ago

@philipdnichols Can you elaborate on your work around? Did you use @ApiImplicitParams instead of @ApiParams or @FormDataParams?

philipdnichols commented 8 years ago

@jencodingatwork Sure - We use the @FormDataParam("file") annotation on the InputStream and FormDataContentDisposition method parameters ("file" is the name of the multipart that contains the file. We then annotate the method with @ApiImplicitParams({}) which takes an array of @ApiImplicitParam. For the @ApiImplicitParam, we pass it the values name="file", paramType="form" and dataType="file".

Let me know if you have any other questions.

xinmeng1 commented 8 years ago

+1

jencodingatwork commented 8 years ago

In case anyone else tries to use the work around with the swagger ui, you can't use the dataType="file" there is an issue with it discussed here: https://github.com/swagger-api/swagger-core/issues/1319. The work around is to use java.io.File instead.

ghost commented 7 years ago

similar for path parameters, names are missing in generated swagger.json when generating from spring @RestController... Parameter name empty string: "parameters" : [ { "name" : "", "in" : "path", "required" : true, "type" : "string" } ],

szabomarcell commented 6 years ago

@mireczatko unfortunately it is not smart enough to figure out the parameter name, you have to specify it explicitly in the annotation:

getFoo(@PathVariable("bar") String bar)

mzatko commented 6 years ago

yeah, of course this is the way, especially in case you want use different than implicit one, which is @PathVariable String bar => @PathVariable("bar") String bar same way as "smarter" frameworks do :o)

puru86 commented 6 years ago

+1 same with @HeaderParam, @PathParam and @ QueryParam.

Weird thing though... as @philipdnichols said, you can get around it by using the @ApiImplicitParams[] annotation, BUT, the plugin suddenly starts working at this point and recognizes the JAXRS params.

For me, this is what happened...

  1. JAXRS service impl created with swagger ApiOperation, ApiResponse and @PathParam annotations
  2. Swagger.json generated without param names.
  3. Added ApiImplicitParams, Swagger.json now shows param names.
  4. a few builds later, the params are being duplicated - pathParam1 shows twice in Swagger UI.
  5. Removed ApiImplicitParams - goes back to normal - shows pathParam1 and only once - CORRECT.
  6. Now i added 5 new services - no params showing for these.

Going to try adding the ApiImplicitParams and see what happens

puru86 commented 6 years ago

ummm .. it seems to be all kinds of weird - its showing up for a few of my services but not for others.

puru86 commented 6 years ago

ok here is what i have:

  1. plugin version 3.1.3

  2. pkg/class structure: a.b.c.rs.entitygrp.service: IEntityAService (interface with all the JAXRS and Swagger annotations) EntityAServiceImpl (concrete impl with @ Component spring annotation - implements IEntityAService ) IEntityBService (interface with all the JAXRS and Swagger annotations) EntityBServiceImpl (concrete impl with @ Component spring annotation - implements IEntityBService ) IEntityCService (interface with all the JAXRS and Swagger annotations) EntityCServiceImpl (concrete impl with @ Component spring annotation - implements IEntityCService ) IEntityDService (interface with all the JAXRS and Swagger annotations) EntityDServiceImpl (concrete impl with @ Component spring annotation - implements IEntityDService ) IEntityEService (interface with all the JAXRS and Swagger annotations) EntityEServiceImpl (concrete impl with @ Component spring annotation - implements IEntityEService ) a.b.c.rs.health.service: IHealthCheckService (interface with all the JAXRS and Swagger annotations) HealthCheckServiceImpl (concrete impl with @ Component spring annotation - implements IHealthCheckService ) a.b.c.rs.echo.service: IEchoService (interface with all the JAXRS and Swagger annotations) EchoServiceImpl (concrete impl with @ Component spring annotation - implements IEchoService )

  3. pom has api source location as the parent package a.b.c.rs

What i changed:

  1. Always using @ Api( tags = "/bla" ) instead of @ Api or @ Api ( value = "/bla")
  2. if the response type is a bean, always ensuring that it is concrete and no abstract
  3. verified that all the param references are correct (names match and types match)

what is happening:

  1. any package that has a single JAXRS impl in it, is working as expected.
  2. The one package with multiple JAXRS services in it (a.b.c.rs.entitygrp.service) is giving inconsistent output. Every time i run the build, the parameters are removed in a random class, and gets added for a random class. I am unable to recognize any patterns.

Going to try breaking it into sub-packages.

puru86 commented 6 years ago

I take it back - after breaking it into sub-packages, even the solo service impls are misbehaving. the ones that were stable are also now losing the params in the swagger json (a.b.c.rs.echo.service).

puru86 commented 6 years ago

the plugin does not like annotations at interface level. i was able to get the params to show by moving all my annos (spring + swagger + jaxrs) down from the interface to the impl.