swagger-api / swagger-core

Examples and server integrations for generating the Swagger API Specification, which enables easy access to your REST API
http://swagger.io
Apache License 2.0
7.36k stars 2.17k forks source link

@Api() Resource inheritance not supported (even with ReflectiveJaxrsScanner) #925

Closed shivangshah closed 9 years ago

shivangshah commented 9 years ago

Hi, I have reading here on how to use reflectiveJaxrsScanner but it doesn't work as you'd expect it to be. Here's the example. My base api-docs look like this :

{
  "apiVersion": "2.0",
  "swaggerVersion": "1.2",
  "apis": [
    {
      "path": "/tenants",
      "description": "Tenants Service"
    },
    {
      "path": "/api/v1",
      "description": "Services"
    },
    {
      "path": "/master",
      "description": "Master Service"
    },
    {
      "path": "/admin",
      "description": "Admin Service"
    },
    {
      "path": "/staging",
      "description": "Staging Service"
    },
    {
      "path": "/dataSources",
      "description": "Data Source Service"
    }
  ]
}

And just for example we will take the datasource service:

{
  "apiVersion": "2.0",
  "swaggerVersion": "1.2",
  "basePath": "http://localhost:8080",
  "resourcePath": "/dataSources",
  "produces": [
    "application/json"
  ],
  "consumes": [
    "application/json"
  ],
  "apis": [
    {
      "path": "/",
      "operations": [
        {
          "method": "POST",
          "summary": "create DataSource",
          "notes": "",
          "type": "string",
          "nickname": "createDataSource",
          "authorizations": {},
          "parameters": [
            {
              "name": "body",
              "required": false,
              "type": "string",
              "paramType": "body",
              "allowMultiple": false
            }
          ]
        },
        {
          "method": "GET",
          "summary": "get all dataSources",
          "notes": "",
          "type": "string",
          "nickname": "getAllDataSources",
          "authorizations": {},
          "parameters": []
        }
      ]
    },
    {
      "path": "/{dataSourceId}",
      "operations": [
        {
          "method": "GET",
          "summary": "get dataSource",
          "notes": "",
          "type": "string",
          "nickname": "getDataSource",
          "authorizations": {},
          "parameters": [
            {
              "name": "dataSourceId",
              "description": "dataSourceId",
              "required": true,
              "type": "string",
              "paramType": "path",
              "allowMultiple": false
            }
          ]
        },
        {
          "method": "PUT",
          "summary": "update a dataSource",
          "notes": "",
          "type": "string",
          "nickname": "updateDataSource",
          "authorizations": {},
          "parameters": [
            {
              "name": "dataSourceId",
              "description": "dataSourceId",
              "required": true,
              "type": "string",
              "paramType": "path",
              "allowMultiple": false
            },
            {
              "name": "body",
              "required": false,
              "type": "string",
              "paramType": "body",
              "allowMultiple": false
            }
          ]
        }
      ]
    }
  ]
}

The problem in the second json is that the "resourcePath" is wrong. Because it did NOT inherit the resource path from the parent class. Here's the java code for this:

Base class:

@Path("/api/v1")
@Api(value = "/api/v1", description = "MDM Services")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class BaseService {
    private final static Logger logger = LoggerFactory.getLogger(BaseService.class);
    private final DataSourceService dataSourceService = new DataSourceService();

    @Path("/dataSources")
    public DataSourceService getDataSourceService() {
        return this.dataSourceService;
    }
}

And here's the datasource service

@Api(value = "/dataSources", description = "MDM Data Source Service")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class DataSourceService {

But default JAXRS does support path inheritance just fine but unfortunately @Api does not (unless I am doing something wrong?)

All help appreciated !

fehguy commented 9 years ago

Hi, this is using subresources. Can you please try with 1.5.3-M1-SNAPSHOT? The annotations should be the same, and there is a sample here:

https://github.com/swagger-api/swagger-core/tree/develop_2.0/samples/java-jaxrs-subresource

shivangshah commented 9 years ago

@fehguy I am currently on 2.0 and yes indeed I am talking about subresources. You want me to try 1.5.3-M1 version ? Is this the version before or after 2.0 ?

shivangshah commented 9 years ago

btw .. i do not see this branch 1.5.3-M1-SNAPSHOT in the link you sent me ..

fehguy commented 9 years ago

Hi, the develop_2.0 branch is targeting 1.5.3-M1-SNAPSHOT:

https://github.com/swagger-api/swagger-core/blob/develop_2.0/pom.xml

You can find the snapshot artifacts in sonatype:

https://oss.sonatype.org/content/repositories/snapshots/com/wordnik/swagger-core/

(the 2.0 snapshot is a misfire, I need to delete it)

shivangshah commented 9 years ago

Got it .. it seems like I am actually using 1.3.4 swagger version with dropwizard and if I upgrade to 1.5.3, there are some breaking changes that I will need to look into before I can try it out with my project .. any documentation for 1.5.3 snapshot with dropwizard 0.8?

fehguy commented 9 years ago

See the sample here:

https://github.com/swagger-api/swagger-core/tree/develop_2.0/samples/java-dropwizard

Note there are some dependencies you need to handle in the pom.xml.

shivangshah commented 9 years ago

I will give this a try sometime this week and let you know how it goes.

shivangshah commented 9 years ago

@fehguy So finally I got a chance play around with 1.5.4 snapshot and it almost got everything working in regards to subresource. There are a few features that the upgrade broke which i am listing here with and maybe you can shed some light as to what could be the problem ?

1) Through a subresource, if a path is not given at root level (because it gets subresource'd from inheritance), the api will not show up in swagger. For example:

@Path("/api/v1")
@Api(tags = "V1 APIs - All", value = "/api/v1", description = "MDM Services")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class BaseResource {

@Path("/somePath")
    @ApiOperation(value = "Returns Some service", response = SomeResource.class)
    public SomeResource getSomeService() {
        return this.someService;
    }
}
@Api(tags = "V1 Tenant APIs", hidden = true, value = "/tenants", description = "MDM Base Service")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class SomeResource {
@GET
    @Path("")
    @CacheControl(maxAge = 3, maxAgeUnit = TimeUnit.SECONDS)
    @ApiOperation(value = "get tenants", notes = "Sort Order Values can be 'ASC' or 'DESC'", response = String.class)
    public Response getStuff(@ApiParam(value = DATASOURCE_HEADER, required = true)
{
}

You see that @Path("")? I had to provide that for the swagger scanner to pickup that api. Otherwise it did not recognize the inherited path

2) The "required = true" does not work with @ApiParam (combined with @HeaderParam or @QueryParam) anymore. I checked the swagger.json and no matter what you put, required is always false. It does work with @PathParam though 3) The previous scanners were able to pickup Body parameters without any @ApiParam now I had to do something like this for it to pickup body parameters: BEFORE:

public Response create(@ApiParam(value = "someHeader", required = true)
            @HeaderParam("someHeader") String header, String jsonBody) {

AFTER

public Response create(@ApiParam(value = DATASOURCE_HEADER, required = true)
                        @HeaderParam("someHeader") String header,
            @ApiParam(value = "jsonBody", required = true) String jsonBody) {

Let me know what you think.

fehguy commented 9 years ago

@shivangshah thank you for the feedback. Here are some answers:

1) I will look at supporting that. If you have @ApiOperation that should be sufficient, like you're expecting

2) the required flags were fixed yesterday. If you get a new snapshot you should see them working fine.

3) the body parameter should be found, so this is a defect too.

shivangshah commented 9 years ago

@fehguy Tested 2) with the latest snapshot. It looks good ! Thanks for the turnaround! Let me know if you need a separate issue(s) for 1) and 3). I can help test them because I already have the framework and testcase for it in place.

fehguy commented 9 years ago

I would really appreciate the separate issues, yes

fehguy commented 9 years ago

since we have new, separate issues, i'm marking this as resolved.