SlideShare a Scribd company logo
1 of 91
Download to read offline
Building Awesome APIs in Grails 
By Chris Latimer 
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
2 
What makes an 
API awesome?
3 
Is it using JSON 
payloads 
instead of XML?
Using this Template 
4 
Is it strict adherence to REST principles?
5 
API Fielding Score
6
7 Predictable and Consistent
8 
"uri": 
"/categories/activism", 
"name": 
"Activism 
& 
Non 
Profits", 
"link": 
“https://vimeo.com/…”, 
… 
"metadata": 
{ 
"connections": 
{…} 
} 
Category ! 
Response: 
"uri": 
"/channels/804185", 
"name": 
"School 
Intercom", 
"link": 
“https://vimeo.com/…”, 
… 
"metadata": 
{ 
"connections": 
{…} 
} 
Channel ! 
Response:
9 
<photo 
id="2636" 
owner="47058503995@N01" 
secret="a123456" 
server=“2" 
title=“test_04” 
ispublic=“1" 
isfriend="0" 
isfamily="0" 
/> 
<contact 
nsid="12037949629@N01" 
username="Eric" 
iconserver="1" 
realname="Eric 
Costello" 
friend="1" 
family="0" 
ignored="1" 
/>
10 
Stable Versions 
URI Based Accept Header 
/v1/endpoint 
! 
/v2/endpoint 
Accept-­‐Version: 
1.0 
! 
Accept-­‐Version: 
1.1 
Content Type 
Accept: 
application/vnd.your.api.v2+json 
! 
Accept: 
application/vnd.your.api.v2.1+json
11 
Predictable Response Codes 
2xx Successful 4xx Client Error 
400 
Bad 
Request 
401 
Unauthorized 
403 
Forbidden 
404 
Not 
Found 
5xx Server Error 
500 
Server 
Error 
502 
Bad 
Gateway 
503 
Unavailable 
200 
Success 
201 
Created 
!
12 
Intuitive Structure
13 
Intuitive URI Structure 
URI Description 
/group/{id} A Facebook group 
/group/{id}/feed This group’s feed 
/group/{id}/files Files uploaded to this group 
/group/{id}/events This group’s events
14 
Intuitive Navigation 
Pagination 
"total": 
659212, 
"page": 
2, 
"per_page": 
10, 
"paging": 
{ 
"next": 
"/channels?page=3", 
"previous": 
"/channels?page=1", 
"first": 
"/channels?page=1", 
"last": 
"/channels?page=65922" 
}
15 
Intuitive Navigation 
Related Resources 
{ 
“uri": 
"/categories/experimental", 
"name": 
"Experimental", 
"subcategories": 
[ 
{ 
"uri": 
“/categories/experimental/animation", 
"name": 
"Animation", 
"link": 
“https://vimeo.com/categories/…” 
}… 
] 
}
Flexible Responses
17 
Partial Responses 
Get Full Response 
/feeds/api/users/default/uploads 
Get Partial Response 
/feeds/api/users/default/uploads? 
 
fields=entry(title,gd:comments,yt:statistics)
18 
Result Filtering 
Get List of Videos 
/feeds/api/videos?q=surfing&max-­‐results=10 
Get Videos with 1,000,000+ Views 
/feeds/api/videos?q=surfing&max-­‐results=10 
&fields=entry[yt:statistics/@viewCount 
> 
1000000]
19 
Customized Responses 
ItemLookup - Default 
ItemId=B00008OE6I 
ItemLookup - Default With Reviews 
ItemId=B00008OE6I 
&ResponseGroup=Reviews 
ItemLookup - Large With Reviews and Offers 
ItemId=B00008OE6I 
&ResponseGroup=Large,Reviews,Offers
20 
Easy to Learn and 
Experiment With
21
22
23 
Designing an 
awesome API
Apps API
G
Phone Shopping App 
Potential Resources 
/phones 
! 
/devices 
! 
/manufacturers
Phone Shopping App 
API Features 
Pagination 
! 
Filtering 
! 
Versioning
Phone Shopping App 
Potential Resources 
/phoneVariations 
! 
/phone/{id} 
! 
/phone/{id}/variations
Phone Shopping App 
API Features 
Complete 
vs. 
Compact 
representations 
! 
Including 
related 
entities 
! 
Linking 
to 
other 
resources
Phone API Endpoints 
URI Verb Description 
/phones GET Get a list of phones 
/phones/{id} GET Get phone details 
/phones/{id}/manufacturer GET Get phone’s manufacturer 
/phones/{id}/variations GET Get variations of a phone
Phone API Versioning 
Header Based 
Accept-­‐Version: 
1.0 
! 
Accept-­‐Version: 
2.0
General Response Structure Patterns 
{ 
“entity” 
: 
{ 
“attr1” 
: 
“value1”, 
“attr2” 
: 
“value2”, 
… 
}, 
“metadata” 
: 
{ 
} 
} 
{ 
“attr1” 
: 
“value1”, 
“attr2” 
: 
“value2”, 
… 
}
General Response Structure Patterns 
{ 
“entities” 
: 
[ 
{ 
“attr1” 
: 
“value1”, 
“attr2” 
: 
“value2”, 
… 
},{…},{…}… 
], 
“metadata” 
: 
{ 
} 
} 
[ 
{ 
“attr1” 
: 
“value1”, 
“attr2” 
: 
“value2”, 
… 
}, 
{…},{…}… 
]
API Formats 
JSON Default 
“phones” 
: 
[ 
{ 
“name”:“iPhone 
5s”, 
“basePrice”:599.99, 
… 
} 
] 
XML by Request 
<phones> 
<phone> 
<name>iPhone 
5s</name> 
… 
</phone> 
… 
</phones>
Intuitive Response Structures 
Single Response Collection Response 
{ 
{ 
“phones” 
: 
[ 
{…}, 
{…}, 
…], 
“paging” 
: 
{ 
… 
} 
} 
phone: 
{ 
“key1” 
: 
“value1”, 
… 
“keyN” 
: 
“valueN”, 
“links” 
: 
[ 
{…},{…}…] 
} 
}
Complete and Compact Representations 
Attribute Compact Complete 
name 
basePrice 
variations 
manufacturer
Customized Responses 
GET 
/phones/1 
{ 
“name” 
: 
“iPhone5s”, 
… 
} 
GET 
/phones/1?include=accessories 
{ 
“name” 
: 
“iPhone5s”, 
… 
“includes” 
: 
[ 
{ 
“accessories” 
: 
[…] 
} 
] 
}
Pagination 
GET 
/phones 
{ 
“phones” 
: 
[ 
{…}, 
{…}, 
…], 
“paging” 
: 
{ 
“totalCount” 
: 
233, 
“currentMax” 
: 
10, 
“currentOffset” 
: 
40 
} 
}
Linking to Related Entities 
GET 
/phones/1 
{ 
…, 
“links” 
: 
[ 
{ 
“rel” 
: 
“self”, 
“href” 
: 
“http://…”, 
}, 
{ 
“rel” 
: 
“manufacturer”, 
“href” 
: 
“http://…” 
} 
] 
}
Building an 
awesome API using
Phone 
Manufacturer 
Variation 
Domain Model
API Features 
• Accept Header Versioning 
• Predictable Response Codes 
• JSON and XML 
• RESTful URIs 
• Multiple Representations 
• Pagination 
• Custom Responses 
• Related Links
Out of the Box APIs 
@Resource(uri="/phones", 
formats=["json", 
"xml"]) 
class 
Phone 
{ 
… 
}
@Resource URL Mappings 
URL Mapping Verb Action 
/phones GET List of phones 
/phones POST Create new phone 
/phones/{id} GET Get single phone 
/phones/{id} PUT Update phone 
/phones/{id} DELETE Delete phone
Read-Only URL Mappings 
@Resource(uri="/phones", 
formats=["json", 
"xml"], 
readOnly=true) 
URL Mapping Verb Action 
/phones GET List of phones 
/phones/{id} GET Get single phone
Link is on Twitter - @chrislatimer
Demo 
> 
git 
clone 
https://github.com/chrislatimer/gmobile.git 
! 
> 
cd 
gmobile 
! 
> 
git 
checkout 
api-­‐step-­‐1
API Features 
• Accept Header Versioning 
• Multiple Representations 
• Pagination 
• Custom Responses 
• Related Links 
• Predictable Response Codes 
• JSON and XML 
• RESTful URIs
Implementing API Versioning 
Version 1! 
Controller 
Version 2! 
Controller 
API Requests URL Mappings
Controller Namespaces 
Version 
1 
Controller 
class 
PhoneController 
extends 
RestfulController<Phone> 
{ 
static 
namespace 
= 
'v1' 
} 
Version 
2 
Controller 
class 
PhoneController 
extends 
RestfulController<Phone> 
{ 
static 
namespace 
= 
'v2' 
}
URL Mappings 
"/phones"(version:'1.0', 
resources:"phone", 
namespace:'v1') 
! 
"/phones"(version:'2.0', 
resources:"phone", 
namespace:'v2') 
Version 1! 
Controller 
Version 2! 
Controller 
Accept-­‐Version: 
1.0 
Accept-­‐Version: 
2.0
Demo 
> 
git 
checkout 
api-­‐step-­‐2
API Features 
• Multiple Representations 
• Pagination 
• Custom Responses 
• Related Links 
• Predictable Response Codes 
• JSON and XML 
• RESTful URIs 
• Accept Header Versioning
Peanut - Ugliest Dog 2014
! 
"class": 
"org.gmobile.Phone", 
"id": 
1, 
"description": 
null, 
"manufacturer": 
{ 
"class": 
"org.gmobile.Manufacturer", 
"id": 
1 
}, 
"name": 
"Xtreme 
Photon 
Z5", 
"variations": 
[ 
{ 
"class": 
"org.gmobile.Variation", 
"id": 
1 
},… 
] 
Ugliest JSON 2014?
API Features 
• Multiple Representations 
• Pagination 
• Custom Responses 
• Related Links 
• Prettier JSON 
• Predictable Response Codes 
• JSON and XML 
• RESTful URIs 
• Accept Header Versioning
How can we improve our ! 
response payload?
Out of the Box Customization 
include 
attributes exclude 
attributes 
beans 
{ 
bookRenderer(XmlRenderer, 
Book) 
{ 
includes 
= 
[‘title’] 
} 
} 
beans 
{ 
bookRenderer(XmlRenderer, 
Book) 
{ 
excludes 
= 
[‘title’] 
} 
} 
This can be useful for very! 
simple customization
Simplified Picture of the Response Flow 
Controller Renderer Converter Marshaller 
as 
JSON/XML 
respond 
render 
value 
marshal
Creating a Custom Marshaller 
class 
PhoneMarshallerJson 
extends 
ClosureObjectMarshaller<JSON> 
{ 
! 
static 
final 
marshal 
= 
{ 
Phone 
phone 
-­‐> 
def 
map 
= 
[:] 
… 
map 
} 
! 
public 
PhoneMarshallerJson() 
{ 
super(Phone, 
marshal) 
} 
}
Creating a Custom Marshaller 
class 
PhoneMarshallerXml 
extends 
ClosureObjectMarshaller<XML>{ 
! 
def 
static 
final 
marshal 
= 
{ 
Phone 
phone, 
XML 
xml 
-­‐> 
xml.build 
{ 
name(phone.name) 
} 
} 
! 
public 
PhoneMarshallerXml() 
{ 
super(Phone, 
marshal) 
} 
}
Registering a Custom Marshaller 
beans 
= 
{ 
customPhoneJsonMarshaller(ObjectMarshallerRegisterer) 
{ 
marshaller 
= 
new 
PhoneMarshallerJson() 
converterClass 
= 
JSON 
priority 
= 
1 
} 
! 
customPhoneXmlMarshaller(ObjectMarshallerRegisterer) 
{ 
marshaller 
= 
new 
PhoneMarshallerXml() 
converterClass 
= 
XML 
priority 
= 
1 
} 
}
Demo 
> 
git 
checkout 
api-­‐step-­‐3
API Features 
• Multiple Representations 
• Pagination 
• Custom Responses 
• Related Links 
• Predictable Response Codes 
• JSON and XML 
• RESTful URIs 
• Accept Header Versioning 
• Prettier JSON
Creating Named Marshallers 
class 
PhoneMarshallerJsonCompact 
extends 
ClosureObjectMarshaller<JSON>{ 
! 
public 
static 
final 
marshal 
= 
{ 
Phone 
phone 
-­‐> 
def 
map 
= 
[:] 
map.id 
= 
phone.id 
map.name 
= 
phone.name 
map 
} 
! 
public 
PhoneMarshallerJsonCompact() 
{ 
super(Phone, 
marshal) 
} 
! 
}
Registering Named Marshallers 
def 
init 
= 
{ 
JSON.createNamedConfig('compact') 
{ 
it.registerObjectMarshaller(Phone, 
PhoneMarshallerJsonCompact.marshal) 
} 
! 
JSON.createNamedConfig('complete') 
{ 
it.registerObjectMarshaller(Phone, 
PhoneMarshallerJson.marshal) 
} 
}
Demo 
> 
git 
checkout 
api-­‐step-­‐4
API Features 
• Pagination 
• Custom Responses 
• Related Links 
• Predictable Response Codes 
• JSON and XML 
• RESTful URIs 
• Accept Header Versioning 
• Prettier JSON 
• Multiple Representations
Creating a Custom Renderer 
class 
ApiJsonRenderer<T> 
extends 
AbstractRenderer<T> 
{ 
! 
public 
ApiJsonRenderer(Class<T> 
targetClass) 
{ 
super(targetClass, 
MimeType.JSON); 
} 
! 
@Override 
void 
render(T 
object, 
RenderContext 
context) 
{ 
// 
rendering 
logic 
} 
}
Using a Custom Renderer 
def 
show(Phone 
phone) 
{ 
def 
detail 
= 
params.detail 
?: 
"complete" 
withFormat 
{ 
json 
{ 
respond(phone, 
[detail:detail]) 
} 
xml 
{ 
XML.use(params?.detail?.toLowerCase() 
?: 
"complete") 
{ 
respond 
phone 
} 
} 
} 
}
Registering a Custom Renderer 
beans 
= 
{ 
phoneRenderer(ApiJsonRenderer, 
Phone) 
}
Demo 
> 
git 
checkout 
api-­‐step-­‐5
The monkey wrench in ! 
grails.converters.JSON
Creating a Custom Converter 
class 
ApiJSON 
extends 
JSON 
{ 
… 
public 
void 
renderPartial(JSONWriter 
out) 
{ 
initWriter(out) 
super.value(target) 
} 
protected 
initWriter(JSONWriter 
out) 
{ 
writer 
= 
out 
referenceStack 
= 
new 
Stack<Object>(); 
} 
}
Demo 
> 
git 
checkout 
api-­‐step-­‐6
Rendering Paging Info 
def 
index() 
{ 
… 
withFormat 
{ 
json 
{ 
respond 
Phone.list(params), 
[detail:detail, 
paging:[totalCount: 
Phone.count(), 
currentMax: 
params.max, 
curentOffset:offset]] 
} 
…
Rendering Paging Info 
void 
render(T 
object, 
RenderContext 
context) 
{ 
… 
if(context.arguments?.paging) 
{ 
writer.key("paging") 
converter 
= 
context.arguments.paging 
as 
ApiJSON 
converter.renderPartial(writer) 
} 
… 
}
Demo 
> 
git 
checkout 
api-­‐step-­‐7
API Features 
• Custom Responses 
• Related Links 
• Predictable Response Codes 
• JSON and XML 
• RESTful URIs 
• Accept Header Versioning 
• Prettier JSON 
• Multiple Representations 
• Pagination
Customizing Responses 
def 
show(Phone 
phone) 
{ 
… 
withFormat 
{ 
json 
{ 
respond(phone, 
[detail:detail, 
include:params?.list('include')]) 
} 
… 
} 
}
Rendering Custom Responses 
void 
render(T 
object, 
RenderContext 
context) 
{ 
… 
if(context.arguments?.include) 
{ 
writer.key("include") 
writer.array() 
context.arguments?.include.each 
{ 
includeProp 
-­‐> 
JSON.use("compact") 
{ 
converter 
= 
object.properties.get(includeProp) 
as 
ApiJSON 
} 
writer.object() 
writer.key(includeProp) 
converter.renderPartial(writer) 
writer.endObject() 
} 
writer.endArray() 
} 
… 
}
Demo 
> 
git 
checkout 
api-­‐step-­‐8
API Features 
• Predictable Response Codes • Related Links 
• JSON and XML 
• RESTful URIs 
• Accept Header Versioning 
• Prettier JSON 
• Multiple Representations 
• Pagination 
• Custom Responses
Including Related Links 
static 
final 
Closure 
marshal 
= 
{ 
LinkGenerator 
linkGenerator, 
Phone 
phone 
-­‐> 
def 
json 
= 
[:] 
json.id 
= 
phone.id 
json.name 
= 
phone.name 
json.links 
= 
[] 
json.links 
<< 
[rel:"self", 
href:linkGenerator.link(resource: 
phone, 
method: 
HttpMethod.GET, 
absolute: 
true)] 
json 
}
Including Related Links 
static 
final 
Closure 
marshal 
= 
{ 
LinkGenerator 
linkGenerator, 
Phone 
phone 
-­‐> 
def 
json 
= 
[:] 
json.id 
= 
phone.id 
json.name 
= 
phone.name 
json.links 
= 
[] 
json.links 
<< 
[rel:"self", 
href:linkGenerator.link(resource: 
phone, 
method: 
HttpMethod.GET, 
absolute: 
true)] 
json 
}
Including Related Links 
closure.curry(linkGenerator)
Demo 
> 
git 
checkout 
api-­‐step-­‐9
API Features 
• Predictable Response Codes 
• JSON and XML 
• RESTful URIs 
• Accept Header Versioning 
• Prettier JSON 
• Multiple Representations 
• Pagination 
• Custom Responses 
• Related Links
Is this API Awesome? 
It’s getting there…
Follow up questions? 
@chrislatimer 
clatimer@apigee.com

More Related Content

What's hot

The API Facade Pattern: Common Patterns - Episode 2
The API Facade Pattern: Common Patterns - Episode 2The API Facade Pattern: Common Patterns - Episode 2
The API Facade Pattern: Common Patterns - Episode 2Apigee | Google Cloud
 
Scaling with swagger
Scaling with swaggerScaling with swagger
Scaling with swaggerTony Tam
 
Design mobile efficient Apis
Design mobile efficient ApisDesign mobile efficient Apis
Design mobile efficient ApisMobile Rtpl
 
Data normalization across API interactions
Data normalization across API interactionsData normalization across API interactions
Data normalization across API interactionsCloud Elements
 
RESTful Api practices Rails 3
RESTful Api practices Rails 3RESTful Api practices Rails 3
RESTful Api practices Rails 3Anton Narusberg
 
Server Installation and Configuration with Chef
Server Installation and Configuration with ChefServer Installation and Configuration with Chef
Server Installation and Configuration with ChefRaimonds Simanovskis
 
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜崇之 清水
 
"Design First" APIs with Swagger
"Design First" APIs with Swagger"Design First" APIs with Swagger
"Design First" APIs with Swaggerscolestock
 
Designing your API Server for mobile apps
Designing your API Server for mobile appsDesigning your API Server for mobile apps
Designing your API Server for mobile appsMugunth Kumar
 
The API Facade Pattern: Technology - Episode 3
The API Facade Pattern: Technology - Episode 3The API Facade Pattern: Technology - Episode 3
The API Facade Pattern: Technology - Episode 3Apigee | Google Cloud
 
Rails as iOS Application Backend
Rails as iOS Application BackendRails as iOS Application Backend
Rails as iOS Application Backendmaximeguilbot
 
Designing and Running a GraphQL API
Designing and Running a GraphQL APIDesigning and Running a GraphQL API
Designing and Running a GraphQL APIAtlassian
 
Mobile APIs: Optimizing APIs for Many Devices
Mobile APIs: Optimizing APIs for Many DevicesMobile APIs: Optimizing APIs for Many Devices
Mobile APIs: Optimizing APIs for Many DevicesApigee | Google Cloud
 

What's hot (20)

The API Facade Pattern: Common Patterns - Episode 2
The API Facade Pattern: Common Patterns - Episode 2The API Facade Pattern: Common Patterns - Episode 2
The API Facade Pattern: Common Patterns - Episode 2
 
Scaling with swagger
Scaling with swaggerScaling with swagger
Scaling with swagger
 
Design mobile efficient Apis
Design mobile efficient ApisDesign mobile efficient Apis
Design mobile efficient Apis
 
Selenium-4-and-appium-2
Selenium-4-and-appium-2Selenium-4-and-appium-2
Selenium-4-and-appium-2
 
Data normalization across API interactions
Data normalization across API interactionsData normalization across API interactions
Data normalization across API interactions
 
RESTful Api practices Rails 3
RESTful Api practices Rails 3RESTful Api practices Rails 3
RESTful Api practices Rails 3
 
WordPress REST API
WordPress REST APIWordPress REST API
WordPress REST API
 
Raml part 1
Raml part 1Raml part 1
Raml part 1
 
Huge: Running an API at Scale
Huge: Running an API at ScaleHuge: Running an API at Scale
Huge: Running an API at Scale
 
API Façade Pattern
API Façade PatternAPI Façade Pattern
API Façade Pattern
 
Server Installation and Configuration with Chef
Server Installation and Configuration with ChefServer Installation and Configuration with Chef
Server Installation and Configuration with Chef
 
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
RESTful API を Chalice で紐解く 〜 Python Serverless Microframework for AWS 〜
 
Ruby On Grape
Ruby On GrapeRuby On Grape
Ruby On Grape
 
"Design First" APIs with Swagger
"Design First" APIs with Swagger"Design First" APIs with Swagger
"Design First" APIs with Swagger
 
Designing your API Server for mobile apps
Designing your API Server for mobile appsDesigning your API Server for mobile apps
Designing your API Server for mobile apps
 
The API Facade Pattern: Technology - Episode 3
The API Facade Pattern: Technology - Episode 3The API Facade Pattern: Technology - Episode 3
The API Facade Pattern: Technology - Episode 3
 
Rails as iOS Application Backend
Rails as iOS Application BackendRails as iOS Application Backend
Rails as iOS Application Backend
 
Chef introduction
Chef introductionChef introduction
Chef introduction
 
Designing and Running a GraphQL API
Designing and Running a GraphQL APIDesigning and Running a GraphQL API
Designing and Running a GraphQL API
 
Mobile APIs: Optimizing APIs for Many Devices
Mobile APIs: Optimizing APIs for Many DevicesMobile APIs: Optimizing APIs for Many Devices
Mobile APIs: Optimizing APIs for Many Devices
 

Similar to Building Awesome APIs in Grails

Api development with rails
Api development with railsApi development with rails
Api development with railsEdwin Cruz
 
Api's and ember js
Api's and ember jsApi's and ember js
Api's and ember jsEdwin Cruz
 
Prairie DevCon 2015 - Crafting Evolvable API Responses
Prairie DevCon 2015 - Crafting Evolvable API ResponsesPrairie DevCon 2015 - Crafting Evolvable API Responses
Prairie DevCon 2015 - Crafting Evolvable API Responsesdarrelmiller71
 
Cloud2Car - Force.com and the Internet of Things
Cloud2Car - Force.com and the Internet of ThingsCloud2Car - Force.com and the Internet of Things
Cloud2Car - Force.com and the Internet of ThingsSalesforce Developers
 
What Makes a Great Open API?
What Makes a Great Open API?What Makes a Great Open API?
What Makes a Great Open API?John Musser
 
How To Structure Go Applications - Paul Bellamy - Codemotion Milan 2016
How To Structure Go Applications - Paul Bellamy - Codemotion Milan 2016How To Structure Go Applications - Paul Bellamy - Codemotion Milan 2016
How To Structure Go Applications - Paul Bellamy - Codemotion Milan 2016Codemotion
 
David Gómez G. - Hypermedia APIs for headless platforms and Data Integration ...
David Gómez G. - Hypermedia APIs for headless platforms and Data Integration ...David Gómez G. - Hypermedia APIs for headless platforms and Data Integration ...
David Gómez G. - Hypermedia APIs for headless platforms and Data Integration ...Codemotion
 
Cdm mil-18 - hypermedia ap is for headless platforms and data integration
Cdm mil-18 - hypermedia ap is for headless platforms and data integrationCdm mil-18 - hypermedia ap is for headless platforms and data integration
Cdm mil-18 - hypermedia ap is for headless platforms and data integrationDavid Gómez García
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...Fabio Franzini
 
Going FaaSter, Functions as a Service at Netflix
Going FaaSter, Functions as a Service at NetflixGoing FaaSter, Functions as a Service at Netflix
Going FaaSter, Functions as a Service at NetflixYunong Xiao
 
Lets dance- Dutch Architecture Conference (LAC) 2018
Lets dance- Dutch Architecture Conference (LAC) 2018Lets dance- Dutch Architecture Conference (LAC) 2018
Lets dance- Dutch Architecture Conference (LAC) 2018Yenlo
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfonyFrancois Zaninotto
 
The liferay case: lessons learned evolving from RPC to Hypermedia REST APIs
The liferay case: lessons learned evolving from RPC to Hypermedia REST APIsThe liferay case: lessons learned evolving from RPC to Hypermedia REST APIs
The liferay case: lessons learned evolving from RPC to Hypermedia REST APIsJorge Ferrer
 
Continuous Integration and Deployment Best Practices on AWS
Continuous Integration and Deployment Best Practices on AWSContinuous Integration and Deployment Best Practices on AWS
Continuous Integration and Deployment Best Practices on AWSDanilo Poccia
 
Mobile Development integration tests
Mobile Development integration testsMobile Development integration tests
Mobile Development integration testsKenneth Poon
 

Similar to Building Awesome APIs in Grails (20)

Api development with rails
Api development with railsApi development with rails
Api development with rails
 
Api's and ember js
Api's and ember jsApi's and ember js
Api's and ember js
 
Mashing Up The Guardian
Mashing Up The GuardianMashing Up The Guardian
Mashing Up The Guardian
 
Prairie DevCon 2015 - Crafting Evolvable API Responses
Prairie DevCon 2015 - Crafting Evolvable API ResponsesPrairie DevCon 2015 - Crafting Evolvable API Responses
Prairie DevCon 2015 - Crafting Evolvable API Responses
 
Cloud2Car - Force.com and the Internet of Things
Cloud2Car - Force.com and the Internet of ThingsCloud2Car - Force.com and the Internet of Things
Cloud2Car - Force.com and the Internet of Things
 
Mashing Up The Guardian
Mashing Up The GuardianMashing Up The Guardian
Mashing Up The Guardian
 
What Makes a Great Open API?
What Makes a Great Open API?What Makes a Great Open API?
What Makes a Great Open API?
 
Don't screw it up! How to build durable API
Don't screw it up! How to build durable API Don't screw it up! How to build durable API
Don't screw it up! How to build durable API
 
How To Structure Go Applications - Paul Bellamy - Codemotion Milan 2016
How To Structure Go Applications - Paul Bellamy - Codemotion Milan 2016How To Structure Go Applications - Paul Bellamy - Codemotion Milan 2016
How To Structure Go Applications - Paul Bellamy - Codemotion Milan 2016
 
David Gómez G. - Hypermedia APIs for headless platforms and Data Integration ...
David Gómez G. - Hypermedia APIs for headless platforms and Data Integration ...David Gómez G. - Hypermedia APIs for headless platforms and Data Integration ...
David Gómez G. - Hypermedia APIs for headless platforms and Data Integration ...
 
Cdm mil-18 - hypermedia ap is for headless platforms and data integration
Cdm mil-18 - hypermedia ap is for headless platforms and data integrationCdm mil-18 - hypermedia ap is for headless platforms and data integration
Cdm mil-18 - hypermedia ap is for headless platforms and data integration
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
Going FaaSter, Functions as a Service at Netflix
Going FaaSter, Functions as a Service at NetflixGoing FaaSter, Functions as a Service at Netflix
Going FaaSter, Functions as a Service at Netflix
 
Lets dance- Dutch Architecture Conference (LAC) 2018
Lets dance- Dutch Architecture Conference (LAC) 2018Lets dance- Dutch Architecture Conference (LAC) 2018
Lets dance- Dutch Architecture Conference (LAC) 2018
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfony
 
What Makes a Great Open API?
What Makes a Great Open API?What Makes a Great Open API?
What Makes a Great Open API?
 
Swift meetup22june2015
Swift meetup22june2015Swift meetup22june2015
Swift meetup22june2015
 
The liferay case: lessons learned evolving from RPC to Hypermedia REST APIs
The liferay case: lessons learned evolving from RPC to Hypermedia REST APIsThe liferay case: lessons learned evolving from RPC to Hypermedia REST APIs
The liferay case: lessons learned evolving from RPC to Hypermedia REST APIs
 
Continuous Integration and Deployment Best Practices on AWS
Continuous Integration and Deployment Best Practices on AWSContinuous Integration and Deployment Best Practices on AWS
Continuous Integration and Deployment Best Practices on AWS
 
Mobile Development integration tests
Mobile Development integration testsMobile Development integration tests
Mobile Development integration tests
 

Recently uploaded

Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 

Recently uploaded (20)

Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 

Building Awesome APIs in Grails

  • 1. Building Awesome APIs in Grails By Chris Latimer © 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.
  • 2. 2 What makes an API awesome?
  • 3. 3 Is it using JSON payloads instead of XML?
  • 4. Using this Template 4 Is it strict adherence to REST principles?
  • 6. 6
  • 7. 7 Predictable and Consistent
  • 8. 8 "uri": "/categories/activism", "name": "Activism & Non Profits", "link": “https://vimeo.com/…”, … "metadata": { "connections": {…} } Category ! Response: "uri": "/channels/804185", "name": "School Intercom", "link": “https://vimeo.com/…”, … "metadata": { "connections": {…} } Channel ! Response:
  • 9. 9 <photo id="2636" owner="47058503995@N01" secret="a123456" server=“2" title=“test_04” ispublic=“1" isfriend="0" isfamily="0" /> <contact nsid="12037949629@N01" username="Eric" iconserver="1" realname="Eric Costello" friend="1" family="0" ignored="1" />
  • 10. 10 Stable Versions URI Based Accept Header /v1/endpoint ! /v2/endpoint Accept-­‐Version: 1.0 ! Accept-­‐Version: 1.1 Content Type Accept: application/vnd.your.api.v2+json ! Accept: application/vnd.your.api.v2.1+json
  • 11. 11 Predictable Response Codes 2xx Successful 4xx Client Error 400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found 5xx Server Error 500 Server Error 502 Bad Gateway 503 Unavailable 200 Success 201 Created !
  • 13. 13 Intuitive URI Structure URI Description /group/{id} A Facebook group /group/{id}/feed This group’s feed /group/{id}/files Files uploaded to this group /group/{id}/events This group’s events
  • 14. 14 Intuitive Navigation Pagination "total": 659212, "page": 2, "per_page": 10, "paging": { "next": "/channels?page=3", "previous": "/channels?page=1", "first": "/channels?page=1", "last": "/channels?page=65922" }
  • 15. 15 Intuitive Navigation Related Resources { “uri": "/categories/experimental", "name": "Experimental", "subcategories": [ { "uri": “/categories/experimental/animation", "name": "Animation", "link": “https://vimeo.com/categories/…” }… ] }
  • 17. 17 Partial Responses Get Full Response /feeds/api/users/default/uploads Get Partial Response /feeds/api/users/default/uploads? fields=entry(title,gd:comments,yt:statistics)
  • 18. 18 Result Filtering Get List of Videos /feeds/api/videos?q=surfing&max-­‐results=10 Get Videos with 1,000,000+ Views /feeds/api/videos?q=surfing&max-­‐results=10 &fields=entry[yt:statistics/@viewCount > 1000000]
  • 19. 19 Customized Responses ItemLookup - Default ItemId=B00008OE6I ItemLookup - Default With Reviews ItemId=B00008OE6I &ResponseGroup=Reviews ItemLookup - Large With Reviews and Offers ItemId=B00008OE6I &ResponseGroup=Large,Reviews,Offers
  • 20. 20 Easy to Learn and Experiment With
  • 21. 21
  • 22. 22
  • 23. 23 Designing an awesome API
  • 25. G
  • 26. Phone Shopping App Potential Resources /phones ! /devices ! /manufacturers
  • 27. Phone Shopping App API Features Pagination ! Filtering ! Versioning
  • 28. Phone Shopping App Potential Resources /phoneVariations ! /phone/{id} ! /phone/{id}/variations
  • 29. Phone Shopping App API Features Complete vs. Compact representations ! Including related entities ! Linking to other resources
  • 30. Phone API Endpoints URI Verb Description /phones GET Get a list of phones /phones/{id} GET Get phone details /phones/{id}/manufacturer GET Get phone’s manufacturer /phones/{id}/variations GET Get variations of a phone
  • 31. Phone API Versioning Header Based Accept-­‐Version: 1.0 ! Accept-­‐Version: 2.0
  • 32. General Response Structure Patterns { “entity” : { “attr1” : “value1”, “attr2” : “value2”, … }, “metadata” : { } } { “attr1” : “value1”, “attr2” : “value2”, … }
  • 33. General Response Structure Patterns { “entities” : [ { “attr1” : “value1”, “attr2” : “value2”, … },{…},{…}… ], “metadata” : { } } [ { “attr1” : “value1”, “attr2” : “value2”, … }, {…},{…}… ]
  • 34. API Formats JSON Default “phones” : [ { “name”:“iPhone 5s”, “basePrice”:599.99, … } ] XML by Request <phones> <phone> <name>iPhone 5s</name> … </phone> … </phones>
  • 35. Intuitive Response Structures Single Response Collection Response { { “phones” : [ {…}, {…}, …], “paging” : { … } } phone: { “key1” : “value1”, … “keyN” : “valueN”, “links” : [ {…},{…}…] } }
  • 36. Complete and Compact Representations Attribute Compact Complete name basePrice variations manufacturer
  • 37. Customized Responses GET /phones/1 { “name” : “iPhone5s”, … } GET /phones/1?include=accessories { “name” : “iPhone5s”, … “includes” : [ { “accessories” : […] } ] }
  • 38. Pagination GET /phones { “phones” : [ {…}, {…}, …], “paging” : { “totalCount” : 233, “currentMax” : 10, “currentOffset” : 40 } }
  • 39. Linking to Related Entities GET /phones/1 { …, “links” : [ { “rel” : “self”, “href” : “http://…”, }, { “rel” : “manufacturer”, “href” : “http://…” } ] }
  • 40. Building an awesome API using
  • 42. API Features • Accept Header Versioning • Predictable Response Codes • JSON and XML • RESTful URIs • Multiple Representations • Pagination • Custom Responses • Related Links
  • 43. Out of the Box APIs @Resource(uri="/phones", formats=["json", "xml"]) class Phone { … }
  • 44. @Resource URL Mappings URL Mapping Verb Action /phones GET List of phones /phones POST Create new phone /phones/{id} GET Get single phone /phones/{id} PUT Update phone /phones/{id} DELETE Delete phone
  • 45. Read-Only URL Mappings @Resource(uri="/phones", formats=["json", "xml"], readOnly=true) URL Mapping Verb Action /phones GET List of phones /phones/{id} GET Get single phone
  • 46.
  • 47. Link is on Twitter - @chrislatimer
  • 48. Demo > git clone https://github.com/chrislatimer/gmobile.git ! > cd gmobile ! > git checkout api-­‐step-­‐1
  • 49. API Features • Accept Header Versioning • Multiple Representations • Pagination • Custom Responses • Related Links • Predictable Response Codes • JSON and XML • RESTful URIs
  • 50. Implementing API Versioning Version 1! Controller Version 2! Controller API Requests URL Mappings
  • 51. Controller Namespaces Version 1 Controller class PhoneController extends RestfulController<Phone> { static namespace = 'v1' } Version 2 Controller class PhoneController extends RestfulController<Phone> { static namespace = 'v2' }
  • 52. URL Mappings "/phones"(version:'1.0', resources:"phone", namespace:'v1') ! "/phones"(version:'2.0', resources:"phone", namespace:'v2') Version 1! Controller Version 2! Controller Accept-­‐Version: 1.0 Accept-­‐Version: 2.0
  • 53. Demo > git checkout api-­‐step-­‐2
  • 54. API Features • Multiple Representations • Pagination • Custom Responses • Related Links • Predictable Response Codes • JSON and XML • RESTful URIs • Accept Header Versioning
  • 55. Peanut - Ugliest Dog 2014
  • 56. ! "class": "org.gmobile.Phone", "id": 1, "description": null, "manufacturer": { "class": "org.gmobile.Manufacturer", "id": 1 }, "name": "Xtreme Photon Z5", "variations": [ { "class": "org.gmobile.Variation", "id": 1 },… ] Ugliest JSON 2014?
  • 57. API Features • Multiple Representations • Pagination • Custom Responses • Related Links • Prettier JSON • Predictable Response Codes • JSON and XML • RESTful URIs • Accept Header Versioning
  • 58. How can we improve our ! response payload?
  • 59. Out of the Box Customization include attributes exclude attributes beans { bookRenderer(XmlRenderer, Book) { includes = [‘title’] } } beans { bookRenderer(XmlRenderer, Book) { excludes = [‘title’] } } This can be useful for very! simple customization
  • 60. Simplified Picture of the Response Flow Controller Renderer Converter Marshaller as JSON/XML respond render value marshal
  • 61. Creating a Custom Marshaller class PhoneMarshallerJson extends ClosureObjectMarshaller<JSON> { ! static final marshal = { Phone phone -­‐> def map = [:] … map } ! public PhoneMarshallerJson() { super(Phone, marshal) } }
  • 62. Creating a Custom Marshaller class PhoneMarshallerXml extends ClosureObjectMarshaller<XML>{ ! def static final marshal = { Phone phone, XML xml -­‐> xml.build { name(phone.name) } } ! public PhoneMarshallerXml() { super(Phone, marshal) } }
  • 63. Registering a Custom Marshaller beans = { customPhoneJsonMarshaller(ObjectMarshallerRegisterer) { marshaller = new PhoneMarshallerJson() converterClass = JSON priority = 1 } ! customPhoneXmlMarshaller(ObjectMarshallerRegisterer) { marshaller = new PhoneMarshallerXml() converterClass = XML priority = 1 } }
  • 64. Demo > git checkout api-­‐step-­‐3
  • 65. API Features • Multiple Representations • Pagination • Custom Responses • Related Links • Predictable Response Codes • JSON and XML • RESTful URIs • Accept Header Versioning • Prettier JSON
  • 66. Creating Named Marshallers class PhoneMarshallerJsonCompact extends ClosureObjectMarshaller<JSON>{ ! public static final marshal = { Phone phone -­‐> def map = [:] map.id = phone.id map.name = phone.name map } ! public PhoneMarshallerJsonCompact() { super(Phone, marshal) } ! }
  • 67. Registering Named Marshallers def init = { JSON.createNamedConfig('compact') { it.registerObjectMarshaller(Phone, PhoneMarshallerJsonCompact.marshal) } ! JSON.createNamedConfig('complete') { it.registerObjectMarshaller(Phone, PhoneMarshallerJson.marshal) } }
  • 68. Demo > git checkout api-­‐step-­‐4
  • 69. API Features • Pagination • Custom Responses • Related Links • Predictable Response Codes • JSON and XML • RESTful URIs • Accept Header Versioning • Prettier JSON • Multiple Representations
  • 70. Creating a Custom Renderer class ApiJsonRenderer<T> extends AbstractRenderer<T> { ! public ApiJsonRenderer(Class<T> targetClass) { super(targetClass, MimeType.JSON); } ! @Override void render(T object, RenderContext context) { // rendering logic } }
  • 71. Using a Custom Renderer def show(Phone phone) { def detail = params.detail ?: "complete" withFormat { json { respond(phone, [detail:detail]) } xml { XML.use(params?.detail?.toLowerCase() ?: "complete") { respond phone } } } }
  • 72. Registering a Custom Renderer beans = { phoneRenderer(ApiJsonRenderer, Phone) }
  • 73. Demo > git checkout api-­‐step-­‐5
  • 74. The monkey wrench in ! grails.converters.JSON
  • 75. Creating a Custom Converter class ApiJSON extends JSON { … public void renderPartial(JSONWriter out) { initWriter(out) super.value(target) } protected initWriter(JSONWriter out) { writer = out referenceStack = new Stack<Object>(); } }
  • 76. Demo > git checkout api-­‐step-­‐6
  • 77. Rendering Paging Info def index() { … withFormat { json { respond Phone.list(params), [detail:detail, paging:[totalCount: Phone.count(), currentMax: params.max, curentOffset:offset]] } …
  • 78. Rendering Paging Info void render(T object, RenderContext context) { … if(context.arguments?.paging) { writer.key("paging") converter = context.arguments.paging as ApiJSON converter.renderPartial(writer) } … }
  • 79. Demo > git checkout api-­‐step-­‐7
  • 80. API Features • Custom Responses • Related Links • Predictable Response Codes • JSON and XML • RESTful URIs • Accept Header Versioning • Prettier JSON • Multiple Representations • Pagination
  • 81. Customizing Responses def show(Phone phone) { … withFormat { json { respond(phone, [detail:detail, include:params?.list('include')]) } … } }
  • 82. Rendering Custom Responses void render(T object, RenderContext context) { … if(context.arguments?.include) { writer.key("include") writer.array() context.arguments?.include.each { includeProp -­‐> JSON.use("compact") { converter = object.properties.get(includeProp) as ApiJSON } writer.object() writer.key(includeProp) converter.renderPartial(writer) writer.endObject() } writer.endArray() } … }
  • 83. Demo > git checkout api-­‐step-­‐8
  • 84. API Features • Predictable Response Codes • Related Links • JSON and XML • RESTful URIs • Accept Header Versioning • Prettier JSON • Multiple Representations • Pagination • Custom Responses
  • 85. Including Related Links static final Closure marshal = { LinkGenerator linkGenerator, Phone phone -­‐> def json = [:] json.id = phone.id json.name = phone.name json.links = [] json.links << [rel:"self", href:linkGenerator.link(resource: phone, method: HttpMethod.GET, absolute: true)] json }
  • 86. Including Related Links static final Closure marshal = { LinkGenerator linkGenerator, Phone phone -­‐> def json = [:] json.id = phone.id json.name = phone.name json.links = [] json.links << [rel:"self", href:linkGenerator.link(resource: phone, method: HttpMethod.GET, absolute: true)] json }
  • 87. Including Related Links closure.curry(linkGenerator)
  • 88. Demo > git checkout api-­‐step-­‐9
  • 89. API Features • Predictable Response Codes • JSON and XML • RESTful URIs • Accept Header Versioning • Prettier JSON • Multiple Representations • Pagination • Custom Responses • Related Links
  • 90. Is this API Awesome? It’s getting there…
  • 91. Follow up questions? @chrislatimer clatimer@apigee.com