|
RESTful
So let's step further to the RESTful part of our project. What we need is another stateless session bean with a method for each CRUD operation we want to support. The only thing we have to do for getting RESTful functionality is to use some annotations. On class level we annotate @Path("customers") as path to our service. Then we use @POST, @GET, @PUT and @DELETE to denote the different RESTful operations. As we want to communicate through JSON we use the MediaType.APPLICATION_JSON.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Stateless
@Path("customers")
public class CustomerResource {
@Inject
CustomerService service;
@POST
@Consumes(MediaType.APPLICATION_JSON)
public void create(Customer customer) {
service.create(customer);
}
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Customer find(@PathParam("id") long id) {
return service.find(id);
}
@PUT
@Consumes(MediaType.APPLICATION_JSON)
public void update(Customer customer) {
service.update(customer);
}
@DELETE
@Path("{id}")
public void delete(@PathParam("id") long id) {
service.remove(id);
}
}
There is one last thing we need to do to complete our REST configuration. @ApplicationPath("api") defines the global path to our application and this class has to extend javax.ws.rs.core.Application.
?
1
2
3
@ApplicationPath("api")
public class RESTConfig extends Application {
}
That's all the magic. Start the integrated Derby database with asadmin start-database and fire up your Glassfish server to try your new RESTful service.
curl
You can do a quick functionality check using curl. To send a POST request to your server and thereby create and persist the data do something like this:
?
1
curl -i -X POST -d '{"id":1,"name":"Annabelle"}' http://localhost:8080/jee7-rest-crud/api/customers -H 'Content-Type: application/json'
Basically that means, send a POST request containing that string to this address using the JSON format. Doing it right, your server will return something like that:
HTTP/1.1 204 No Content
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)
Server: GlassFish Server Open Source Edition 4.0
Date: Fri, 20 Sep 2013 05:11:11 GMT
Status code 204 No Content is perfect here because we defined our RESTful service not to send any data back on a POST request. If you want to read the data you saved before you can send a GET request:
?
1
curl -i -X GET http://localhost:8080/jee7-rest-crud/api/customers/1 -H 'Content-Type: application/json'
Your server should return a result like this:
HTTP/1.1 200 OK
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition 4.0 Java/Oracle Corporation/1.7)
Server: GlassFish Server Open Source Edition 4.0
Content-Type: application/json
Date: Fri, 20 Sep 2013 05:10:16 GMT
Content-Length: 27
{"id":1,"name":"Annabelle"}
The PUT (update) and DELETE (remove) operations can be tested in the same way.
Unit Test
If you want to unit test your RESTful service you can now use the new ClientBuilder from the JAX-RS 2.0 API coming with JEE7. But you will need some extra dependencies for the JSON data binding because Java do not yet provide that (likely to come with Java 8).
?
1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.6.3</version>
<scope>test</scope>
</dependency>
To do the data binding for JSON we need to implement the MessageBodyReader<T> and MessageBodyWriter<T> from the javax.ws.rs.ext package. These classes need to be annotated with @Provider and @Consumes respectively @Produces. Check the CustomerMessageBodyReader and CustomerMessageBodyWriter classes of the project for implementation details.
Now we can write a unit test to check the CRUD functionality of our RESTful service.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class CustomerClientTest {
private static final String SERVER = "http://localhost:8080/jee7-rest-crud/api/customers";
private WebTarget target;
@Before
public void setUp() {
Client client = ClientBuilder.newClient();
client.register(CustomerMessageBodyReader.class);
client.register(CustomerMessageBodyWriter.class);
this.target = client.target(SERVER);
}
@Test
public void crud() {
Customer origin = new Customer(1, "Mathilda");
Entity<customer> entity = Entity.entity(origin, MediaType.APPLICATION_JSON);
// create
Response response = target.request(MediaType.APPLICATION_JSON).post(entity, Response.class);
assertThat(response.getStatus(), equalTo(204));
// read
Customer result = target.path(String.valueOf(origin.getId())).request(MediaType.APPLICATION_JSON).get(Customer.class);
assertThat(result, equalTo(origin));
// update
entity.getEntity().setName("Annabelle");
target.request().put(entity);
// delete
target.path(String.valueOf(origin.getId())).request(MediaType.APPLICATION_JSON).delete();
}
}
</customer>
First we build the client and register the custom reader and writer classes. Then we set the target to the address of our service. The rest is straight forward testing of the various functionality we have built. |
|