Representations - RESTful Entities - RESTful Web Services with Dropwizard (2014)

RESTful Web Services with Dropwizard (2014)

Chapter 5. Representations - RESTful Entities

Our web service is now responding to requests that produce output by utilizing the Response class. We saw that there are methods of this class that take an object as a parameter.

Creating a representation class

We are going to create the representations that will be produced by the REST resources of our application. A simple Java class is everything needed by Jersey, so it will consider the class as a RESTful representation.

Given that our web service needs to produce contact-related information in the JSON format, a sample response would look something like the following code:

{ id: 1, firstName: "John", lastName: "Doe", phone: "+123-456-789" }

We will build our representation class around this JSON string. The class will have the necessary properties (id, firstName, lastName, and phone) along with their getter methods.

How to do it…

Perform the following steps for creating a representation class:

1. Create a new package called com.dwbook.phonebook.representations and create a Contact class in it.

2. Add the aforementioned contact properties as final members, also implementing their getters and a constructor:

3. package com.dwbook.phonebook.representations;

4.

5. public class Contact {

6. private final int id;

7. private final String firstName;

8. private final String lastName;

9. private final String phone;

10.

11. public Contact() {

12. this.id = 0;

13. this.firstName = null;

14. this.lastName = null;

15. this.phone = null;

16. }

17.

18. public Contact(int id, String firstName, String lastName,String phone) {

19. this.id = id;

20. this.firstName = firstName;

21. this.lastName = lastName;

22. this.phone = phone;

23. }

24.

25. public int getId() {

26. return id;

27. }

28. public String getFirstName() {

29. return firstName;

30. }

31. public String getLastName() {

32. return lastName;

33. }

34. public String getPhone() {

35. return phone;

36. }

}

How it works…

The representation class for contacts is now ready. All that was required was just a plain Java class with the same properties as the JSON object that we wish our application to generate. In order for this to work though, the appropriate public getter methods are needed.

Our properties were declared final in order to be immutable, and for this reason, we also created a constructor that initializes the properties accordingly.

Instances of this class may now be used in our Jersey-based REST resources as the output. Jackson will handle the transformation from POJO to JSON transparently.

There's more…

Any POJO can be used as a representation. Jackson constructs the JSON string recursively according to the getter methods of each class and their return type.

The Jackson Java JSON processor

Jackson is a powerful open source JSON data binder/parser and processor that facilitates the transformation of plain old Java objects to the JSON format and vice versa. Jersey uses Jackson for its transformation needs and is part of the dropwizard-core module; so, it is already included in our project setup.

JSON arrays

Any instance of the java.util.List type will be converted to a JSON array. For example, if we wanted to store multiple phone numbers for a contact, we would have declared private final List<String> phoneNumbers in the representation class (with the appropriate modifications to the class constructor and the getter).

This would lead to JSON representations of the following format:

{ id: 1, firstName: "John", lastName: "Doe", phoneNumbers: ["+123-456-789", "+234-567-890", "+345-678-901"] }

Ignoring properties

You can prevent a property from being a part of the JSON representation by adding the @JsonIgnore annotation to its getter.

This will cause Jackson to ignore a getter method that otherwise would be treated as a JSON property.

Serving representations through the Resource class

Consider the ContactResource#getContact() method we previously implemented. We use the Response#ok(Object entity) method in order to build the response to be sent to the client, passing it to String as a parameter, as shown in the following code:

return Response.ok("{id: " + id + ", name: \"Dummy Name\", phone: \"+0123456789\" }").build();

Now, we have our Representation class ready, and we are going to utilize it and pass instances of it to the #ok() method.

How to do it…

Perform the following steps to learn the serving of representation through the resource class:

1. Update the ContactResource#getContact() method accordingly in order to pass a Contact object in the #ok() method instead of String, as shown in the following code. You will need to import the Contact class first (import com.dwbook.phonebook.representations.Contact):

2. @GET

3. @Path("/{id}")

4. public Response getContact(@PathParam("id") int id) {

5. // retrieve information about the contact with the provided id

6. // ...

7. return Response

8. .ok( new Contact( id, "John", "Doe", "+123456789") )

9. .build();

}

10. Next, modify the method's signature, splitting the name variable to firstName and lastName in order to be consistent with the Contact class:

11. @PUT

12. @Path("/{id}")

13. public Response updateContact(

14. @PathParam("id") int id,

15. @FormParam("firstName") String firstName,

16. @FormParam("lastName") String lastName,

17. @FormParam("phone") String phone) {

18. // update the contact with the provided ID

19. // ...

20. return Response

21. .ok( new Contact(id, firstName, lastName, phone) )

22. .build();

}

23. Rebuild (mvn package) and run the application again:

$ java -jar target/dwbook-phonebook-1.0-SNAPSHOT.jar server config.yaml

24. Navigate to http://localhost:8080/contact/123 or perform a PUT request to the same URL. You will see that the response that the server is sending to our request is a JSON representation of the object we are passing to the Response#ok() method.

How it works…

We define the response sent to the client by using the Response#ok() method, which accepts an object as a parameter. Until now, we have been passing JSON strings directly. This is not an efficient way, as our application will be handling actual objects (the Contactinstances), and there is no reason for manually creating JSON representations of them when this can be done automatically by Jackson.

There's more...

We are now using our representation class in order to map its properties to the response we are producing. We can also use the same class to map our input parameters. For instance, we could modify the ContactResource#updateContact() andContactResource#createContact()methods to expect a Contact object as a parameter instead of using each of its properties explicitly.

Using cURL to perform HTTP requests

Using your browser, you can only perform GET requests. In order to effectively test our application though, we will need a tool capable of performing HTTP requests with the POST, PUT, and DELETE methods. cURL (http://curl.haxx.se/) is a command-line tool that we can use to better comprehend the examples. You can download it from http://curl.haxx.se/download.html by choosing the package that is compatible with your platform.

Performing a GET request is as simple as the cURL. The following example will call the #getContact() method:

$ curl http://localhost:8080/contact/123

Using cURL to perform HTTP requests

The JSON string you are seeing in the second line is the server's response.

In order to perform a PUT request to update a contact, we will need to use the -X flag followed by the method name (that is curl -X PUT …). To send data to the server along with our request, a contact's information in this case, use the -d flag as well along with the data. Note that since the #updateContact() method's parameters are mapped to request parameters (with @FormParam), we need to send the data URL encoded. Take a look at the following screenshot:

Using cURL to perform HTTP requests

If we want to see a verbose output that includes the request's and response's headers, we can use the -v (long name --verbose) flag. Also, in case we need to set the value of a request header, we can use the -H (long name --header) flag followed by the header information:

$ curl --header "Content-Type: application/json" http://localhost:8080/contact/1

Mapping the request data to representations

The current way of reading the web service properties by mentioning each one of them (annotated) in the signatures of the #createContact() and #updateContact() methods is fine; however, it is not efficient in case of significant amount of input data. Imagine a case where we would need to add several additional properties in the Contact class. We would have to also update the method signatures as well, making them less readable and finally unmanageable. Generally, it is preferred to map the request data to the representation directly. To achieve this, we will update the relevant methods accordingly, removing the properties and adding a contact instance instead. Jackson will take care of the rest.

How to do it…

Perform the following steps to map the request data:

1. Update the ContactResource#createContact() method, replacing its parameters with a single contact object:

2. @POST

3. public Response createContact(Contact contact) {

4. // store the new contact

5. // ...

6. return Response

7. .created(null)

8. .build();

}

9. Update the ContactResource#updateContact() method, replacing its parameters with a single contact object:

10.@PUT

11.@Path("/{id}")

12.public Response updateContact(

13. @PathParam("id") int id,

14. Contact contact) {

15. // update the contact with the provided ID

16. // ...

17. return Response

18. .ok(new Contact(id, contact.getFirstName(), contact.getLastName(), contact.getPhone()))

19. .build();

}

20. Rebuild and run the application again. The application is now able to handle HTTP POST and PUT requests to the /contact and /contact/{id} endpoints respectively, having JSON strings on the request body instead of the named parameters. Note that theContent-Type header of the request will be set to application/json.

How it works…

By declaring a Contact instance as the parameter on a method that handles requests (that is, a method with Jersey annotations bound to URI), we force Jersey to parse the request body and deserialize (using Jackson) it to a Contact object.

The PUT request we performed in the previous example can now be performed by sending the JSON data to the server and setting the appropriate header, as shown in the following line of code:

$ curl --header "Content-Type: application/json" -X PUT -d '{"firstName": "FOO", "lastName":"BAR", "phone":"987654321"}' http://localhost:8080/contact/123

How it works…

In case a POST request is performed on http://localhost:8080/contact with the {"firstName": "Alexandros", "lastName": "Dallas", "phone": "+3012345678"} JSON data as the request's body and the Content-Type header: application/json, the contact object within the#createContact() method will have its properties initialized accordingly, thanks to Jackson and its appropriate JAX-RS entity providers. Entity providers are components that process the payload that is included in an HTTP request and transform it to an object. This is similar to the transformation that happens when a resource method is returning an object and is transformed to a JSON object.