4 Building our API

The default JSON rendered by Grails is a good start, but it doesn’t necessarily express the details we want in our public-facing API. JSON Views allow us to render our data using Groovy’s StreamingJsonBuilder, in a statically-compiled Groovy view. JSON views provide a powerful DSL-based tool for expressing the JSON output from our API.

4.1 Introducing JSON Views

Here’s a trivial example of a JSON view:

json.message {
    hello "world"
}

This JSON view would produce the following ouput when rendered:

{"message":{ "hello":"world"}}

JSON views also support a model which references the data passed in to the view, as seen below:

model {
    String message
}
json.message {
    hello message
}

JSON views are Groovy files with the file extension gson, and they reside in the grails-app/views directory, just like GSP views. They are resolved (by convention) to a controller with the same name as the view directory, again like GSP views.

4.2 Customizing our API

Let’s create a JSON view to customize the output from the /api/orders/$id endpoint. Right now, the default JSON renderer includes ids of all associated objects. However, we don’t want to expose the id of the shippingAddress property (which is an instance of our Address domain class) - it’s not exposed as a domain resource in our API and it’s only relevant to users of API as part of an Order or Customer. Ideally, we’d like to include the shippingAddress fields in the JSON output of our Order API.

In addition, we’d like to express the orderId property as the order’s id, rather than the actual id from the database.

Create a new directory under grails-app/views, called order:

$ mkdir grails-app/views/order
If you’re familiar with Grails' view resolution, you may be thinking we need to create an OrderController in order to use views from our order directory. We could do that, however because we’re making use of the @Resource annotation on our domain class, Grails will generate an associated OrderController (which will in turn inherit from RestfulController) for us. So at this point, we don’t need to create a controller for our Order class.

Create a new JSON view called show.gson. This will resolve to the show action in our controller, just as a show.gsp page would in a normal Grails application. Edit the new view with the following content:

grails-app/views/order/show.gson
import com.example.Order

model {
    Order order
}
json {
    id order.orderId
    shippingCost order.shippingCost
    date order.orderPlaced.format('M-dd-yyy') (1)

    shippingAddress { (2)
        street order.shippingAddress.street
        street2 order.shippingAddress.street2
        city order.shippingAddress.city
        state order.shippingAddress.state
        zip order.shippingAddress.zip
    }

    products order.products.collect { [id: it.id] } (3)

    customer {
        id order.customer.id
    }
}
1 Note that we are using Groovy’s format method on the Date class to customize the format of the orderPlaced property
2 Here we’re filling out our shippingAddress with the fields from the Address class
3 Notice that we’re iterating over a collect (order.products) with the collect method and returning a map - this will create a JSON array of objects

Now if you make a request to /api/orders/1, you should see the following output:

curl -H "Accept: application/json" localhost:8080/api/orders/1
{
    id: "0A12321",
    shippingCost: 13.54,
    date: "2-08-2017",
    shippingAddress: {
        street: "321 Arrow Ln",
        street2: null,
        city: "Chicago",
        state: "IL",
        zip: 646465
    },
    products: [
            {
                id: 11
            },
            {
                id: 1
            },
            {
                id: 6
            }
    ],
    customer: {
        id: 1
    }
}

Let’s create another JSON view for our Customer domain class. Create a new directory under grails-app/views, called customer, and a new JSON view show.gson

$ mkdir grails-app/views/customer

Create a new JSON view called show.gson. This will resolve to the show action in our controller, just as a show.gsp page would in a normal Grails application. Edit the new view with the following content:

grails-app/views/customer/show.gson
import com.example.Customer

model {
    Customer customer
}
json {
    id customer.id
    firstName customer.firstName
    lastName customer.lastName
    fullName "${customer.firstName} ${customer.lastName}"

    address {
        street customer.address.street
        street2 customer.address.street2
        city customer.address.city
        state customer.address.state
        zip customer.address.zip
    }

    orders customer.orders.collect { [id: it.id] }
}
  Get the Code