Chapter 12. Writing Resource Endpoints

Table of Contents

Create Entity with POST
Read Collection of Entities with GET
Read a Single Entity with GET

Let's create a resource class called DomainResource, annotated with JAX-RS @Path and @Produces annotations. One extra thing we need for LinkRest to work is a an instance of javax.ws.rs.core.Configuration, that can be injected with @Context annotation:

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Context;

@Path("domain")
@Produces(MediaType.APPLICATION_JSON)
public class DomainResource {

    @Context
    private Configuration config;
}

Create Entity with POST

Now let's implement a POST method in DomainResource class:

import com.nhl.link.rest.LinkRest;
import com.nhl.link.rest.SimpleResponse;

...

@POST
public SimpleResponse create(String data) {
    return LinkRest.create(Domain.class, config).sync(data);
}

Here we've built a very simple "create chain" using LinkRest fluent API. It starts with a static "create" method on LinkRest class, taking a type of entity to create (Domain) and previously injected Configuration. Finally it calls "sync" method to execute the request. "data" String is expected to be an "Update Document" (see the section called “Request: Update Document”), i.e. a single object or an array of objects. Now if you compile your app and deploy it in a web container (e.g. Tomcat), you may call this endpoint to create new Domain objects:

curl -i -X POST 'http://example.org/myapp/domain' \
>          -d '{"vhost":"mysite1.example.org","name":"My Site #1"}'

HTTP/1.1 201 Created
Content-Type: application/json

{"success":true}

In your container log you might see output from Cayenne, actually inserting a newly created object:

INFO CommonsJdbcEventLogger - INSERT INTO "domain" ("name", "vhost") VALUES (?, ?)
INFO CommonsJdbcEventLogger - [bind: 1->name:'My Site #1', 2->vhost:'mysite1.example.org']
INFO CommonsJdbcEventLogger - Generated PK: domain.id = 1
INFO CommonsJdbcEventLogger - === updated 1 row.

Read Collection of Entities with GET

You may create more Domain objects, executing POST request above. Now let's write a GET method to search for domains:

import com.nhl.link.rest.DataResponse;
import com.nhl.link.rest.LinkRest;

...

@GET
public DataResponse<Domain> getAll(@Context UriInfo uriInfo) {
    return LinkRest.select(Domain.class, config).uri(uriInfo).select();
}

The above is a typical "select chain". Now GET can be invoked from the client like this:

curl -i -X GET 'http://example.org/myapp/domain'

HTTP/1.1 200 OK
Content-Type: application/json

{
    "data" : [
        { "id" : 1, "name" : "My Site #1", "vhost" : "mysite1.example.org" },
        { "id" : 2, "name" : "My Site #2", "vhost" : "mysite2.example.org" }
    ],
    "total" : 2
}

Since select chain above incorporates UriInfo, it will recognize LinkRest control parameters passed from the client (see Chapter 8, Control Parameters). Let's try using "cayenneExp" filter and "include":

curl -i -X GET 'http://example.org/myapp/domain?cayenneExp=vhost="mysite1.example.org"&include=id'

HTTP/1.1 200 OK
Content-Type: application/json

{
    "data" : [
        { "id" : 1 }
    ],
    "total" : 1
}

Read a Single Entity with GET

A common request is to locate a single instance of an entity by ID. Here is how this can be done with LinkRest:

@GET
@Path("{id}")
public DataResponse<Domain> getOne(@PathParam("id") int id, @Context UriInfo uriInfo) {
    return LinkRest.select(Domain.class, config).byId(id).uri(uriInfo).selectOne();
}

Here we are binding "id" as a URL path parameter, but also notice that LinkRest doesn't mandate any specific place in the URL for ID. This is a decision made by the developer. Calling this endpoint, we'll get an expected result:

curl -i -X GET 'http://example.org/myapp/domain/1'

HTTP/1.1 200 OK
Content-Type: application/json

{
    "data" : [
        { "id" : 1, "name" : "My Site #1", "vhost" : "mysite1.example.org" }
    ],
    "total" : 1
}

Even though we expect at most one object to be returned, the response is the same Collection Document as we've seen before.