Monday, September 30, 2013

Swagger: make developers love working with your REST API

As JAX-RS API is evolving, with version 2.0 released earlier this year under JSR-339 umbrella, it's becoming even more easy to create REST services using excellent Java platform.

But with great simplicity comes great responsibility: documenting all these APIs so other developers could quickly understand how to use them. Unfortunately, in this area developers are on their own: the JSR-339 doesn't help much. For sure, it would be just awesome to generate verbose and easy to follow documentation from source code, and not asking someone to write it along the development process. Sounds unreal, right? In certain extent, it really is, but help is coming in a form of Swagger.

Essentially, Swagger does a simple but very powerful thing: with a bit of additional annotations it generates the REST API descriptions (HTTP methods, path / query / form parameters, responses, HTTP error codes, ...) and even provides a simple web UI to play with REST calls to your APIs (not to mention that all this metadata is available over REST as well).

Before digging into implementation details, let's take a quick look what Swagger is from API consumer prospective. Assume you have developed a great REST service to manage people. As a good citizen, this REST service is feature-complete and provides following functionality:

  • lists all people (GET)
  • looks up person by e-mail (GET)
  • adds new person (POST)
  • updates existing person (PUT)
  • and finally removes person (DELETE)
Here is the same API from Swagger's perspective:

It looks quite pretty. Let's do more and call our REST service from Swagger UI, here this awesome framework really shines. The most complicated use-case is adding new person (POST) so this one will be looked closely.

As you can see on the snapshot above, every piece of REST service call is there:

  • description of the service
  • relative context path
  • parameters (form / path / query), required or optional
  • HTTP status codes: 201 CREATED and 409 CONFLICT
  • ready to go Try it out! to call REST service immediately (with out-of-the box parameters validation)

To complete the demo part, let me show yet another example, where REST resource is being involved (in our case, it's a simple class Person). Swagger is able to provide its properties and meaningful description together with expected response content type(s).

Looks nice! Moving on to the next part, it's all about implementation details. Swagger supports seamless integration with JAX-RS services, with just couple of additional annotations required on top of existing ones. Firstly, every single JAX-RS service which supposed to be documented should be annotated with @Api annotation, in our case:

@Path( "/people" ) 
@Api( value = "/people", description = "Manage people" )
public class PeopleRestService {
    // ...
}

Next, the same approach is applicable to REST service operations: every method which supposed to be documented should be annotated with @ApiOperation annotation, and optionally with @ApiResponses/@ApiResponse. If it accepts parameters, those should be annotated with @ApiParam annotation. Couple of examples here:

@Produces( { MediaType.APPLICATION_JSON } )
@GET
@ApiOperation( 
    value = "List all people", 
    notes = "List all people using paging", 
    response = Person.class, 
    responseContainer = "List"
)
public Collection< Person > getPeople(  
        @ApiParam( value = "Page to fetch", required = true ) 
        @QueryParam( "page") @DefaultValue( "1" ) final int page ) {
    // ...
}

And another one:

@Produces( { MediaType.APPLICATION_JSON } )
@Path( "/{email}" )
@GET
@ApiOperation( 
    value = "Find person by e-mail", 
    notes = "Find person by e-mail", 
    response = Person.class 
)
@ApiResponses( {
    @ApiResponse( code = 404, message = "Person with such e-mail doesn't exists" )    
} )
public Person getPeople( 
        @ApiParam( value = "E-Mail address to lookup for", required = true ) 
        @PathParam( "email" ) final String email ) {
    // ...
}

REST resource classes (or model classes) require special annotations: @ApiModel and @ApiModelProperty. Here is how our Person class looks like:

@ApiModel( value = "Person", description = "Person resource representation" )
public class Person {
    @ApiModelProperty( value = "Person's first name", required = true ) 
    private String email;
    @ApiModelProperty( value = "Person's e-mail address", required = true ) 
    private String firstName;
    @ApiModelProperty( value = "Person's last name", required = true ) 
    private String lastName;

    // ...
}

The last steps is to plug in Swagger into JAX-RS application. The example I have developed uses Spring Framework, Apache CXF, Swagger UI and embedded Jetty (complete project is available on Github). Integrating Swagger is a matter of adding configuration bean (swaggerConfig), one additional JAX-RS service (apiListingResourceJson) and two JAX-RS providers (resourceListingProvider and apiDeclarationProvider).

package com.example.config;

import java.util.Arrays;

import javax.ws.rs.ext.RuntimeDelegate;

import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.env.Environment;

import com.example.resource.Person;
import com.example.rs.JaxRsApiApplication;
import com.example.rs.PeopleRestService;
import com.example.services.PeopleService;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.wordnik.swagger.jaxrs.config.BeanConfig;
import com.wordnik.swagger.jaxrs.listing.ApiDeclarationProvider;
import com.wordnik.swagger.jaxrs.listing.ApiListingResourceJSON;
import com.wordnik.swagger.jaxrs.listing.ResourceListingProvider;

@Configuration
public class AppConfig {
    public static final String SERVER_PORT = "server.port";
    public static final String SERVER_HOST = "server.host";
    public static final String CONTEXT_PATH = "context.path";  
 
    @Bean( destroyMethod = "shutdown" )
    public SpringBus cxf() {
        return new SpringBus();
    }
 
    @Bean @DependsOn( "cxf" )
    public Server jaxRsServer() {
        JAXRSServerFactoryBean factory = RuntimeDelegate.getInstance().createEndpoint( jaxRsApiApplication(), JAXRSServerFactoryBean.class );
        factory.setServiceBeans( Arrays.< Object >asList( peopleRestService(), apiListingResourceJson() ) );
        factory.setAddress( factory.getAddress() );
        factory.setProviders( Arrays.< Object >asList( jsonProvider(), resourceListingProvider(), apiDeclarationProvider() ) );
        return factory.create();
    }
 
    @Bean @Autowired
    public BeanConfig swaggerConfig( Environment environment ) {
        final BeanConfig config = new BeanConfig();

        config.setVersion( "1.0.0" );
        config.setScan( true );
        config.setResourcePackage( Person.class.getPackage().getName() );
        config.setBasePath( 
            String.format( "http://%s:%s/%s%s",
                environment.getProperty( SERVER_HOST ),
                environment.getProperty( SERVER_PORT ),
                environment.getProperty( CONTEXT_PATH ),
                jaxRsServer().getEndpoint().getEndpointInfo().getAddress() 
            ) 
        );
  
        return config;
    }

    @Bean
    public ApiDeclarationProvider apiDeclarationProvider() {
        return new ApiDeclarationProvider();
    }
 
    @Bean
    public ApiListingResourceJSON apiListingResourceJson() {
        return new ApiListingResourceJSON();
    }
 
    @Bean
    public ResourceListingProvider resourceListingProvider() {
        return new ResourceListingProvider();
    }
 
    @Bean 
    public JaxRsApiApplication jaxRsApiApplication() {
        return new JaxRsApiApplication();
    }
 
    @Bean 
    public PeopleRestService peopleRestService() {
        return new PeopleRestService();
    }
   
    // ... 
}

In order to get rid of any possible hard-coded configuration, all parameters are passed through named properties (SERVER_PORT, SERVER_HOST and CONTEXT_PATH). Swagger exposes additional REST endpoint to provide API documentation, in our case it is accessible at: http://localhost:8080/rest/api/api-docs. It is used by Swagger UI which itself is embedded into final JAR archive and served by Jetty as static web resource.

The final piece of the puzzle is to start embedded Jetty container which glues all those parts together and is encapsulated into Starter class:

package com.example;

import org.apache.cxf.transport.servlet.CXFServlet;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.resource.Resource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;

import com.example.config.AppConfig;

public class Starter {
    private static final int SERVER_PORT = 8080;
    private static final String CONTEXT_PATH = "rest";
 
    public static void main( final String[] args ) throws Exception {
        Resource.setDefaultUseCaches( false );
  
        final Server server = new Server( SERVER_PORT );  
        System.setProperty( AppConfig.SERVER_PORT, Integer.toString( SERVER_PORT ) );
        System.setProperty( AppConfig.SERVER_HOST, "localhost" );
        System.setProperty( AppConfig.CONTEXT_PATH, CONTEXT_PATH );    

        // Configuring Apache CXF servlet and Spring listener  
        final ServletHolder servletHolder = new ServletHolder( new CXFServlet() );      
        final ServletContextHandler context = new ServletContextHandler();   
        context.setContextPath( "/" );
        context.addServlet( servletHolder, "/" + CONTEXT_PATH + "/*" );     
        context.addEventListener( new ContextLoaderListener() ); 
     
        context.setInitParameter( "contextClass", AnnotationConfigWebApplicationContext.class.getName() );
        context.setInitParameter( "contextConfigLocation", AppConfig.class.getName() );
   
        // Configuring Swagger as static web resource
        final ServletHolder swaggerHolder = new ServletHolder( new DefaultServlet() );
        final ServletContextHandler swagger = new ServletContextHandler();
        swagger.setContextPath( "/swagger" );
        swagger.addServlet( swaggerHolder, "/*" );
        swagger.setResourceBase( new ClassPathResource( "/webapp" ).getURI().toString() );

        final HandlerList handlers = new HandlerList();
        handlers.addHandler( context );
        handlers.addHandler( swagger );
   
        server.setHandler( handlers );
        server.start();
        server.join(); 
    }
}

Couple of comments make thing a bit more clear: our JAX-RS services will be available under /rest/* context path while Swagger UI is available under /swagger context path. The one important note concerning Resource.setDefaultUseCaches( false ): because we are serving static web content from JAR file, we have to set this property to false as workaround for this bug.

Now, let's build and run our JAX-RS application by typing:

mvn clean package
java -jar target/jax-rs-2.0-swagger-0.0.1-SNAPSHOT.jar

In a second, Swagger UI should be available in your browser at: http://localhost:8080/swagger/

As a final note, there are a lot more to say about Swagger but I hope this simple example shows the way to make our REST services self-documented and easily consumable with minimal efforts. Many thanks to Wordnik team for that.

Source code is available on Github.

79 comments:

Orest Ivasiv said...

Nice post. Really useful.

Do you have any experience using swagger with REST+security (OAuth, basic, digest, etc.) Does swagger play nice with secured REST APi?

Unknown said...

Great post and finding!

Really useful documentation layer on top of REST layer.

Couple of questions:
* is it possible to export all generated documentation to the company official portal? Or to access the documentation the app should be up and running.
* Does this library knows something about API versioning?

Andriy Redko said...

Hi Orest,

Thank you very much for your comments. Swagger does support the security in some extent as covered in this manual: https://github.com/wordnik/swagger-core/wiki/authorizations (personally, I haven't used this feature yet but it's a very important use case to cover).

Thank you.

Best Regards,
Andriy Redko

Andriy Redko said...

Hi Stan,

Thanks a lot for your comments. Yes, Swagger does have a Maven plugin and can generate API documentation at build time (https://github.com/kongchen/swagger-maven-plugin). With respect to API versioning, Swaggers support API version (https://github.com/wordnik/swagger-core/wiki/API-Declaration) though its usage is somewhat limited and is up to developer.

Thank you.

Best Regards,
Andriy Redko

atgroxx said...

I too tried to use the swagger with camel cxfrx, but was not able to do so.

Have you tried to integrate the Camel cxfrs with Swagger.

If you have could you kindly post the steps ..

Thanks in advance for your help.

Andriy Redko said...

Hi!

Thanks a lot for your comments. Unfortunately, I do not have hands-on experience with Apache Camel and cannot answer your question. However, if you could outline some details about the problem you are having, I might suggest to try something out.

Thank you.

Best Regards,
Andriy Redko

Unknown said...

Excellent post.Really helped me to get started with Swagger.
For the TryitOut button on the SwaggerUI, how do it enable it for https calls?

Thanks,
Rajeev S

Andriy Redko said...

Hi Rajeev,

Thank you very much for your comment. To answer your question, it is quite easy, in class AppConfig, line 54, replace please String.format( "http://%s:%s/%s%s", with String.format( "https://%s:%s/%s%s", (or better just parametrize the protocol as well). Hope it helps!

Thank you!

Best Regards,
Andriy Redko

dhiru said...

Very nice and comprehensive article on using Swagger.

Thanks

herberzt said...

Nice post. I have no experience with creating/deploying/documenting an API. I was wondering if you could help me with intefrating swagger into an Eclipse project that has already been started for me by my internship. They have created a REST Api and they want us to use swagger for documentation/annotation. I am completely lost at what to do. I have done some research, but can't seem to find anything on using it with an eclipse project.

Andriy Redko said...

Hi!

Thanks a lot for your comment. Yeah, sure, I would be happy to help you out. Would you mind to share your project in GitHub so we can work together on Swagger integration?

Thank you!

Best Regards,
Andriy Redko

herberzt said...

Unfortunately I cannot do that. It belongs to a company I am working at for an internship this summer. Im just trying to figure out what files i need to put into my project and where. Even some sort of direction would be appreciated.

Andriy Redko said...

Hi!

Gotcha, no problem. Let me try to guide you through than. So Swagger consist of two parts (as for this blog post concerns): API description and UI (optional). API description part in general depends on what kind of REST framework you are using, could you please hint me with that? Swagger UI is simple, self-contained and could be just pulled from GitHub: https://github.com/swagger-api/swagger-ui. It is a static set of web resources. So I think once we figure out the API part, we can glue everything together. Waiting for your response!

Best Regards,
Andriy Redko

herberzt said...

Yes, I have the swagger files downloaded from GitHub. We are using Jersey and it looks like Spring as well. This is the first time I have ever worked on a web service / servlet, or API so this is all new to me, kinda confused as to what Jersey and Spring does exactly but I can certainly read up on that on my own. If it helps at all I'm using Eclipse to work on the project and it is a DynamicWeb project. The API has already been written, me and my partner just have to go through and annotate the stuff so that we can use the UI for deployment.

Prachetan Anubhuti - Pragna Prachetas said...

hello Andi,
great article , more over it is exactly what i have been looking for.
Ran into a jetty issue while running it. so updated the jetty version to 9.1 to get it working.
Now when I try to look for localhost:8080/swagger i am getting 404. My rest API is just coming fine and the document also. But not sure how to resolve the 404.

Andriy Redko said...

Hi Pragnya,

Thank you very much for your comment. Yes, you are right, I updated Jetty to 9.1+ and there is 404 returned. It seems like the handlers are managed a bit differently by Jetty now, could you please just change the order of handlers in Starter.java like that, instead of:

handlers.addHandler( context );
handlers.addHandler( swagger );


Please change the order to:

handlers.addHandler( swagger );
handlers.addHandler( context );


It should be fine with that. Please let me know if it does not work for you.
Thank you!

Best Regards,
Andriy Redko

Andriy Redko said...

I will try to prepare the Jersey + Swagger example and push it on GitHub so you could use it as a guide. Will keep you posted!

Thanks.

Best Regards,
Andriy Redko

herberzt said...

Andriy,

Thank you, that would be a big help.

Andriy Redko said...

Hi!

I have created a sample, Jersey 2.0 based project branch for you on GitHub: https://github.com/reta/jax-rs-2.0-swagger/tree/jersey-2.0

It is a little bit hard to figure out how exactly you run your application but I hope it will give you a basic idea. The key class is JaxRsApiApplication which extends Jersey's ResourceConfig class and register appropriate Swagger (and JAX-RS beans). Once you run the Starter class in Eclipse, you should be able to open Swagger UI on http://localhost:8080/swagger. Please give it a try and let me know it was helpful or not.

Thank you!

Best Regards,
Andriy Redko

herberzt said...

Andriy,

Thank you I will take a look at it over the next couple of days and get back to you. I appreciate you taking the time to create it.

herberzt said...

Andriy,

Sorry it has taken me a while to get back to you. I have sucessfuly deployed my swagger project and documented two API's. Horray! I was wondering if you know anything about using Basic Auth with swagger-UI? Currently when I hit the "try it out!" button when testing the api I have to login to access the API, I am trying to set it up so that a header is sent so that I don't have to log in everytime. I have looked at the documentation, but everything I have tried so far has been unsucessful.

Thanks again!

Andriy Redko said...

Hi!

Glad to hear you pulled it off! I haven't used Basic Auth with Swagger UI yet, but it seems like it could be added manually (some JavaScript coding required). There is an issue to watch: https://github.com/swagger-api/swagger-ui/issues/764.

Thank you.

Best Regards,
Andriy Redko

Hj said...

Hi,
I'm new to swagger and want to learn it.But i dont know how to get started with it.Please help me with it.
Im interested in swagger with jersey at this link https://github.com/reta/jax-rs-2.0-swagger/tree/jersey-2.0.

If i pull the code form github into eclipse what do i have to do to get it running
Your step by step help is highly appreciated.
Thanks!

Andriy Redko said...

Hi,

Thanks a lot for your interest. It is very easy: once you pull the code to Eclipse, you just right-click on a project, select [Run As] / [Java Application] and select Starter class. That's it, once run, point your browser at http://localhost:8080/swagger/

Thank you!

Best Regards,
Andriy Redko

Hj said...

Hi,
Thanks alot Andriy for your help.When i right click the project i can only see the Run configurations.. option.There is no Run as option.

To be sure i followed correct steps to pull the code to Eclipse,i'm listing the steps i followed followed:

File-> import-> projects from git-> clone URI-> source git repository (under URI pasted the HTTPS clone URL from github)-> branch selection (selected all listed branches ->Local destination..(under directory selected my workspace path) ->import as general project-> project name (jax-rs-2.0-swagger)

Thanks.

Andriy Redko said...

Hi,

Got it, you have two choices here:
- right-click on the project, select [Configure], then [Convert To Maven Project]
- reimport the project as [Check out Maven Projects from SCM], using the same Github repository

Whatever is easier for you.
Thanks.

Best Regards,
Andriy Redko

Hj said...

Hi;

Thanks Andriy for the useful post.I opted for the first choice and its working.

Now i would like to integrate swagger(at https://github.com/reta/jax-rs-2.0-swagger/tree/jersey-2.0)

into my existing jersey2 rest application.For that how do i get started?

Thanks.

Andriy Redko said...

Hi,

You basically need two update your Jersey configuration (see please JaxRsApiApplication class). It is very hard to give you the right advice because there could quite a few ways to create Jersey applications and integrate them with Swagger. If you could share your project @ Github, I would be happy to help you out.

Thank you!

Best Regards,
Andriy Redko

Hj said...

Hi,

I have shared the project on Github at the below URL:
https://github.com/HJ786/TutorialsDesk.git

Thnaks!

Andriy Redko said...

Hi,

Submitted PR: https://github.com/HJ786/TutorialsDesk/pull/1
Please take a look, it is the easiest way to start playing with Swagger and Swagger UI.
Just start with adding more annotations to your Tasks REST service!
Thanks!

Best Regards,
Andriy Redko

Hj said...

Hi,

I did a merge online then pulled the code from github into my project in eclipse.Swagger is still not running at my end on the given URL http://localhost:8080/TutorialsDesk.Rest.CRUDWebServices/swagger-ui/

Thanks.

Hj said...

Hi,
To elaborate my problem i would like to mention that in Eclipse in the git repositories window when i right click the project(TutorialsDesk.Rest.CRUDWebServices) and select pull..it says Nothing to update-eveyrthing uptodate.

In the project explorer,when i right click the project(TutorialsDesk.Rest.CRUDWebServices)and select Run As-> Run on Server(select the server) i cannot see swagger changes integrated to it.

Neither can i see the newly added files nor any changes made to my existing files in my project(TutorialsDesk.Rest.CRUDWebServices)under project explorer or git repositories window.

Your help in this reagrd is highly appreciated.

Thanks.

Andriy Redko said...

Hi,

Please check your repo commit history, https://github.com/HJ786/TutorialsDesk/commits/master. I am not sure exactly what you are trying to do but you merged and reverted the merge at least 2 times. Right now there is no changes from PR in your repo. You may reset your HEAD to this commit: https://github.com/HJ786/TutorialsDesk/commit/40cebd3f60121a734c438e1c6258efe21d21a7d8 (please consult Github documentation how to do that, it is very good).

Thanks.

Best Regards,
Andriy Redko

Hj said...

Hi,
I reset the HEAD to the commit 40cebd3f60121a734c438e1c6258efe21d21a7d.Now i can view all changes(swagger integrated) made to my Tasks REST service.

Thanks alot for your help uptil now!

Now i will start working on adding more annotations to my Tasks REST service.

Thanks.

Andriy Redko said...

Hi,

Awesome, good luck!
Thanks for you comments.

Best Regards,
Andriy Redko

Jess said...

Hi!

I apologize in advance because I'm not too familiar with creating, working with or documenting an API. Is it possible to use Swagger UI to document a REST API that isn't dependent on a framework? The API I'm trying to document is written in C and according to my coworkers was not developed using a framework. I've done research but I can't seem to figure out how or if it's possible to use Swagger UI to document it. Any help would really be appreciated!

Andriy Redko said...

Hi Jess,

Thank you very much for the comment. Essentially, Swagger is just an API description specification (https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md). If your REST API, written in any language, is able to return its own description according to specification, Swagger UI will be happy to show it off! On the other side, I am not aware of any implementation which could generate the API documentation in C (I would suspect it may be not possible as C has no reflection support). However, the one way to dial with that is by manually creating swagger.json file with API description and returning it from your C API (f.e. /api-specs/swagger.json), that will require some work but I do not see another option at the moment. If your API is not changing, that would be one time thing. I hope it will help.

Thank you.

Best Regards,
Andriy Redko

Jess said...

Hi Andriy,

Thanks for the reply and sorry for the slow response! Could you clarify why C having no reflection support would disallow it from generating the documentation?

Thanks!

Andriy Redko said...

Hi Jess,

My apologies for giving you a confusing answer. I would like to disambiguate it a bit: reflection simplifies a lot of things and as such makes certain use cases much simpler to implement. By no means I intended to let you think that "no reflection support would disallow it from generating the documentation", probably more routine work is required.

Thank you.

Best Regards,
Andriy Redko

Hj said...

Hi Andriy,
I tried adding annotations to my application.But i'm getting the blow errors for each operation.

Response Body
Apache Tomcat/7.0.61 - Error report HTTP Status 403 -


Response Code
403

Response Headers
{
"date": "Wed, 05 Aug 2015 21:08:46 GMT",
"server": "Apache-Coyote/1.1",
"content-length": "961",
"content-language": "en",
"content-type": "text/html;charset=utf-8"
}

Please tell me where am i going wrong?
Thanks!

Hj said...

*below

Andriy Redko said...

Hi!

403 usually means forbidden access (authorization).
Did you configure security for your application?
Thanks.

Best Regards,
Andriy Redko

Hj said...

Hi,

I don't think i did that.I would appreciate if you guide me how to do it.

Thanks!

Hj said...

Hi,

In some operations Response Code is 404.

Thanks!

Hj said...
This comment has been removed by the author.
Hj said...

Hi,
Now when i start server i'm getting below error on console

SEVERE: Servlet [Jersey2Config] in web application [/TutorialsDesk.Rest.CRUDWebServices] threw load() exception
java.lang.ClassNotFoundException: io.swagger.jaxrs.config.DefaultJaxrsConfig
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1720)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1571)
at org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:506)
at org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:488)
at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:115)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1148)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1087)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5266)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5554)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1575)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1565)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

In the browser when i type the swagger url id says
Can't read swagger JSON from http://localhost:8080/TutorialsDesk.Rest.CRUDWebServices/rest/swagger.json

Thanks!

Andriy Redko said...

Hi!

Let us move this discussion to your github repo.
Thanks.

Best Regards,
Andriy Redko

Unknown said...

Hello Andriy,

I just cloned the application, imported it to eclipse and running it has java application with pointing starter class, when i use localhost:808/swagger/ i cannot see anything. web page is empty with just swagger icon on it. Do i need to make any other changes to run this application.

Andriy Redko said...

Hello Swagath,

Thanks for your comment. No, you are not supposed to make any changes to have application working. Could you please check the Eclipse console for possible errors. Also, could you please run curl http://localhost:8080/rest/api/api-docs to check if API description is properly returned?

Thank you.

Best Regards,
Andriy Redko

Unknown said...

Hi Andriy,

After entering url, i can see the below warning on eclipse console,


WARN] 2015-09-01 13:10:32.166 org.eclipse.jetty.io.SelectorManager - [] Could not process key for channel java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:53149]
java.lang.IllegalStateException: AsyncContext completed
at org.eclipse.jetty.server.AsyncContextState.state(AsyncContextState.java:45) ~[jetty-server-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.server.AsyncContextState.complete(AsyncContextState.java:90) ~[jetty-server-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.servlet.DefaultServlet$1.failed(DefaultServlet.java:880) ~[jetty-servlet-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.util.IteratingCallback.failed(IteratingCallback.java:108) ~[jetty-util-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.server.HttpOutput$ReadableByteChannelWritingCB.failed(HttpOutput.java:591) ~[jetty-server-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.util.IteratingCallback.iterate(IteratingCallback.java:89) ~[jetty-util-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.util.IteratingCallback.succeeded(IteratingCallback.java:102) ~[jetty-util-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.io.WriteFlusher$PendingState.complete(WriteFlusher.java:265) ~[jetty-io-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.io.WriteFlusher.completeWrite(WriteFlusher.java:420) ~[jetty-io-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.io.SelectChannelEndPoint.onSelected(SelectChannelEndPoint.java:111) ~[jetty-io-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.io.SelectorManager$ManagedSelector.processKey(SelectorManager.java:498) [jetty-io-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.io.SelectorManager$ManagedSelector.select(SelectorManager.java:455) [jetty-io-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.io.SelectorManager$ManagedSelector.run(SelectorManager.java:420) [jetty-io-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:601) [jetty-util-9.0.5.v20130815.jar:9.0.5.v20130815]
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:532) [jetty-util-9.0.5.v20130815.jar:9.0.5.v20130815]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_51]
[WARN] 2015-09-01 13:10:32.166 org.eclipse.jetty.io.SelectorManager - [] Could not process key for channel java.nio.channels.SocketChannel[connected local=/0:0:0:0:0:0:0:1:8080 remote=/0:0:0:0:0:0:0:1:53150]
java.lang.IllegalStateException: AsyncContext completed



curl http://localhost/rest/api/api-docs gave me below output
C:\>curl http://localhost:8080/rest/api/api-docs
{"apiVersion":"1.0.0","swaggerVersion":"1.2","apis":[{"path":"/people","descript
ion":"Manage people"}]}


Thanks,

Regards,
swagath

Andriy Redko said...

Hi Swagath,

Thanks a bunch for such a great details. It seems like you have run into Jetty bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=418871). Could you please try to update the Jetty version in pom.xml from

<org.eclipse.jetty.version>9.0.5.v20130815</org.eclipse.jetty.version>

to

<org.eclipse.jetty.version>9.2.11.v20150529</org.eclipse.jetty.version>

Thank you.

Best Regards,
Andriy Redko

Unknown said...

Hi Andriy,

Thanks for your reply.

I made a changes as you said in pom file. Now i am geting Page not found error(404)

Problem accessing /swagger/. Reason:

Not Found
Powered by Jetty://


Thanks,

Regards,
Swagath

Andriy Redko said...

Hi Swagath,

My apologies, I should have been committed the fix to Github myself. Could you please pull latest master from Github? It should work as expected.

Thank you!

Best Regards,
Andriy Redko

Unknown said...

Hi Andriy,

Thanks a lot. It's working fine now.


Regards,
Swagath

Unknown said...

Hello Andriy,

Could you suggest me some document or blog if any to learn about swagger from the scratch. I just thinking of doing some simple project to understand these concepts more clearly. but i don't have idea about from where i should start.

So it will be very helpfull, if you could give some directions.

Thanks,

Regards,
Swagath

Andriy Redko said...

Hi Swagath,

As for me, Swagger's Wiki (https://github.com/swagger-api/swagger-core/wiki) is the best source of documentation and samples. In particular, those sections https://github.com/swagger-api/swagger-core/wiki/Annotations, https://github.com/swagger-api/swagger-core/wiki/Java-CXF-Quickstart, https://github.com/swagger-api/swagger-core/wiki/Java-Integrations are very helpful.

Good luck with building great APIs!
Thanks!

Best Regards,
Andriy Redko

Unknown said...

Hi Andriy,
That was a full fledged example! Followed this and was able to do this successfully. However, I want to know one more thing:
If you see petstore example on Swagger UI website (http://petstore.swagger.io/#/, go to pet, then go to Add new pet to the store.), there is a feature in which data Type of a parameter is Model Schema and it is displayed just like the Response class in your example. BUt, if you left click it, the JSON format of the class gets copied to the parameter input value! I just want to know how does this works?
Thanks a lot! :)

Anmol.

Andriy Redko said...

Hi Anmol,

Thank you for your comment! Yeah, thanks to Swagger, it is very easy to do. There are actually two ways:
1. Annotating the parameter itself, f.e. @ApiParam(value = "person") Person person
2. Using @ApiImplicitParam / @ApiImplicitParams

In this case, when API parameter is a complex entity (usually passed as HTTP call payload), Swagger UI is going to show its JSON representation, same way you saw it on petstore example. Hope it answers your question!

Thanks!

Best Regards,
Andriy Redko

Unknown said...

Hi Andriy,
Thanks for the quick answer. Actually I am using Swagger in Groovy Grails. The version of swagger I am using is 1.3.8. I have tried it using @ApiImplicitParam. But it doesnt work. It works only when I write response= ABC.CLASS in @ApiOperation, and then write in @ApiImplicitParam(dataType="ABC"). This solves the problem but is impractical, because response class model schema is also displayed on the screen alongwith data type model schema, which is not good. I think I have to update Swagger to 1.5 since I have found a bug in the previous version. (https://github.com/swagger-api/swagger-core/issues/1149).

Cheers!
Anmol

Andriy Redko said...

Hi Anmol,

Yeah, @ApiImplicitParam needs dataType to be provided as a fully qualified class name. Nevertheless, upgrading to 1.5 is a great idea, it seems like 1.3 won't evolve anymore. Should be very straightforward (the project on Github for this post has a branch for Swagger 1.5 as well, could be helpful for you).

Thanks!

Best Regards,
Andriy Redko

JT said...

How do we use this if the project is not Maven based? Also what if it is not JAXRS based REST implementation?

Thanks for any prompt answer! Great work!

Andriy Redko said...

Hey JT,

Thanks for the comment! If the project is not Maven-based, you just need to find a way to include Swagger JAR files into the build / classpath (for SBT or Gradle it is as straightforward as just adding dependencies into your build files).

By not JAX-RS based project I mean f.e. just use pure Java servlets or Play! Framework integration, those are not implementations conformant with JAX-RS but Swagger supports it.

Hope it helps!
Thanks!

Best Regards,
Andriy Redko

Unknown said...

Hi All,

Am trying swagger tool integration with restful using Apache CXF with out springs, maven.

Can anyone provide some information on this.

Thanks in advance.

Andriy Redko said...

Hi Jaya,

Sure, please take a look on example projects:

https://github.com/apache/cxf/tree/master/distribution/src/main/release/samples/jax_rs/description_swagger2

https://github.com/apache/cxf/tree/master/distribution/src/main/release/samples/jax_rs/description_swagger2_web

Those are basic examples of Swagger integration with Apache CXF without Spring (however you are going to need Maven to build them). Please let me know if this is what you are looking for.

Thanks.

Best Regards,
Andriy Redko

Unknown said...

Hi Andriy,

Thanks for the quick reply.

I have developed RESTful web service using CXFNonSpringJaxrsServlet and trying to integrate swagger for the same. Can't we build it with out maven.

Regards,
Jaya Reddy

Unknown said...

Hi Andriy,

The links suggested by you still contains some spring related dependencies in web.xml.

CXF Swagger2 Spring Sample

contextConfigLocation
WEB-INF/context.xml


org.springframework.web.context.ContextLoaderListener


I am using pure CXFNonSpringJaxrsServlet for restful web service to integrate swagger.

Any help greatly appreciated.

Andriy Redko said...

Hi Jaya,

Yeah, you right, description_swagger2_web still contains Spring dependencies. Please use https://github.com/apache/cxf/tree/master/distribution/src/main/release/samples/jax_rs/description_swagger2, there is no Spring here but Maven is required for build. CXFNonSpringJaxrsServlet is the good one to use. If you want to get rid of Maven, you still have to have build process in place (other build tools or scripts). I am not sure what is your choice here.

Thanks.

Best Regards,
Andriy Redko

Unknown said...
This comment has been removed by the author.
Unknown said...

Hi Andriy,

Am using the ant build and below jars for my project.
---------------------
activation-1.1.jar
asm-3.1.jar
cxf-2.7.18.jar
FastInfoset-1.2.2.jar
httpasyncclient-4.0-beta3.jar
httpclient-4.2.5.jar
httpcore-4.2.4.jar
httpcore-nio-4.2.4.jar
javassist-3.19.0-GA.jar
javax.ws.rs-api-2.0-m10.jar
jdom-1.0.jar
jettison-1.3.7.jar
junit-4.10.jar
log4j-api-2.4.1.jar
log4j-core-2.4.1.jar
log4j-slf4j-impl-2.1.jar
mail-1.4.jar
mockito-all-1.10.19.jar
neethi-3.0.3.jar
org-apache-commons-lang.jar
org.apache.servicemix.bundles.swagger-jaxrs-1.3.12_2.jar
org.json.jar
powermock-mockito-1.6.2-full.jar
reflections-0.9.5.jar
rome-0.9.jar
scala-library-2.10.0-rc1.jar
slf4j.api-1.6.1.jar
stax-api-1.0-2.jar
swagger-annotations_2.10.0-1.2.0.jar
swagger-core_2.10-1.3.12.jar
swagger-jaxrs_2.10-1.3.0.jar
wsdl4j-1.6.3.jar
xmlschema-core-2.1.0.jar
---------------------------

Unknown said...

and also
the web.xml is as below.
----------------------------



CXFNonSpringJaxrsServlet
org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet

jaxrs.serviceClasses

com.xxx.xxx.rest.SwaggerResourceClass,
com.wordnik.swagger.jaxrs.listing.ApiListingResourceJSON



jaxrs.features
org.apache.cxf.jaxrs.swagger.SwaggerFeature


swagger.api.version
2.10.0


swagger.api.basepath
http://localhost:8080/swagger/rest/api_docs/


jaxrs.resources

com.wordnik.swagger.jaxrs.listing.ApiListingResourceJSON



jaxrs.providers

org.apache.cxf.jaxrs.provider.json.JSONProvider(dropRootElement=true supportUnwrapped=true)



jaxrs.providers

com.wordnik.swagger.jaxrs.json.JacksonJsonProvider,
com.wordnik.swagger.jaxrs.listing.ApiDeclarationProvider,
com.wordnik.swagger.jaxrs.listing.ResourceListingProvider



jaxrs.interceptors
org.apache.cxf.jaxrs.interceptor.AttachmentInputInterceptor


jaxrs.interceptors
org.apache.cxf.jaxrs.interceptor.AttachmentOutputInterceptor

1



CXFNonSpringJaxrsServlet
/rest/*



jaxrs.scan
true


defaultJaxrsConfig
com.wordnik.swagger.jaxrs.config.DefaultJaxrsConfig
2


---------------------------------

Andriy Redko said...

Hi Jaya,

Could you please share your complete project over Github?
Thanks.

Best Regards,
Andriy Redko

Unknown said...

Thanks for the Quick reply,

You can find my code at the below URL:https://github.com/JayachandraReddy/Swagger_Project

Please let me know where exactly am missing it???

Regards,
Jaya Reddy.

Unknown said...

Hi Andriy,

Awaiting for your reply.

Thanks & Regards,
Jaya Reddy

Andriy Redko said...

Hi Jaya,

Please check issues on your Github project: https://github.com/JayachandraReddy/Swagger_Project
Thanks.

Best Regards,
Andriy Redko

Unknown said...

Hi Andriy,

Thank you for the suggetions, will work on it.

Regards,
Jayachandra Reddy K

Unknown said...

Hi Andriy,

we are able to do swagger integration using both spring and non-spring frame work.

Thanks,
Jayachandra Reddy K.

Andriy Redko said...

Hi Jaya,

That's great news, I am glad you pulled it off!
Thanks!

Best Regards,
Andriy Redko

javafaqs said...

Hi Andriy,

I am new to swagger tool. Could you please provide the sample code(running code) jersy with swagger(without spring)
and provide steps how to import to Eclipse(Mars).

Thanks,
Jagadeesh.T

Andriy Redko said...

Hi Jagadeesh,

Thanks a lot for your comment. Swagger has excellent documentation regarding integration with Jersey, please take a look on it: https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-Jersey-2.X-Project-Setup-1.5

Most of the projects are Maven based, so you just do File -> Import -> Existing Maven project in Eclipse and you are good to go.

Certainly, I would be more than happy to help you out if you encounter some issues along the way.

Thank you.

Best Regards,
Andriy Redko