[Tutorial] How To Turn A Cool Idea Into A Business API with the WSO2 Platform
- By Sanjeewa Malalgoda
- |
- 14 Mar, 2016
In this tutorial we will design a REST API from scratch using the contract first approach. First, we will write a service definition using Swagger API definition language. Next we will create a web application from that service and deploy it as a service. Thereafter, we will try to invoke the service and use it.
Once you have the web service up and running you can create an API for that service. You can then expose your RESTful web service as a business API. When you deploy the service as a business API you can add some QoS to your API (such as throttling, usage monitoring, etc.).
After following this tutorial you can learn how to develop a complete business API and expose it to the outside world with minimum coding knowledge. If you’re not familiar with the WSO2 product stack or Java web development you can still follow the steps in this tutorial.
Prerequisites
What is Swagger?
According the Swagger official web page, the goal of Swagger is to define a standard, language-agnostic interface to REST APIs that allow both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined via Swagger, a consumer can understand and interact with the remote service with a minimal amount of implementation logic. Similar to what interfaces have done for lower-level programming, Swagger removes the guesswork in calling the service. With swagger, you can define REST API interfaces. The following is a very simple API.
swagger: "2.0" info: version: "1.0" title: "Hello World API" paths: /hello/{user}: get: description: Returns a greeting to the user! parameters: - name: user in: path type: string required: true description: The name of the user to greet. responses: 200: description: Returns the greeting. schema: type: string 400: description: Invalid characters in "user" were provided.
In the example above we describe a simple Hello World API. It has a single URL exposed – /hello/{user}
. user
is the single parameter to the API, defined as part of the path and we say it’s a string. We also describe the successful response and mention that it’s a string as well. A generic 400 error will be received if the user
contains invalid characters. You can also see that throughout the operation itself we have provided additional documentation. Therefore, with these steps, you can write a complete API definition in self descriptive manner.
Refer to this document for more details: https://swagger.io/getting-started-with-swagger-i-what-is-swagger/.
Create your service definition
In this step we will be defining a contract for the API interface that will be referred to as the API definition. We use open API specification, formally known as Swagger, to document the API definition.
You can use tools like SwaggerEditor to help you document the API definition in open API spec. To document the APIM Store and Publisher APIs we have used the Swagger YAML format.
Let's consider a simple use case; you’re free to come up with your ideas too. Here, you need to expose the service to external users to find nearby shops based on their geolocation. For this service, we would need geolocation as the input for users and, in response, it will return all shops around the user as shop object array. In addition, you would need to expose the service to obtain quotations for items you’d need to purchase. For this, you need to pass the item name and, in response, you will receive a quotation object.
In our sample service we will have an API with 2 resources.
The first resource is /shops
. This resource supports the HTTP get method and you need to pass your geolocation as query parameters. It will then look for shops around you and return an array of shops.
You can start the service definition as follows:
paths: /shops: get: summary: Shops available
The second resource is /estimates/price
. This resource will return your estimated price for the product you pass to the API. You need to pass the product name as a query parameter.
The service definition can be started with the following:
/estimates/price: get: summary: Price Estimates
In the attached zip file you will find the project source code. It has an API definition as a YAML file, a pom file to build the project, and meta information required to build the web application. To see complete service definition you can go to src/main/resources/api.yaml
file and open it using any text editor software.
Creating JAX-RS project
Next we will generate a service skeleton from the API definition that has been created already. We will be using Apache CXF implementation of Java API for RESTful web services. You can use the following guide to setup a basic JAX-RS service: https://cxf.apache.org/docs/jax-rs-maven-plugins.html
To generate a service skeleton from the API definition we will use Swagger for CXF plugin, but first you need to check it out and build it. Check out the following code and build it: https://github.com/hevayo/swagger2cxf-maven-plugin.git
Once you go to this git location you can download the source code then go to the root of that directory and type mvn clean install
. Then it will build the project and the JAR file will be installed to your local Maven repo. When you build your code you can use this plugin.
Server stub generation
First you need to include the API definition inside the Maven project; an ideal place to include it is under src/main/resources/api.yaml
.
Add the following plugin to the project. Now we are going to use the previously built Swagger to CXF plugin to generate the service skeleton. To do that we need to add the following plugin definition to the pom file. You can find the complete pom file in the root level of the code sample directory that has been provided.
<plugin> <groupId>org.wso2.maven.plugins</groupId> <artifactId>swagger2cxf-maven-plugin</artifactId> <version>1.0-SNAPSHOT</version> <configuration> <inputSpec>${project.basedir}/src/main/resources/api.yaml</inputSpec> </configuration> </plugin>
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>1.9.1</version> <executions> <execution> <id>add-source</id> <phase>generate-sources</phase> <goals> <goal>add-source</goal> </goals> <configuration> <sources> <source>src/gen/java</source> </sources> </configuration> </execution> </executions> </plugin>
Since we have provided the project with the pom file and the api.yaml
file you can build it from there. Here is the content of the project we have provided.

As you can see we have the pom file and the api.yaml
files in project space. Moreover, since we need to build a web application with this we need to add some other classes to the webapp directory as well.
Once you have followed the above steps (these plugins have been already added to the sample we’ve provided) you may generate the code with the following command.
Now let’s use the mvn swagger2cxf:generate
command and generate the server stub.
The generated code will be at src/gen/java
so we need to add this to the build which can be done via the Maven build helper plugin. You will see the gen directory and impl directory created with some classes.

After the above step, we have all the classes that are required to implement our business logic. The following is an auto generated class for shops API. Now we can implement logic to get shops based on geolocation and return them as shops array.
For this sample implementation we will not be using any complex logic. We will only create a simple object and return it as follows:
public class ShopsApiServiceImpl extends ShopsApiService { @Override public Response shopsGet(Double latitude,Double longitude){ // do some magic! return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build(); } }
Replace shopsGet
method with following:
public Response shopsGet(Double latitude,Double longitude){ // do some magic! ShopDTO shopDTO = new ShopDTO(); shopDTO.setFirstName("owner"); shopDTO.setEmail("[email protected]"); shopDTO.setShopName("Cake Shop"); shopDTO.setLastName("Owner"); return Response.ok().entity(shopDTO).build(); }
In the same way, the estimate API will be created as follows and you can implement your logic there.
public class EstimatesApiServiceImpl extends EstimatesApiService { @Override public Response estimatesPriceGet(String productName){ // do some magic! return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build(); } }
Replace estimatesPriceGet
method with following:
public Response estimatesPriceGet(String productName){ // do some magic! PriceEstimateDTO priceEstimateDTO = new PriceEstimateDTO(); priceEstimateDTO.setDisplayName(productName); priceEstimateDTO.setProductId("123"); priceEstimateDTO.setCurrencyCode("USD"); priceEstimateDTO.setHighEstimate(BigDecimal.valueOf(12)); priceEstimateDTO.setLowEstimate(BigDecimal.valueOf(8)); priceEstimateDTO.setEstimate(String.valueOf(10)); return Response.ok().entity(priceEstimateDTO).build(); }
Configuring API context
In Tomcat and application server the war name is used as context of the web app. Furthermore, you can use # to add sub context to a web app. Refer to Tomcat Naming Convention. We will use this feature to define the context of our API.
Ex. Your sample API context will be /con/test/v1
then, corresponding war for the above context should be con#test#v1.war
. As you can see this will allow you to have multiple versions of the API Ex.
To generate a war with the above naming convention use maven-war-plugin with the following configuration:
<plugin> <artifactId>maven-war-plugin</artifactId> <version>2.2</version> <configuration> <webResources> <resource> <directory>src/main/webapp</directory> </resource> </webResources> <warName>con#test#v1</warName> </configuration> </plugin>
Now we have completed all coding required for this web application and we can build this web app and export as .war file. To do so, go to the provided project root and run the following command.
> mvn clean install
Then it will build a whole project and create a web application war file.
Now we can deploy our service in any web application server (for this you can use WSO2 API Manager or WSO2 Application Server as both come with app hosting capabilities). You can use the management console or directly copy the application to the server web apps directory. You may find more information in this article.
Otherwise, you can copy the web application to a web apps directory of the running server using the following command:
> cp target/con#test#v1.war /home/sanjeewa/work/packs/APIM/wso2am-1.9.0/repository/deployment/server/webapps/
If the server is successfully deployed you will see the below logs in the console.
[2016-02-12 19:03:24,871] INFO - ServerImpl Setting the server's publish address to be / [2016-02-12 19:03:24,950] INFO - TomcatGenericWebappsDeployer Deployed webapp: StandardEngine[Catalina].StandardHost[localhost].StandardContext[/con/test/v1].File[/home/sanjeewa/work/packs/APIM/wso2am-1.9.0/repository/deployment/server/webapps/con#test#v1.war]
To see the service definition of a deployed server you may go to the following URL by clicking it on the browser.
https://127.0.0.1:9763/con/test/v1/?_wadl
WSDL content
<?xml version="1.0" encoding="UTF-8"?> <application> <grammars /> <resources base="https://10.100.1.65:9763/con/test/v1/"> <resource path="/shops"> <method name="GET"> <request> <param name="latitude" style="query" type="xs:double" /> <param name="longitude" style="query" type="xs:double" /> </request> <response> <representation mediaType="application/json" /> </response> </method> </resource> <resource path="/estimates"> <resource path="/price"> <method name="GET"> <request> <param name="product_name" style="query" type="xs:string" /> </request> <response> <representation mediaType="application/json" /> </response> </method> </resource> </resource> </resources> </application>
To access the deployed service you may type the following curl command and invoke the service.
>curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET https://127.0.0.1:9763/con/test/v1/shops?latitude=6.931944&longitude=79.847778
HTTP/1.1 200 OK Date: Fri, 12 Feb 2016 14:37:01 GMT Content-Type: application/json Transfer-Encoding: chunked Server: WSO2 Carbon Server {"email":"[email protected]", "shopName":"Cake Shop","firstName":"owner", "coordinateLong":null,"picture":null, "promoCode":null,"coordinateLat":null, "lastName":"Owner"}
>curl -i -H "Accept: application/json" -X GET https://127.0.0.1:9763/con/test/v1/estimates/price?product_name=cake
HTTP/1.1 200 OK Date: Fri, 12 Feb 2016 14:35:53 GMT Content-Type: application/json Transfer-Encoding: chunked Server: WSO2 Carbon Server {"productId":"123","estimate":"10","lowEstimate":8, "highEstimate":12,"surgeMultiplier":null, "currencyCode":"USD","displayName":"cake"}
Expose your service as a business API
Now given that your service has been deployed successfully let's create an API with the service that has been created. Go to API Publisher and create the API with Swagger created already. For this we can use the ‘create API from Swagger’ option.

Figure 1
Provide service URL when you create the API.
https://127.0.0.1:9763/con/test/v1

Figure 2
Follow final steps and publish the API.

Figure 3
Now go to the API Store and navigate to the API that has been created and subscribe to it. Then you will be able to invoke it with the Swagger UI as shown below. The same way you may expose this as a business API and earn some revenue based on API usages. Moreover, you may apply different QoS (such as authentication, throttling, usage, and metering) to your service.

Figure 4