Blog

- January 04, 2016

In the first part of this article, we described the key features of APISpark connectors and what they can bring to existing Web APIs. We will focus here on how to plug existing Web APIs written with Restlet Framework on the platform.

Getting Swagger definition from Restlet Framework applications

As we saw, creating the Swagger definition of your Web API is a task still on your hands. Thankfully, Restlet Framework provides a Swagger integration to facilitate this.

Restlet Framework application

To implement and build the Restlet Framework sample application, we will take advantage of Maven. For this purpose, we need to create a pom.xml file and configure all the required dependencies for Restlet:

<project xmlns="http://maven.apache.org/POM/4.0.0" 
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                                        http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.restlet.sample</groupId>
  <artifactId>my-webapi-with-restlet</artifactId>
  <name>${project.artifactId}</name>
  <version>1.0.0-snapshot</version>

  <properties>
    <java-version>1.7</java-version>
    <restlet-version>2.3.5</restlet-version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.restlet.jse</groupId>
      <artifactId>org.restlet</artifactId>
      <version>${restlet-version}</version>
    </dependency>

    <dependency>
      <groupId>org.restlet.jse</groupId>
      <artifactId>org.restlet.ext.jackson</artifactId>
      <version>${restlet-version}</version>
    </dependency>

    <dependency>
      <groupId>org.restlet.jse</groupId>
      <artifactId>org.restlet.ext.jetty</artifactId>
      <version>${restlet-version}</version>
    </dependency>

  </dependencies>

  <repositories>
    <repository>
      <id>maven-restlet</id>
      <name>Public online Restlet repository</name>
      <url>http://maven.restlet.com</url>
    </repository>
  </repositories>
</project>

The core element of a Restlet Framework application consists of the class that extends the Application class and defines the various available resources. We’ll create a router and attach resource classes for specific paths. The following snippet describes the content of this class:

public class ContactsApplication extends Application {
    public Restlet createInboundRoot() {
        Router router = new Router();

        router.attach("/contacts/", ContactsServerResource.class);
        router.attach("/contacts/{id}", ContactServerResource.class);

        return router;
    }

    public String toString() {
        return "Contact manager";
    }
}

Below is a sample content for the ContactsServerResource class:

public class ContactsServerResource extends ServerResource {
    @Get
    public List getContacts() {
	    List contacts = new ArrayList<>();
	    Contact contact = new Contact();
	    contacts.add(contact);
	    return contacts;
    }

    (...)
}

These server resources leverage some classes for holding data: Contact for the contacts and Company for the companies. These classes are described below:

public class Contact {
    private String id;
    private String firstName;
    private String lastName;
    private Company company;

    // Getters and setters
    // ...
}

public class Company {
    private String id;
    private String name;

    // Getters and setters
    // ...
}

To launch the application in a standalone mode, simply create a component, configure it for HTTP and attach the previous application to it. When the component is started, the application is available at http://localhost:8182.

Now let’s implement this component:

Component component = new Component();
component.getServers().add(Protocol.HTTP, 8182);

ContactsApplication application = new ContactsApplication();
component.getDefaultHost().attachDefault(application);

component.start();

We defined a sample application. Let’s extend it to make its Swagger definition available.

Using the Swagger extension

The first way consists of using the Restlet Framework’s own Swagger extension. This extension is part of the Restlet Framework distribution but you can also leverage Maven to bring it into your application. Below is a sample configuration within a Maven pom.xml file with the org.restlet.ext.swagger dependency:

<project xmlns="http://maven.apache.org/POM/4.0.0" 
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                                        http://maven.apache.org/xsd/maven-4.0.0.xsd">
  (...)

  <dependencies>
    (...)
        <dependency>
      <groupId>org.restlet.jse</groupId>
      <artifactId>org.restlet.ext.swagger</artifactId>
      <version>${restlet-version}</version>
        <exclusions>
          <exclusion>
            <groupId>org.raml</groupId>
            <artifactId>raml-parser</artifactId>
          </exclusion>
        </exclusions>
    </dependency>
  </dependencies>

  (...)
</project>

Now that you get the extension in your application, you can configure your application to return Swagger content. This extension supports two different versions of Swagger (1.2 and 2.0).

Within the Restlet Framework application class, you can now extend the SwaggerApplication class instead of the Application one. In this case, you will be able to use the attachSwaggerSpecificationRestlet method to attach resources to serve Swagger content. Restlet will automatically instrospect your application and find out the contract of your application. This contract will then be used to generate the corresponding Swagger content.

The following sample describes how to configure Swagger support in your Restlet Framework application class:

public class ContactsApplication extends SwaggerApplication {
    public Restlet createInboundRoot() {
        Router router = new Router();
        (...)
        attachSwaggerSpecificationRestlet(router, "/docs");

        return router;
    }
}

The Swagger content of the resource listing can now be reached on the /docs path. Here is what you will get when calling the /docs path with DHC:

swagger1.2-resource-listing

As you can see, we have the /contacts category. If you call the /docs/contacts path , you will see the details of corresponding operations, as described below:

swagger1.2-resource-contacts

You can see that the Restlet Framework introspection is really neat since path parameters are also detected.

getContactOperation

Input and output parameters of Java methods are also introspected to find out structures of exchanged messages, as described below:

swager1.2-models

The Swagger extension also gives you the ability to extend the default behavior to plug your own content for both resource listing and resources. The following code describes how to implement this by overriding the getSwaggerSpecificationRestlet method within your Restlet application class.

public class ContactsApplication extends SwaggerApplication {
    @Override
    public SwaggerSpecificationRestlet getSwaggerSpecificationRestlet(
            Context context) {
        return new SwaggerSpecificationRestlet(getContext()) {
            @Override
            public Representation getApiDeclaration(String category) {
                JacksonRepresentation result
                              = new JacksonRepresentation(
                        new FileRepresentation("/path/to/my/repo/" + category,
                                MediaType.APPLICATION_JSON),
                        ApiDeclaration.class);
                return result;
            }

            @Override
            public Representation getResourceListing() {
                JacksonRepresentation result
                              = new JacksonRepresentation(
                        new FileRepresentation("/path/to/my/repo/api-docs",
                                MediaType.APPLICATION_JSON),
                        ApiDeclaration.class);
                return result;
            }
        };
    }

    (...)
}

Support for Swagger 2.0

The Swagger extension of Restlet also supports version 2.0 of the specification. The support of Swagger 2.0 in Restlet Framework is based on the Swagger2SpecificationRestlet class.

public class ContactsApplication extends Application {

    public Restlet createInboundRoot() {
        Router router = new Router();
        (...)
        Swagger2SpecificationRestlet swagger2SpecificationRestlet
                               = new Swagger2SpecificationRestlet(this);
        swagger2SpecificationRestlet.setBasePath("http://myapp.org/");
        swagger2SpecificationRestlet.attach(router, "/docs");
        return router;
    }
}

Like with Swagger 1.2, resources, methods and path parameters are also detected:

swagger2-paths

Input and output parameters of Java methods are also introspected to find out structures of exchanged messages, as described below:

swagger2-definitions

Now we have the Swagger content for our RESTful service, we can leverage this to configure a connector. You can refer to the previous section “Leveraging Swagger definitions”.

The Restlet Framework introspector

As we mentioned earlier, APISpark also provides a built-in tool, the introspector, to introspect your application and automatically create and configure the Connector for a Restlet Framework based application. This tool is usable directly from the command line.

For more details, you can have a look at the corresponding documentation.

Conclusion

APISpark provides a built-in support to enhance easily your existing Web APIs with additional services like call monitoring, analytics and rate limitations out of the box. This support is based on the Connector feature that can be configured using a definition of your Web APIs based on the Swagger format.

In this post, we described how to manage a RESTful service written in Java with the Restlet Framework. We will see in further posts that this feature isn’t dependant on a particular technology. The only thing is to be able to provide a Swagger or RAML definition describing the contract of your services.