Swagger-codegen: basePath specified in swagger file is ignored by spring code generator

Created on 28 Mar 2017  路  30Comments  路  Source: swagger-api/swagger-codegen

Description

A basePath specified in a swagger file is ignored by the spring code generator. Annotation @RequestMapping doesn't contain it.

Swagger-codegen version

2.2.2 (swagger-codegen-maven-plugin)

Swagger declaration file content or url
################################################################################
#                             Metadata                                         #
################################################################################
# this is an example API to illustrate the usage of Swagger 

swagger: '2.0'
info:
  title: Person API
  description: Create, maintain, and update a person database as personal contacts' list.
  version: "1.0.0"

# array of all schemes that your API supports
schemes:
  - https

# will be prefixed to all paths
basePath: /v1
produces:
  - application/json

################################################################################
#                                 Paths                                        #
################################################################################  
paths:

  /persons/{id}:              
    delete:
      summary: Deletes a person.
      description: |
        Deletes a person from the database.
      tags:
        - Person
      parameters:
        - name: id
          in: path
          description: The ID of the person to be deleted.
          type: integer
          format: int64
          required: true
      responses:
        204:
          description: Person deleted.

generates:

@javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "2017-03-28T19:13:06.141+02:00")

@Api(value = "persons", description = "the persons API")
public interface PersonsApi {

    @ApiOperation(value = "Deletes a person.", notes = "Deletes a person from the database. ", response = Void.class, tags={ "Person", })
    @ApiResponses(value = { 
        @ApiResponse(code = 204, message = "Person deleted.", response = Void.class) })
    @RequestMapping(value = "/persons/{id}",
        produces = { "application/json" }, 
        method = RequestMethod.DELETE)
    default ResponseEntity<Void> personsIdDelete(@ApiParam(value = "The ID of the person to be deleted.",required=true ) @PathVariable("id") Long id) {
        // do some magic!
        return new ResponseEntity<Void>(HttpStatus.OK);
    }

}
Command line used for generation
Steps to reproduce
Related issues
Suggest a Fix
Bug Spring

Most helpful comment

No, my expectation was that the code generator for spring takes the basePath specified in the swagger file into account. The contextPath of spring has another purpose. It moves all rest endpoints including those provided by spring itself. We want to use the basePath to put a version number into it that is prepended to all rest endpoints specified in the swagger file. Of course if there were a spring feature with which we can prepend all endpoints of our swagger api with a version number we would have used it as a workaround.

All 30 comments

Is this the same as #3720?

Yes it is the same problem.

@Frank-Stephan so did the following resolve the issue for you?

https://github.com/swagger-api/swagger-codegen/issues/3720#issuecomment-245564959

In 3720 was suggested to change the base path in the spring configuration file (server.contextPath=/v2). This is not feasible for me, as it moves all rest endpoints including spring boot health endpoints. In addition I see then no way to provide two API versions out of one micro service.

@Frank-Stephan so your requirement is to change contextPath for some but not all of the endpoints?

No, my expectation was that the code generator for spring takes the basePath specified in the swagger file into account. The contextPath of spring has another purpose. It moves all rest endpoints including those provided by spring itself. We want to use the basePath to put a version number into it that is prepended to all rest endpoints specified in the swagger file. Of course if there were a spring feature with which we can prepend all endpoints of our swagger api with a version number we would have used it as a workaround.

I have the same issue. Do you know when the fix is planned?

@Frank-Stephan I think what the generator is doing with basePath is per design. If you want your operation path to be /v1/persons/{id}, for example, you would put that in your path:

paths:
  '/v1/persons/{id}':
    ### stuff

I found a workaround that it works for me: I copied the application properties from the generated code to the src/main.resources.

@fehguy I have a similar problem, but following the approach you suggest consolidates all my endpoints into a single api file, which apparently can then only to mapped to a single controller. Any suggestions on how one could get the base bath as Frank wanted and yet keep different controller implementations? I tried multiple controllers implementing different methods of the same single api interface, but that resulted in an ambiguous mapping exception.

Frankly, I'm not sure why the issue was closed.
I think it is a valid requirement to have the basePath prepended to the resources. Otherwise the only viable workaround is to do it manually for each resource. And this not only violates the DRY principle, but also contradicts the entire REST design paradigm. REST is all about resources and by the workaround we just mix up concerns, making the notion of a resource contaminated with some "configuration" stuff.
Imagine I'm talking about user management and would like to create a namespace for it. Not only to separate versions, but also to separate bounded contexts. In that case it would sound like user-management/v1. Putting it into the basePath looks natural. In that case it is just a prefix, not a part of a resource. The resources are then described as

  /users:
    post:
...

Lacking the ability to handle the basePath by the generator, I have to describe my resources in the way:

  /user-management/v1/users:
    post:
...

But sorry, there is no resource like user-management/v1/users. It is a mix of configuration data and resources.
So, maybe it is still possible to reopen it and fix the issue? I will see if it is possible to do that by just modifying the Spring templates, if yes, will try to create a PR for the issue.

And a workaround by @erreobi may not work for everyone. For example, I never check in a generated code to a source repository and never copy parts of it to my sources. It is an endless source of inconsistencies. Just imagine, you changed your Swagger model and the generated code is changed. Who should then know all places, where a part of the generated code has been replicated to? This might work for a one-person project, but in a team environment might be challenging...

This issue still persists. Please let us know when a fix is expected.

Adding

...
@RequestMapping(value = "{{{contextPath}}}")
...

as annotation to api.mustache in the JavaSpring templates seems a viable solution to me. Or am I missing something here?

@kerkhofsd this will produce request mapping with only a base path. What worked for me, is
@RequestMapping(value = "{{{contextPath}}}{{{path}}}",...
I will fire a PR in a couple of days...

@ok11
I meant adding it as an annotation on class/interface level:

@RequestMapping(value = "{{{contextPath}}}")
public interface {{classname}} {

Right. Sorry, haven't realized what you mean. Yes, your suggestion is definitely better. Would you then initiate a PR with the proposal?

@kerkhofsd Any chance of a PR for your fork and fix, would be great to see it fixed upstream.

#8131
@imduffy15 thanks for the reminder

Awesome! Thank you.

I don't understand if this problem was fixed and merged to the master branch since even though i have basePath i my swagger file I don't see it in the generated interface file

Any word on this? BasePath is still not being added to my requestMapping in Spring.

Here's the relevant part of my spec file.

host: 'localhost:8080'
basePath: /v1
...
paths:
  /free-busy:
...

Here's the request mapping from the java controller. There is no v1 :(

@RequestMapping(value = "/free-busy",

This should be @RequestMapping(value = "/v1/free-busy")

8131

PR still open...

Ping...

Any progress on this? Currently we manually have to copy the base path and attach it to hostname in configuration. That should not be the case. Currently the basepath in swagger basically useless...

This is an issue both server( and I can understand that it may be difficult to implement ) but whyfor client as well?

Again this is something that we've run into when developing using Swagger's generated Spring code.

when will this fix be merged?

Hello, would be interested in an update as well! Thanks

hey guys, i'll take a look on this next week.

Was this page helpful?
0 / 5 - 0 ratings