Professional
Minneapolis, MN
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.)
Described in Roy Fielding's 2000 PhD dissertation
Fielding, Roy.Many helpful defaults
De-coupled server and client
NO GSPs!
Resource Transformation
import grails.rest.Resource
@Resource(uri='/gr8ladies')
class Gr8Lady {
String first
String last
}
URL mappings
URLmappings.groovy
"/gr8ladies"(resources:"gr8lady")
Or
"/gr8ladies"(resources:"gr8lady") {
"/chapter"(controller:"chapter", method:"GET")
}
--> /gr8ladies/{id}/chapter
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 |
Many of the cases are handled by Grails or the server(i.e. 5XXs)
if(someCondition) {
render status: 4XX
}
Handled by Default! :)
On each Controller
class Gr8LadyController {
static allowedMethods = [list: "GET", save: "POST", update: "PUT"]
}
URL Mappings
"/gr8ladies"(resource: "gr8lady", method: "GET")
http://example.com/resource
http://example.com/resource/{id}
http://example.com/resource/{id}
http://example.com/resource?id=abc123
http://example.com/resource/{id}/?action=delete
http://example.com/resource/add
/resources
NOT
/ReSoUrCeS
Try Either:
/multiWordResources
Or:
/multi-word-resources
And stick to it. Don't Mix and Match!
plural nouns preferred
http://example.com/users
vs
http://example.com/user
http://example.com/resource?fieldName=value
By Parameter
http://example.com/resource.json
Available formats
grails:
mime:
types:
...
json: ['application/json', 'text/json'],
...
xml: ['text/xml', 'application/xml']
By Resource
import grails.rest.Resource
@Resource(uri='/gr8ladies', formats=['json'])
class Gr8Lady {
...
}
Requesting another type returns a 406 (Not Acceptable)
By RestfulController
class Gr8LadyController extends RestfulController {
static responseFormats = ['json', 'xml']
}
Remember to add any response formats for versioned mime types
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
Object Marshallers
grails-app/conf/spring/resources.groovy
import grails.converters.JSON
import org.gr8ladies.ChapterMarshaller
beans = {
JSON.registerObjectMarshaller(new ChapterMarshaller())
}
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
}
}
link to the resource and navigation
{
"_links": {
"self": { "href": "/gr8ladies" },
"next": [
{ "href": "/gr8ladies?page=2" }
]
}
}
grails-app/conf/spring/resources.groovy
import grails.rest.render.hal.*
beans = {
halGr8LadyRenderer(HalJsonRenderer, org.gr8ladies.Gr8Lady)
}
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""
}
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]
}
http://example.com/v1/resource/{id}
GET https://example.com/resource
version: 2.0
GET https://example.com/resource
Accept: application/vnd.example.v2+json
@Resource(uri='/gr8ladies/v1')
@Resource(uri='/gr8ladies/v2')
"/gr8ladies"(version:'1.0', resources:"gr8lady", namespace: 'v1')
"/gr8ladies"(version:'2.0', resources:"gr8lady", namespace: 'v2')
@Resource(uri="/gr8ladies", readOnly=true)
class Gr8Lady {
String first
...
}
Token based Authentication based on Spring-Security
Last Updated May 2015
Last Updated November 2014
Last Updated February 2014
@Resource
!