rest api's: easier than you imagined

94
REST API’s: Easier Than You Imagined @AdamTuttle FusionGrokker.com You are here

Upload: adam-tuttle

Post on 20-May-2015

1.655 views

Category:

Technology


1 download

DESCRIPTION

Taffy has changed a fair amount, and for the better, since its release 2.5 years ago. It's also now used in production on Adobe ColdFusion and Railo every day of the year. It's baked into Slatwall, the open source eCommerce plugin for Mura. It's used by an augmented reality iPhone application to send data and photos between phones and servers. And still, it's the easiest, fastest way to get the job done from a CFML platform; and I'd like to help you get started writing API's today. This session will teach you the basics of REST, as well as everything you need to know to get started writing REST API's with Taffy. From "what's an HTTP verb?" to Dependency Injection, to Uploading Files, and everywhere in between. We'll also cover adding an API to an existing application because as we all know, starting from scratch is not often a privilege of which we get the pleasure.

TRANSCRIPT

Page 1: REST API's: Easier Than You Imagined

REST API’s:Easier Than You Imagined

@AdamTuttleFusionGrokker.com

You are here

Page 2: REST API's: Easier Than You Imagined

Agenda

• REST 101

• Creating REST APIs with ColdFusion*

• Adding an API to an existing app

• Best Practices, Patterns, Anti-patterns

Page 3: REST API's: Easier Than You Imagined

Agenda

• REST 101

• Creating REST APIs with ColdFusion*

• Adding an API to an existing app

• Best Practices, Patterns, Anti-patterns

*Using Taffy

Page 4: REST API's: Easier Than You Imagined
Page 5: REST API's: Easier Than You Imagined

I’m @AdamTuttle

Page 6: REST API's: Easier Than You Imagined

That’s Me!

Page 7: REST API's: Easier Than You Imagined

I make stuff

Page 8: REST API's: Easier Than You Imagined

• Created May 2010

• #6 most watched ColdFusion project on GitHub

• 8+ people contributing

• Syntax doesn’t suck

I made Taffy

Page 9: REST API's: Easier Than You Imagined

Who Uses Taffy?

Page 10: REST API's: Easier Than You Imagined

REST 101

Page 11: REST API's: Easier Than You Imagined

What is REST?

Page 12: REST API's: Easier Than You Imagined

What is REST?

Page 13: REST API's: Easier Than You Imagined

Request ResponseGET http://...HeadersRequest data

200 OKHeadersResponse data

Page 14: REST API's: Easier Than You Imagined
Page 15: REST API's: Easier Than You Imagined

<form action=”http://...” method=”POST”>

</form>

Page 16: REST API's: Easier Than You Imagined

VocabularyVerb

Noun

Data Format (“Mime Type”)

Data

Page 17: REST API's: Easier Than You Imagined

HTTP VerbsGET Read

POST Insert

PUT Update

DELETE Delete

OPTIONS Allowed Verbs

HEAD Headers Only

Page 18: REST API's: Easier Than You Imagined

HTTP VerbsGET Read

POST Insert

PUT Update

DELETE Delete

OPTIONS Allowed Verbs

HEAD Headers Only

Safe

Unsafe

Idempotent

Page 20: REST API's: Easier Than You Imagined

<form action=”http://...” method=”POST”>

</form>

Page 21: REST API's: Easier Than You Imagined

<form action=”http://...” method=”POST”>

</form>

Noun

Page 22: REST API's: Easier Than You Imagined

<form action=”http://...” method=”POST”>

</form>

NounVerb

Page 23: REST API's: Easier Than You Imagined

<form action=”http://...” method=”POST”>

</form>

NounVerb

<input type=”hidden” name=”foo” value=”bar” />

Request Data

Page 24: REST API's: Easier Than You Imagined

Data FormatHTML: text/html

Image: image/jpeg

JSON: application/json

XML: application/xml

ZIP: application/octet-stream

Page 25: REST API's: Easier Than You Imagined

HTTP Status Codes

• 2xx = Success

• 3xx = Redirect

• 4xx = Client Error

• 5xx = Server Error

Page 26: REST API's: Easier Than You Imagined

Do Not Write This Down

This will not be on the test

Page 27: REST API's: Easier Than You Imagined

Raw Request$ telnet www.google.com 80Trying 173.194.73.104...Connected to www.google.com.Escape character is '^]'.GET /index.html HTTP/1.1Host: www.google.com{blank line}

Page 28: REST API's: Easier Than You Imagined

Raw ResponseHTTP/1.1 200 OKDate: Sat, 11 May 2013 18:29:45 GMT[...]X-XSS-Protection: 1; mode=blockX-Frame-Options: SAMEORIGINTransfer-Encoding: chunked

<!doctype html><html..........

}ResponseHeaders

Page 29: REST API's: Easier Than You Imagined

Web APIs work similarly

Page 30: REST API's: Easier Than You Imagined

Raw RequestPOST /api/v1/tweets HTTP/1.1Host: twitter.comContent-Type: application/jsonAccept: application/json, */*;q=0.9User-Agent: MyTwitterApp{

“username”: “AdamTuttle”,“tweet”: “Hello, #CFObjective!”

}[blank line]

Page 31: REST API's: Easier Than You Imagined

Raw ResponseHTTP/1.1 201 Tweet CreatedContent-Type: application/json; charset=UTF-8{

...}

Page 32: REST API's: Easier Than You Imagined

<form action=”http://.../foo/bar” method=”POST”>

</form>

<input type=”hidden” name=”foo” value=”bar” />

Page 33: REST API's: Easier Than You Imagined

POST /....../foo/barHost: www.example.comContent-Type: x-www-form-urlencodedAccept: application/json

foo=bar&flap=jacks

Page 34: REST API's: Easier Than You Imagined

POST /....../foo/barHost: www.example.comContent-Type: x-www-form-urlencodedAccept: application/json

foo=bar&flap=jacks

No question mark

Page 35: REST API's: Easier Than You Imagined

Creating REST APIs with ColdFusion*

*Using Taffy

Page 36: REST API's: Easier Than You Imagined

Choices• Taffy

• Mach-II

• ColdBox

• Relaxation

• Powernap

• RestfulCF

• CF10

Page 37: REST API's: Easier Than You Imagined

Why I (still) <3 Taffy• Simplest, Most-concise syntax

• Easily extended (security layer, etc)

• Doesn’t require access to CFAdmin

• Portable (Railo, CF8+ supported)

• Plays fine with any app framework

• ONLY Convention-over-Config option (CF10?)

• Open Source

Page 38: REST API's: Easier Than You Imagined

Your FirstTaffy-powered API

Page 39: REST API's: Easier Than You Imagined

Application.cfc

component extends=”taffy.core.api” {}

index.cfm

<!--- this space intentionally blank--->

Page 40: REST API's: Easier Than You Imagined
Page 41: REST API's: Easier Than You Imagined

An API w/ Results... that fits into a

Tweet

Page 42: REST API's: Easier Than You Imagined

Application.cfccomponent extends=”taffy.core.api”{}

index.cfm

resources/hi.cfccomponent extends = ”taffy.core.resource” taffy_uri = ”/hi”{ function get(){ return representationOf(“hi”); }}

Page 43: REST API's: Easier Than You Imagined

Application.cfccomponent extends=”taffy.core.api”{}

index.cfm

resources/hi.cfccomponent extends = ”taffy.core.resource” taffy_uri = ”/hi”{ function get(){ return representationOf(“hi”); }}

36

104

Page 44: REST API's: Easier Than You Imagined
Page 45: REST API's: Easier Than You Imagined
Page 46: REST API's: Easier Than You Imagined
Page 47: REST API's: Easier Than You Imagined
Page 48: REST API's: Easier Than You Imagined
Page 49: REST API's: Easier Than You Imagined

Anatomy of an API

Page 50: REST API's: Easier Than You Imagined

Anatomy of an API

Application.cfcindex.cfm/resources/...

Page 51: REST API's: Easier Than You Imagined

Application.cfccomponent extends=”taffy.core.api” {

variables.framework = {};

function applicationStartEvent(){} function requestStartEvent(){} function onTaffyRequest(){}

}

Page 52: REST API's: Easier Than You Imagined

index.cfm

Page 53: REST API's: Easier Than You Imagined

Resources

• Live in /resources subfolder• Each resource defines its own URI• Only implemented verbs are allowed• Collections vs. Members

Page 54: REST API's: Easier Than You Imagined

Resources

component extends=”taffy.core.resource”taffy_uri=”/foo/{fooId}” {

public function get(fooId){} public function delete(fooId){}

}

Page 55: REST API's: Easier Than You Imagined

3 Data Input Options

Page 56: REST API's: Easier Than You Imagined

Tokens & Query Params

• Mapped by name to method args

• Tokens are the same for every method in a resource CFC and always required (otherwise 404)

• Query Params are optional; also passed by name

Page 57: REST API's: Easier Than You Imagined

Simple Inputcomponent extends=”taffy.core.resource” taffy_uri=”/foo/{fooId}” {

function get(fooId, optional string city){ //... }}

<cfargument name=”city” required=”false” />

/api/index.cfm/foo/17?city=Philadelphia

Page 58: REST API's: Easier Than You Imagined

Simple Inputcomponent extends=”taffy.core.resource” taffy_uri=”/foo/{fooId}” {

function get(fooId, optional string city){ //... }}

<cfargument name=”city” required=”false” />

/api/index.cfm/foo/17?city=Philadelphia

Page 59: REST API's: Easier Than You Imagined

Simple Inputcomponent extends=”taffy.core.resource” taffy_uri=”/foo/{fooId}” {

function get(fooId, optional string city){ //... }}

<cfargument name=”city” required=”false” />

/api/index.cfm/foo/17?city=Philadelphia

Page 60: REST API's: Easier Than You Imagined

Simple Inputcomponent extends=”taffy.core.resource” taffy_uri=”/foo/{fooId}” {

function get(fooId, optional string city){ //... }}

<cfargument name=”city” required=”false” />

/api/index.cfm/foo/17?city=Philadelphia

Page 61: REST API's: Easier Than You Imagined

Simple Inputcomponent extends=”taffy.core.resource” taffy_uri=”/foo/{fooId}” {

function get(fooId, optional string city){ //... }}

<cfargument name=”city” required=”false” />

/api/index.cfm/foo/17?city=Philadelphia

Page 62: REST API's: Easier Than You Imagined

Request Body InputTaffy Supports JSON and Form-encoded bodies as long as you set the Content-Type header

{“foo”:”bar baz”,”baz”:true}

foo=bar%20baz&baz=true

Page 63: REST API's: Easier Than You Imagined

Data Output

Page 64: REST API's: Easier Than You Imagined

Returning DatarepresentationOf method abstracts serialization

component extends=”taffy.core.resource”taffy_uri=”/foo” {

public function get(){ var querySvc = new Query(); //... return representationOf( someQuery ); }

}

Page 65: REST API's: Easier Than You Imagined

Returning DatarepresentationOf method abstracts serialization

component extends=”taffy.core.resource”taffy_uri=”/foo” {

public function get(){ var querySvc = new Query(); //... return representationOf( myStruct ); }

}

Page 66: REST API's: Easier Than You Imagined

Returning DatarepresentationOf method abstracts serialization

component extends=”taffy.core.resource”taffy_uri=”/foo” {

public function get(){ var querySvc = new Query(); //... return representationOf( myArray ); }

}

Page 67: REST API's: Easier Than You Imagined

ColdFusion serializes queries ... abnormally.

{"COLUMNS":["COL1","COL2","COL3"],"DATA":[[3,3,true]]}

Taffy’s queryToArray() helper convertsqueries to an array of structures

[ {"CoL1":3,"col2":3,"col3":true}, {"CoL1":4,"col2":4,"col3":false}]

queryToArray()

Page 68: REST API's: Easier Than You Imagined

queryToArray()

return representationOf(queryToArray( myQuery )

);

Page 69: REST API's: Easier Than You Imagined

Response Headersreturn representationOf( ...).withStatus( 201, “Created”).withHeaders( { “X-MY-HEADER” = “My header value” });

Page 70: REST API's: Easier Than You Imagined

Empty Success

return noData().withStatus(201, “Created”);

return noData();

Page 71: REST API's: Easier Than You Imagined

More Advancedgithub.com/atuttle/Taffy/wiki

Page 72: REST API's: Easier Than You Imagined

Dependency Injection/resources/FooService.cfc

/resources/FooCollection.cfc

component { function doStuff(){...}; }

component extends=”taffy.core.resource” ...{ property name=”FooService”;

function get(){ local.foo = this.FooService.doStuff(); //... }}

Page 73: REST API's: Easier Than You Imagined

Resource Subfolders/resources/fooCollection.cfc “fooCollection”

/resources/Cat/Grumpy.cfc “CatGrumpy”

/resources/Services/Old/User.cfc “ServicesOldUser”

Bean Nam

e Generation

Page 74: REST API's: Easier Than You Imagined

• Custom Token Regex

• Intercept requests w/ onTaffyRequest

• 3rd Party Bean Factories

• Verb:Method mapping w/ metadata

• Custom result serializers

• Environment specific config

• ETags for result caching

• ... much, much, much more

Page 75: REST API's: Easier Than You Imagined

Adding an API to an existing App

Page 76: REST API's: Easier Than You Imagined

Shared State

• Subfolder supported, not required

• Enable by using the same Application Name

• Shared variables*

*with great power comes great responsibility

Page 77: REST API's: Easier Than You Imagined

Best Practices

Page 78: REST API's: Easier Than You Imagined

Separate Collections &

Members

Page 79: REST API's: Easier Than You Imagined

Version yourAPI from day 1.

/api/v1/foo/bar

Page 80: REST API's: Easier Than You Imagined

Thoughtful URIs

Page 81: REST API's: Easier Than You Imagined

Human-Readable URIs

Page 82: REST API's: Easier Than You Imagined

Token vsQuery String

Page 83: REST API's: Easier Than You Imagined

PUT or POST?

Page 84: REST API's: Easier Than You Imagined

HATEOAS

Page 85: REST API's: Easier Than You Imagined

HTTP Status Codes are your friend

Page 86: REST API's: Easier Than You Imagined

Antipatterns

Page 87: REST API's: Easier Than You Imagined

I hate you.

If you code like this...

Page 88: REST API's: Easier Than You Imagined

GET request writes data

Page 89: REST API's: Easier Than You Imagined

2+ requests / task

Page 90: REST API's: Easier Than You Imagined

200 Error

Page 91: REST API's: Easier Than You Imagined

Using Cookies

Page 92: REST API's: Easier Than You Imagined

Getting SupportMailing List: bit.ly/taffy-users

IRC: #coldfusion on freenode and dalnetTweet me: @AdamTuttle

Page 93: REST API's: Easier Than You Imagined

Thank You

Page 94: REST API's: Easier Than You Imagined