Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Web App Next Stop In Our Software Journey - REST Services: Part II

DZone's Guide to

Web App Next Stop In Our Software Journey - REST Services: Part II

We want to expose the remaining operations, handle JSON, and take a look at making our service follow RESTful principles as best as possible.

· Integration Zone
Free Resource

Build APIs from SQL and NoSQL or Salesforce data sources in seconds. Read the Creating REST APIs white paper, brought to you in partnership with CA Technologies.

Welcome back. We continue where we left off in Part 1. We have established a basic working REST service that exposes the internal Shape Calculator. If you have not been following along, you can view all of the articles here.

Up until now, we have exposed only one of the operations, and it only produces XML. We want to expose the remaining operations, and we want to handle JSON as well. We also want to take a look at making our service follow RESTful principles as best as possible.

Here is a nice article on that topic.

Let's Get Started

Our focal point now is the service interface (SEI), the com.eli.calc.shape.service.ws.ShapeCalculatorWebSerivce.

We already have one operation done, this one:

    @GET
    @Path("/pending")
    PendingRequestsResponse getPendingRequests();

According to the principles, looks like we did that one correctly. We  GET /pending. Makes sense.

Let's move on to an interesting operation; this one requires parameters. Further, since we are maintaining the same interface as the previous SOAP project, then our discrete parameters are wrapped inside an object (QueueCalculationParms).

First, let's view the complete interface currently:

package com.eli.calc.shape.service.ws;

    // .....imports here....

@Produces(MediaType.APPLICATION_XML)
public interface ShapeCalculatorWebService {

    StatusResponse deletePendingRequests();

    StatusResponse deleteResults();

    StatusResponse queueCalculation(QueueCalculationParms parameters);

    @GET
    @Path("/pending")
    PendingRequestsResponse getPendingRequests();

    CalculatedResultsResponse getCalculatedResults();

    RunPendingRequestsResponse runPendingRequestsStopOnError();

    RunPendingRequestsResponse runPendingRequestsNoStopOnError();

}

New Operation

We are going to add to work on the queueCalculation(...). So, let's add this:

    /**
     * Since executing this operation results in a pending request,
     * let's use the same /pending endpoint.
     * 
     * @param parameters
     * @return StatusReponse
     */
    @PUT
    @Path("/pending")
    StatusResponse queueCalculation(QueueCalculationParms parameters);

POST vs PUT

Why choose @PUT ?

Image title

The calculator's queueCalculation() operation is not guaranteed to create a new pending request. If the calculator's database already has a pending request for the same parameters or if there is a calculation result (every calculation result contains the request parameters that it used in the calculation) related to those parameters, then no new pending request is queued.

While we are looking at what HTTP verbs to use, let's do all of the operations.

@DELETE
@Path("/pending")
StatusResponse deletePendingRequests();

@GET
@Path("/pending")
PendingRequestsResponse getPendingRequests();

@POST
@Path("/pending")
StatusResponse queueCalculation(QueueCalculationParms parameters);

@GET
@Path("/results")
CalculatedResultsResponse getCalculatedResults();

@DELETE
@Path("/results")
StatusResponse deleteResults();


RunPendingRequestsResponse runPendingRequestsStopOnError();

RunPendingRequestsResponse runPendingRequestsNoStopOnError();

We have to decide what to do with the runoperations.

Invoking either of them takes any pending requests and runs the calculations, creating a calculated result.  We could use  @POST, however, we are not really passing any parameters, and we are not even in control of which resource is being calculated or created. These last two operations are more of a notification to the calculator to do its thing.

Here are the HTTP method definitions. Based on those, I think that it has to be either @POST or  @PUT.

9.1.2 Idempotent Methods

Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. The methods GET, HEAD, PUT, and DELETE share this property. The run operations definitely do not meet the above criteria.

Since @PUT is like a create-or-update, we'll go with it.

And This Is Where We Introduce A WADL

We could use curl to attempt to test the new operation, but I want to use SOAPUI. I want to make it as easy as I can on myself, and as much information as I can get, so let's take a look at generating a WADL.

(You don't have to do this; there are those who eschew this sort of thing.)

CXF will help us with this. We add a new dependency to our POM:

    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-rs-service-description</artifactId>
        <version>${cxf.version}</version>
    </dependency>

Update.Build.Deploy.Start.

Prior to adding the above CXF dependency, we saw only the service advertized.

Image title

Now we also get a link to a WADL.

Image title

The WADL

<application xmlns="http://wadl.dev.java.net/2009/02"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <grammars>
        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
            attributeFormDefault="unqualified" elementFormDefault="unqualified">
            <xs:element name="pendingRequestsResponse" type="pendingRequestsResponse" />
            <xs:complexType name="pendingRequestsResponse">
                <xs:complexContent>
                    <xs:extension base="statusResponse">
                        <xs:sequence>
                            <xs:element name="numPending" type="xs:int" />
                            <xs:element maxOccurs="unbounded" minOccurs="0"
                                name="pendingRequests" nillable="true" type="calculationRequest" />
                        </xs:sequence>
                    </xs:extension>
                </xs:complexContent>
            </xs:complexType>
            <xs:complexType name="statusResponse">
                <xs:sequence>
                    <xs:element minOccurs="0" name="causeMsg" type="xs:string" />
                    <xs:element minOccurs="0" name="clazz" type="xs:string" />
                    <xs:element minOccurs="0" name="code" type="statusCode" />
                    <xs:element minOccurs="0" name="description" type="xs:string" />
                    <xs:element minOccurs="0" name="errMsg" type="xs:string" />
                </xs:sequence>
            </xs:complexType>
            <xs:complexType final="extension restriction" name="calculationRequest">
                <xs:sequence>
                    <xs:element minOccurs="0" name="calcType" type="calcType" />
                    <xs:element minOccurs="0" name="dimension" type="xs:double" />
                    <xs:element minOccurs="0" name="shapeName" type="shapeName" />
                </xs:sequence>
            </xs:complexType>
            <xs:simpleType name="calcType">
                <xs:restriction base="xs:string">
                    <xs:enumeration value="CALC_AREA" />
                    <xs:enumeration value="CALC_VOLUME" />
                    <xs:enumeration value="CALC_FOO" />
                    <xs:enumeration value="CALC_FOOBAR" />
                </xs:restriction>
            </xs:simpleType>
            <xs:simpleType name="shapeName">
                <xs:restriction base="xs:string">
                    <xs:enumeration value="CIRCLE" />
                    <xs:enumeration value="SQUARE" />
                    <xs:enumeration value="EQUILATERALTRIANGLE" />
                    <xs:enumeration value="SPHERE" />
                    <xs:enumeration value="CUBE" />
                    <xs:enumeration value="TETRAHEDRON" />
                </xs:restriction>
            </xs:simpleType>
            <xs:simpleType name="statusCode">
                <xs:restriction base="xs:string">
                    <xs:enumeration value="SUCCESS" />
                    <xs:enumeration value="ERROR" />
                </xs:restriction>
            </xs:simpleType>
        </xs:schema>
    </grammars>
    <resources base="http://localhost:8080/1-ws-rest-p2/services/shapecalc">
        <resource path="/">
            <resource path="pending">
                <method name="DELETE">
                    <response>
                        <representation mediaType="application/xml" />
                    </response>
                </method>
                <method name="GET">
                    <response>
                        <representation mediaType="application/xml" />
                    </response>
                </method>
                <method name="PUT">
                    <request>
                        <representation mediaType="*/*" />
                    </request>
                    <response>
                        <representation mediaType="application/xml" />
                    </response>
                </method>
            </resource>
            <resource path="results">
                <method name="DELETE">
                    <response>
                        <representation mediaType="application/xml" />
                    </response>
                </method>
                <method name="GET">
                    <response>
                        <representation mediaType="application/xml" />
                    </response>
                </method>
            </resource>
            <resource path="run/nostop">
                <method name="PUT">
                    <response>
                        <representation mediaType="application/xml" />
                    </response>
                </method>
            </resource>
            <resource path="run/stop">
                <method name="PUT">
                    <response>
                        <representation mediaType="application/xml" />
                    </response>
                </method>
            </resource>
        </resource>
    </resources>
</application>

I just wanted to show the above - we will not be using it directly - we just need to pass the URL to SOAPUI.

SOAPUI

Let's create a REST project in SOAPUI using the WADL.

Image title

I copied the URL from the browser and plop it in the WADL-dialog:

Image title

And we have:

Image title

Test

Let's try the GET /pending since we already know that worked.

Image title

Looks good. OK, time to see if we can do a PUT /pending.

Image title

If we execute the request as-is, we get:

Image title

We saw a similar error before when we were testing GET /pending and CXF didn't know how to deal with the PendingRequestsResponse. We now have to do what we did, then this time, we edit the QueueCalculationParms class:

Image title

Build.Deploy.Start.WADL.Test.

We repeat the previous request.

Image title

Let's try this:

Image title

We set the Media Type to application/xml of course, and just randomly fabricated an XML parameter. And the error gives us an indication of what we need.

Let's try again.

Image title

We have the same problem with the StatusResponse class.

StatusResponse

Image title

Build.Deploy.Start.WADL.Test.

We repeat the previous request.

Image title

Looking much better.

Granted, there are still some missing annotations, however, it is working because the child Shape Calculator has its own checking/verification of parameters. We'll get back to this later.

Let's fill in some of the request's XML QueueCalculationParms.

Image title

Looks really good. Now let's try the GET /pending again.

Image title

The remaining operations are no different than what we have covered, so we will stop here.

NOTE:  You may find that it was not strictly necessary to add either...

 @Produces(MediaType.APPLICATION_XML)  or @Consumes(MediaType.APPLICATION_XML)  

...to the SEI (ShapeCalculatorWebService).

NOTE #2: If you encounter weird problems with the request or response data, when you have made code or annotation changes, you might try getting a fresh WADL and re-creating the SOAPUI REST project.

Final Steps (Next Time)

What remains for this release of the REST service is to have it handle JSON. We also will combine a SOAP service and this REST service within the same web application or project. After that, upcoming articles on creating clients for a previously-developed SOAP service, and also for this service.

Latest Code

You can get the latest code to this project here. And you can get the child project (Shape Calculator) here. Stay tuned!

The Integration Zone is brought to you in partnership with CA Technologies.  Use CA Live API Creator to quickly create complete application backends, with secure APIs and robust application logic, in an easy to use interface.

Topics:
integration ,api ,rest apis ,soap ,json

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}