Restful Web Services in Grails 3

by Jenn Strater @jennstrater

http://jlstrater.github.io/Restful-Grails3

Slides(source)

About Me

Professional

About Me

Minneapolis, MN

    Connect on Social Media
  • Twitter @jennstrater
  • LinkedIn https://linkedin.com/in/jennstrater
  • Github https://github.com/jlstrater

Agenda

  • Remedial REST
  • Ways To Improve A RESTful API
    • with Grails Examples
  • Related Grails Plugins

What this talk will NOT cover

  • Scalability of Grails APIs
  • Security
  • Ingesting RESTful APIs

Remedial REST

Terminology

  • Application Programming Interface (API)
  • Web Service
  • Representational State Transfer (REST)

Definition

REpresentational State Transfer (REST) is an architectural style that describes how distributed data objects, or resources, can be defined and addressed, stressing the easy exchange of information and scalability.(Fischer 2013.)

History

Described in Roy Fielding's 2000 PhD dissertation

Fielding, Roy. Architectural Styles and the Design of Network-based Software Architectures. 2000.

Goals

  • To create a uniform interface between components
  • Decouple implementations from the underlying services

Characteristics

Uniform Interface

  • Individual Resources are identified using URIs
  • Resources are abstracted from the data source and can be manipulated before being sent to a client
  • Hypermedia As The Engine Of Application State (HATEOAS)

Stateless

    Self-contained and independent requests
  • Improves scalability
  • Allows for parallel processing of requests
  • Lets resources be viewed in isolation

Client-Server

    Decoupled clients and servers
  • Increases portability
  • Easier to scale

Layered System

    Endpoints can be the terminus or an intermediary service
  • Allows for load balancing and intermediate security enforcers

Why choose REST?

  • Easy to implement
  • Usable across many different platforms and languages

Why REST and Grails?

Many helpful defaults

    Other advantages of Grails
  • Ease of development
  • Shorter development time

Questions about REST?

Ways To Improve A RESTful API

(with Grails)

Scope

De-coupled server and client

NO GSPs!

New in Grails 3

  • Based on Spring Boot
  • Switched to Gradle for build system
  • Major structural changes
    • Configuration
    • Scripts

Getting Started

Resource Transformation

import grails.rest.Resource

@Resource(uri='/gr8ladies')
class Gr8Lady {
  String first
  String last
}

Getting Started

URL mappings

URLmappings.groovy

"/gr8ladies"(resources:"gr8lady")

Or

"/gr8ladies"(resources:"gr8lady") {
  "/chapter"(controller:"chapter", method:"GET")
}
--> /gr8ladies/{id}/chapter

HTTP Status Codes

  • 200 is ok ... but not for everything

HTTP Status Codes

Learn the correct status codes for different errors

Code Description
2XX Successful
200 OK
4XX Client Error
400 Bad Request
403 Forbidden
404 Not Found
5XX Server Errors
500 Internal Server Error
502 Bad Gateway
an exerpt fromhttp://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

HTTP Status Codes in Grails

Many of the cases are handled by Grails or the server(i.e. 5XXs)

if(someCondition) {
  render status: 4XX
}

HTTP verbs

  • GET to retrieve a resource
  • POST to create a new resource
  • PUT to update an existing resource
  • DELETE to remove an existing resource

HTTP verbs in Grails

Resource Annotation

Handled by Default! :)

HTTP verbs in Grails

On each Controller

class Gr8LadyController {
  static allowedMethods = [list: "GET", save: "POST", update: "PUT"]
}

HTTP verbs in Grails

URL Mappings

"/gr8ladies"(resource: "gr8lady", method: "GET")

Endpoints

List

http://example.com/resource

Show

http://example.com/resource/{id}

Endpoints

  • http://example.com/resource/{id}
  • NOT http://example.com/resource?id=abc123
  • NOT http://example.com/resource/{id}/?action=delete
  • NOT http://example.com/resource/add

Consistent Style

casing

/resources

NOT

/ReSoUrCeS

Consistent URI style

Try Either:

/multiWordResources

Or:

/multi-word-resources

And stick to it. Don't Mix and Match!

Consistent Style

Resource Names

plural nouns preferred

http://example.com/users

vs

http://example.com/user

Search

    http://example.com/resource?fieldName=value
  • Lookup based on values

Multiple Media Types (JSON, XML)

  • XML and JSON are most common

Multiple Media Types (JSON, XML) in Grails

  • XML by default
  • By Parameter

    http://example.com/resource.json

Multiple Media Types (JSON, XML) in Grails

Available formats

grails:
  mime:
    types:
    ...
    json: ['application/json', 'text/json'],
    ...
    xml: ['text/xml', 'application/xml']

Multiple Media Types (JSON, XML) in Grails

By Resource

import grails.rest.Resource

@Resource(uri='/gr8ladies', formats=['json'])
class Gr8Lady {
  ...
}

Requesting another type returns a 406 (Not Acceptable)

Multiple Media Types (JSON, XML) in Grails

By RestfulController

class Gr8LadyController extends RestfulController {
  static responseFormats = ['json', 'xml']
}

Remember to add any response formats for versioned mime types

Custom Response Formats

  • Filter from default responses
  • Provide different responses per version
  • Provide response formats based on security

Custom Response Formats in Grails

Object Marshallers

grails-app/init/Bootstrap.groovy

import grails.converters.JSON

class Bootstrap {
  def init = { servletContext ->
    JSON.registerObjectMarshaller(Gr8Lady) {
      def returnArray = [:]
      returnArray['firstName'] = it.first
      returnArray['lastName'] = it.last
      returnArray['chapter'] = it.chapter?.name
      return returnArray
    }
  }
}

Usage

render gr8lady as JSON

Custom Response Formats in Grails

Object Marshallers

grails-app/conf/spring/resources.groovy

import grails.converters.JSON
import org.gr8ladies.ChapterMarshaller

beans = {
    JSON.registerObjectMarshaller(new ChapterMarshaller())
}

Custom Response Formats in Grails

Object Marshallers

class Gr8LadyMarshaller implements ObjectMarshaller<JSON>{
    public boolean supports(Object object) {
      return object instanceof Gr8Lady
    }
    
    public void marshalObject(Object object, XML converter) {
      Gr8Lady gr8lady  = (Gr8Lady)object
      converter.chars gr8lady.displayName
    }
}

Hypermedia As The Engine Of Application State (HATEOAS)*

link to the resource and navigation

{
  "_links": {
    "self": { "href": "/gr8ladies" },
    "next": [
      { "href": "/gr8ladies?page=2" }
    ]
  }
}

HATEOAS in Grails

  • JSON
  • Hypertext Application Language (HAL)
  • grails-app/conf/spring/resources.groovy

    import grails.rest.render.hal.*
    beans = {
        halGr8LadyRenderer(HalJsonRenderer, org.gr8ladies.Gr8Lady)
    }

HATEOAS in Grails

Usage: Content Negotiation

curl -i -H "Accept: application/hal+json" http://localhost:8080/gr8ladies/1

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/hal+json;charset=ISO-8859-1

{
  "_links": {
    "self": {
      "href": "http://localhost:8080/gr8ladies/1",
      "hreflang": "en",
      "type": "application/hal+json"
    }
  },
  "name": ""Grace Hopper""
}

Pagination*

Parameters

http://example.com/resource?offset=0&max=10

def list() {
  List gr8ladies = Gr8Lady.list(max: params.max, offset: params.offset)
  respond [results: gr8ladies, max: params.max, offset: params.offset]
}

Versioning*

  • URI http://example.com/v1/resource/{id}
  • Custom Header
  • GET https://example.com/resource
    version: 2.0
  • Content Type
  • GET https://example.com/resource
    Accept: application/vnd.example.v2+json

Versioning in Grails

      URI
    • @Resource(uri='/gr8ladies/v1')
    • @Resource(uri='/gr8ladies/v2')
      Accept Header
    • "/gr8ladies"(version:'1.0', resources:"gr8lady", namespace: 'v1')
    • "/gr8ladies"(version:'2.0', resources:"gr8lady", namespace: 'v2')

Read-only Mode

  • for public APIs (or security)

Read-only Mode in Grails

@Resource(uri="/gr8ladies", readOnly=true)
class Gr8Lady {
  String first
  ...
}

Related Plugins for other Grails versions

Spring Security REST Plugin

Token based Authentication based on Spring-Security

Last Updated May 2015

Source & Documentation

Restful API Plugin

Last Updated November 2014

Source & Documentation

Rest Renderer

Last Updated February 2014

Source & Documentation

Conclusions

  • REST is an architecture style, not a standard
  • There are many ways to implement REST
  • Grails makes REST easy with @Resource!
  • Don't reinvent the wheel, use standard practices.

Questions?

References