Grails

Grails REST Example

In this example we shall show you how to create RESTful APIs using Grails. Exposing your application functionality to other applications is always achieved using web services. Grails provides several features that make implementing a RESTful web service in Grails easy using a RESTful resource.

Originally, web services grew in popularity as a means for system integration. But with the recent popularity of sites such as Google Maps and Amazon.com, and social networking sites like Facebook, there is an expectation that public APIs should be offered so users can create new and innovative client applications. When these clients combine multiple services from multiple providers, they are referred to as mashups. They can include command-line applications, desktop applications, web applications, or some type of widget.

In this example, we will learn how to expose your application functionality as a Representational State Transfer (REST) web service for Finacial market order gateway application to provide access to domain objects. This RESTful web service will be able to return either XML or JavaScript Object Notation (JSON), depending on the needs of the client application. This web service will also be designed to take advantage of convention over configuration for exposing CRUD functionality for any Grails domain model.

1. Project Environment

  1. Groovy/Grails Tool Suite
  2. Grails 3.0.10
  3. Groovy 2.4.5
  4. JDK 1.8

2. Grails Project

2.1. Create new project

We will start creating a new Grails 3 project using the following Grails command line.

grails create-app grails-rest-example --profile=web-api

2.2. Project Structure

  • build directory where build related files like compiled classes and assembled packages are located.
  • gradle directory contains the Gradle Wrapper that allows you to build the project without a local Gradle installation.
  • conf directory contains the YAML configuration files and Logback configuration.
  • init directory contains Bootstrap.groovy and the new Application main class which looks like main class in Spring Boot.
  • controllers directory contains controllers classes.
  • domain directory contains location of domain classes.
  • i18n directory contains location of message bundles for i18n.
  • services directory contains location of services.
  • util directory contains special utility classes.
  • src folder is an optional directory for Groovy source files of types other than those in grails-app/*
  • build.gradle and gradle.properties contain the build configuration.

3. REST Web Service

REST is not really a technology itself, but more like an architectural pattern. REST is very simple and just involves using plain XML or JSON as a communication medium, combined with URL patterns that are “representational” of the underlying system, and HTTP methods such as GET, PUT, POST and DELETE.
Each HTTP method maps to an action type. For example GET for retrieving order, POST for submitting new order, PUT for updating submitted one and so on.

Grails includes flexible features that make it easy to create RESTful APIs. Creating a RESTful resource can be as simple as one line of code, as demonstrated in the next section.

3.1. Domain classes as REST resources

The easiest way to create a RESTful API in Grails is to expose a domain class as a REST resource. Simply by adding the Resource transformation and specifying a URI, your domain class will automatically be available as a REST resource in either XML or JSON formats. The transformation will automatically register the necessary RESTful URL mapping and create a controller called OrderController.
Also, If you wish to change the default to return JSON instead of XML, you can do this by setting the formats attribute of the Resource transformation:

@Resource(uri='/api/orders', formats=['json', 'xml'])
class Order {
...
}

Order.groovy:

package grails.rest.example

import grails.rest.*
@Resource(uri='/api/orders', formats=['json', 'xml'])
class Order {
	
	Long id
	String stock
	String side
	Double price
	Long size
	
	static mapping = {
		version false
		table 'orders'
		id column: 'id', generator:'native', params:[sequence:'order_seq']
	  }
	
    static constraints = {
			stock blank:false
			side blank:false
			price blank:false
			size blank:false
	}
}

4. Running Grails Web Service

4.1. Initial Order Data

We added some orders data to BootStrap.groovy, then we run our Grails application as a spring boot app using Application.groovy.

BootStrap.groovy:

import grails.rest.example.Order

class BootStrap {

    def init = { servletContext ->
        new Order(stock:"AAPL", side:"S", price:200, size:1000).save()
        new Order(stock:"IBM", side:"B", price:300, size:2000).save()
		new Order(stock:"JNJ", side:"T", price:150, size:3000).save()
    }
    def destroy = {
    }
}

Application.groovy:

import grails.rest.example.Order

class BootStrap {

    def init = { servletContext ->
        new Order(stock:"AAPL", side:"S", price:200, size:1000).save()
        new Order(stock:"IBM", side:"B", price:300, size:2000).save()
		new Order(stock:"JNJ", side:"T", price:150, size:3000).save()
    }
    def destroy = {
    }
}

4.2. List Orders

Hitting the URL http://localhost:8080/api/orders, which will render the response with the default JSON format like:

[{
	"class": "grails.rest.example.Order",
	"id": 1,
	"price": 200.0,
	"side": "S",
	"size": 1000,
	"stock": "AAPL"
}, {
	"class": "grails.rest.example.Order",
	"id": 2,
	"price": 300.0,
	"side": "B",
	"size": 2000,
	"stock": "IBM"
}, {
	"class": "grails.rest.example.Order",
	"id": 3,
	"price": 150.0,
	"side": "T",
	"size": 3000,
	"stock": "JNJ"
}]

Also, we can set the desired response format using the file extension in the URI, hitting the URL http://localhost:8080/api/orders.xml, will render the response with the XML format like:

<?xml version="1.0" encoding="UTF-8"?>
<list>
   <order id="1">
      <price>200.0</price>
      <side>S</side>
      <size>1000</size>
      <stock>AAPL</stock>
   </order>
   <order id="2">
      <price>300.0</price>
      <side>B</side>
      <size>2000</size>
      <stock>IBM</stock>
   </order>
   <order id="3">
      <price>150.0</price>
      <side>T</side>
      <size>3000</size>
      <stock>JNJ</stock>
   </order>
</list>

Also, instead of using the file extension in the URI, you can also obtain a JSON response by issuing a GET request while using the ACCEPT header. Here’s an example using the Unix curl tool:

curl -i -H "Accept: application/json" localhost:8080/api/orders

Output:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 06 Jul 2016 21:52:22 GMT

[{"class":"grails.rest.example.Order","id":2,"price":300.0,"side":"B","size":2000,"stock":"IBM"},{"class":"grails.rest.example.Order","id":3,"price":150.0,"side":"T","size":3000,"stock":"JNJ"},{"class":"grails.rest.example.Order","id":4,"price":200.0,"side":"S","size":5000,"stock":"TWT"}]

4.3. Submit Order

We can create a new order by issuing a POST request:

curl -i -X POST -H "Content-Type: application/json" -d '{"price": 200,"side": "S","size": 5000,"stock": "TWT"}' localhost:8080/api/orders

Output:

HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Location: http://localhost:8080/api/orders/4
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 06 Jul 2016 21:35:14 GMT

{"class":"grails.rest.example.Order","id":4,"price":200.0,"side":"S","size":5000,"stock":"TWT"}

4.4. Update Order

We can create a new order by issuing a PUT request:

curl -i -X PUT -H "Content-Type: application/json" -d '{"price": 210,"size": 500}' localhost:8080/api/orders/1

Output:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Location: http://localhost:8080/api/orders/1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 06 Jul 2016 21:37:41 GMT

{"class":"grails.rest.example.Order","id":1,"price":210.0,"side":"S","size":500,"stock":"AAPL"}

4.5. Delete Order

We can create a new order by issuing a DELETE request:

curl -i -X DELETE localhost:8080/api/orders/1

Output:

HTTP/1.1 204 No Content
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: application/json;charset=UTF-8
Date: Wed, 06 Jul 2016 21:39:12 GMT

As you can see, the Resource transformation enables all of the HTTP method verbs on the resource. You can enable read-only capabilities by setting the readOnly attribute to true. However, In this case POST, PUT and DELETE requests will be forbidden.

@Resource(uri='/api/orders', formats=['json', 'xml'], readOnly=true)
class Order {
...
}

5. Download the Source Code

This was an example on how to create a Grails REST web service.

Download
You can download the full source code of this example here: GrailsRESTWebServiceExampleCode.zip

Ashraf Sarhan

Ashraf Sarhan is a passionate software engineer, an open source enthusiast, has a Bsc. degree in Computer and Information Systems from Alexandria University. He is experienced in building large, scalable and distributed enterprise applications/service in multiple domains. He also has a keen interest in JavaEE, SOA, Agile and Big Data technologies.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Owen Rubel
Owen Rubel
5 years ago

You could do ALL this alot easier by just doing the following:

grails create-app –profile org.grails.profiles:beapi:1.0.0

https://www.beapi.io/documentation

Back to top button