api management with taffy and api blueprint
TRANSCRIPT
![Page 1: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/1.jpg)
API MANAGEMENT WITH TAFFY AND API BLUEPRINT
KAI KOENIG (@AGENTK)
![Page 2: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/2.jpg)
AGENDA
▸ What is Taffy?
▸ REST in a nutshell
▸ But is it “RESTful ENOUGH”?
▸ Taffy setup and basic flow
▸ Advanced configuration
▸ API Blueprint and other tools
![Page 3: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/3.jpg)
WHAT IS TAFFY?
![Page 4: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/4.jpg)
WHAT IS TAFFY?
TAFFY
▸ TLDR version: Taffy is a framework to build REST-based APIs in CFML
▸ Developed by Adam Tuttle
▸ Currently in version 3.1, incepted around 2011 (MIT license)
▸ Very stable, very powerful
▸ Allows the creation of REST-based APIs in CFML independent of any vendor implementation - works with Lucee and ACF
▸ Can be integrated with other frameworks
![Page 5: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/5.jpg)
WHAT IS TAFFY?
WHY TAFFY?
“But hey, both Lucee and Adobe CF have their own implementation of REST-API handling and it’s SO EASY to use and it has SELF-DOCUMENTATION! That’s great, ey?”
▸ At first glance it might seem like a great idea for getting started. But:
▸ Various issues (created URL structures, JSON handling, clunky syntax)
▸ Significantly lock-in to a vendor’s implementation
▸ Overall developer-unfriendly approaches
![Page 6: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/6.jpg)
WHAT IS TAFFY?
BENEFITS OF TAFFY
▸ This is not a talk about the deficiencies of REST in ACF or Lucee
▸ This is why Taffy is great:
▸ Developer-friendly and easy to get started with
▸ Backwards-compatible to ACF 8
▸ Convention over configuration
▸ Hardly any boilerplate code
![Page 7: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/7.jpg)
REST IN A NUTSHELL
https://www.flickr.com/photos/kikasz/2891113802/
![Page 8: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/8.jpg)
REST IN A NUTSHELL
WHAT IS REST?
▸ REpresentational State Transfer - a method to communicate over a network
▸ Mostly used over HTTP, technically protocol-independent
▸ 2 phases:
▸ Request - noun, verb, MIME type, headers, data
▸ Response - status code, status text, headers, data
![Page 9: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/9.jpg)
REST IN A NUTSHELL
THE REQUEST (I)
▸ Nouns - identifier of the data we want to work with, e.g. /users or /users/232
▸ Main verbs:
▸ POST: creating a new record (unsafe)
▸ PUT: updating existing record (idempotent)
▸ GET: retrieving existing record (safe)
▸ DELETE: deleting record (idempotent)
![Page 10: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/10.jpg)
REST IN A NUTSHELL
THE REQUEST (II)
▸ Less commonly used verbs:
▸ HEAD: similar to GET, but only returns headers (safe)
▸ OPTIONS: used to check which verbs are available (safe)
▸ PATCH: similar to PUT, updating individual properties (idempotent)
▸ MIME type:
▸ Client and API server agree on the data types for exchange, e.g. text/html, application/xml etc
![Page 11: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/11.jpg)
REST IN A NUTSHELL
THE REQUEST (III)
▸ Headers - supply metadata with the request (Accept, Content-Type)
▸ Data - the data sent from the client to the server
▸ Can conceptually be of any format
▸ Most common: JSON
![Page 12: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/12.jpg)
REST IN A NUTSHELL
THE RESPONSE
▸ Status code & Status text:
▸ “200 OK”
▸ “404 Not Found”
▸ “500 Server Error” …
▸ There are a lot more specific status codes, such as 201, 301, 302, 400, 401 etc.
▸ Headers and Data
![Page 13: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/13.jpg)
REST IN A NUTSHELL
WHY DO PEOPLE LIKE AND USE REST?
▸ Works naturally with the HTTP protocol
▸ Other alternatives:
▸ SOAP-XML: very enterprise-y, bloated and complex
▸ XML-RPC: similar to REST, but ignores the power of the verb
![Page 14: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/14.jpg)
RESTFUL ENOUGH?
https://www.flickr.com/photos/kikasz/2891113802/https://xkcd.com/386/
![Page 15: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/15.jpg)
BUT IS IT RESTFUL ENOUGH?
THE REALITY IS MORE COMPLEX
▸ Roy Fielding’s 2000 dissertation about what we today know as REST
▸ Followed up by a series of blog posts from ~2008 about HATEOAS (Hypermedia As The Engine Of Application State)
▸ prescribing additional requirements and behaviours
▸ often considered as ideal, but impractical in a lot of ways
▸ Leads to a lot of discussion what REST is and how one has to use it
![Page 16: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/16.jpg)
BUT IS IT RESTFUL ENOUGH?
MORE MATURE?
▸ Plain JSON
▸ HATEOAS
{ "name" : “iPhone 7" }
{ "name": “iPhone 7", "links": [ { "rel": "self", "href": "http://localhost:8080/product/1" } ] }
![Page 17: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/17.jpg)
BUT IS IT RESTFUL ENOUGH?
HATEOAS{ "content": [ { "price": 499.00, "name": "iPad", "links": [ { "rel": "self", "href": "http://localhost:8080/product/1" } ], "attributes": { "connector": "socket" } }, { "price": 49.00, "name": "Dock", "links": [ { "rel": "self", "href": "http://localhost:8080/product/3" } ], "attributes": { "connector": "plug" } } ], "links": [ { "rel": "product.search", "href": "http://localhost:8080/product/search" } ] }
![Page 18: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/18.jpg)
BUT IS IT RESTFUL ENOUGH?
RICHARDSON MATURITY LEVEL
http://martinfowler.com/articles/richardsonMaturityModel.html
![Page 19: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/19.jpg)
TAFFY SETUP AND BASIC FLOW
https://www.flickr.com/photos/joanna_young/4515399787/
![Page 20: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/20.jpg)
TAFFY SETUP AND BASIC FLOW
INSTALLATION
▸ Download .zip-file from Github or taffy.io
▸ Installation options:
▸ Global mapping /taffy
▸ /taffy physically in webroot
▸ Installation in sub-directory of site (needs application-specific mappings)
![Page 21: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/21.jpg)
TAFFY SETUP AND BASIC FLOW
DRIVEN BY APPLICATION.CFC
▸ Extends taffy.core.api
▸ Needs to call onApplicationStart() and onRequestStart() on the parent CFC
▸ Earlier versions of Taffy had their own Application.cfc events - it was recommended to actually not implement onApplicationStart() etc
▸ That’s gone since Taffy 2.0
component extends="taffy.core.api" { this.name = "TaffyDemo";
function onApplicationStart() { application.productList = [ { "id":1, "name":"iPhone 7" }, { "id":2, "name":"iPhone 7+" }, { "id":3, "name":"iPad Pro 9.7inch" } ];
return super.onApplicationStart();
}
function onRequestStart() { return super.onRequestStart(); }
}
![Page 22: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/22.jpg)
TAFFY SETUP AND BASIC FLOW
CONVENTION OVER CONFIGURATION
▸ Taffy tries to NOT be in your way
▸ Examples:
▸ Default function names for resources are get(), post(), put(), delete()
▸ Looks for resources in a /resources directory
▸ Lots of things are just fine and work out of the box naturally because of sensible conventions
![Page 23: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/23.jpg)
TAFFY SETUP AND BASIC FLOW
MINIMAL LAYOUT
![Page 24: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/24.jpg)
TAFFY SETUP AND BASIC FLOW
RESOURCES (I)
▸ Extend taffy.core.resource
▸ Live in the /resources directory or a /resources mapping
▸ Can be changed - requires dropping the default bean factory
▸ Good practice:
▸ Have a CFC for a “thing” and for a “collection of things” each
▸ My convention: “SomeThing” and “SomeThingCollection”
▸ A resource should at least implement one verb function
![Page 25: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/25.jpg)
TAFFY SETUP AND BASIC FLOW
RESOURCES (II)
▸ taffy_uri defines the public URL of your resource
▸ representationOf() triggers the default serialiser
▸ withStatus() sets the HTTP status of the response (defaults to “200 OK”)
component extends="taffy.core.resource" taffy_uri="/product" { public function get(){
return representationOf(application.productList).withStatus(200); } }
![Page 26: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/26.jpg)
TAFFY SETUP AND BASIC FLOW
RESOURCES (III)
▸ Passing {productId} token into the resource’s URL
▸ Returning 404 if there’s no record found
component extends="taffy.core.resource" taffy_uri="/product/{productId}" { public function get(numeric productId){
for (var product in application.productList) { if (product["id"] == arguments.productId) { return representationOf(product).withStatus(200, "OK"); } }
return noData().withStatus(404, "Not Found"); } }
![Page 27: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/27.jpg)
TAFFY SETUP AND BASIC FLOW
RESOURCES (IV)
▸ If a verb is not implemented in a resource, Taffy will return “405 Not Allowed”
▸ Tokens will automatically become part of the arguments scope
▸ Tokens support regular expressions: /product/{pId:\d{4}} - /product/{pId:[A-Za-z]+}
▸ Query string parameters will ALSO automatically become part of the arguments scope
▸ Use .noData() if the intention is to not return data
▸ Similar to .withStatus(…), it’s possible to chain .withHeaders(…) to the return statement
![Page 28: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/28.jpg)
TAFFY SETUP AND BASIC FLOW
TAFFY DASHBOARD
![Page 29: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/29.jpg)
TAFFY SETUP AND BASIC FLOW
TAFFY DASHBOARD
▸ Dashboard allows to:
▸ execute requests (incl. Query Params, Headers and Basic Auth)
▸ inspect the response
▸ see a limited amount of documentation
▸ Should (usually) be switched off in production
▸ Default: caches API, needs explicit reloads
![Page 30: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/30.jpg)
TAFFY SETUP AND BASIC FLOW
CHANGING DATA - WHERE TO PUT POST?
▸ If the POST method was in Product.cfc - we’d have an issue.
▸ The URL route requires us to use /product/{productId}
▸ POST therefore has to life in ProductCollection.cfc
▸ PUT however (updating existing data) can happily go into Product.cfc
▸ URL matching: /product/search will match before /product/{productId}
![Page 31: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/31.jpg)
TAFFY SETUP AND BASIC FLOW
GOOD PRACTICES FOR PUT AND POST
▸ If you created a record with POST:
▸ return “201 Created” with the created data
▸ potentially return x-inserted-id in the header
▸ If you updated a record with PUT:
▸ return “200 OK” with the updated data
▸ if the record to be updated didn’t exist, create it (see above)
![Page 32: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/32.jpg)
ADVANCED TASKS AND CONFIG
![Page 33: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/33.jpg)
ADVANCED TASKS AND CONFIG
BREAKING AWAY FROM THE CONVENTIONS
▸ Metadata:
▸ Annotate functions to be triggered by a specific verb: taffy_verb=“<VERB>”
▸ Necessary for extended verbs like OPTIONS, HEAD, PATCH. Optional for standard verbs.
▸ There’s more metadata in serialisers (later)
![Page 34: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/34.jpg)
ADVANCED TASKS AND CONFIG
BREAKING AWAY FROM THE CONVENTIONS
▸ Configuration: variables.framework struct in Taffy’s Application.cfc
▸ reloadKey/reloadPassword vs. reloadOnEveryRequest
▸ serializer/deserializer (later)
▸ disableDashboard
▸ jsonp/allowCrossDomain
▸ beanFactory - allows hooking into Coldspring, DI/1 etc…
![Page 35: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/35.jpg)
ADVANCED TASKS AND CONFIG
AUTHENTICATION AND SECURITY
▸ Firstly - what do you want to achieve?
▸ Requiring an API Token?
▸ Fine-grain security?
▸ oAuth
▸ HTTP Basic Auth
▸ SSL
![Page 36: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/36.jpg)
ADVANCED TASKS AND CONFIG
API TOKEN (I)
▸ Best place to start is onTaffyRequest(…)
▸ Return true to continue processing the request
▸ Return a representation object to abort the request
▸ Two common options for passing token:
▸ URI parameters and/or as part of the data
▸ In the header
![Page 37: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/37.jpg)
ADVANCED TASKS AND CONFIG
API TOKEN (II)
function onTaffyRequest(verb, cfc, requestArguments, mimeExt, headers, methodMetadata, matchedURI) {
if (not structKeyExists(arguments.requestArguments, "apiKey") || !Len(arguments.requestArguments["apiKey"])) { return noData().withStatus(401, "Unauthorized"); }
if (!arrayFind(application.validAPIKeys, arguments.requestArguments["apiKey"])) { return noData().withStatus(403, "Forbidden"); }
return true; }
![Page 38: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/38.jpg)
ADVANCED TASKS AND CONFIG
CUSTOM SERIALISERS (I)
▸ Default serialiser is JSON (CFML-server built-in)
▸ Extend from taffy.core.baseRepresentation
▸ Implement getAsX functions
▸ getAsXML, getAsJSON, getAsYML etc
![Page 39: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/39.jpg)
ADVANCED TASKS AND CONFIG
CUSTOM SERIALISERS (II)
component extends="taffy.core.baseSerializer" { variables.anythingToXML = application.anythingToXML; variables.jsonUtil = application.jsonUtil;
function getAsXML() output="false" taffy_mime="application/xml" taffy_default="false" { return variables.anythingToXML.toXml(variables.data); }
function getAsJSON() output="false" taffy_mime="application/json" taffy_default="true" { return variables.jsonUtil.serialize(variables.data); } }
![Page 40: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/40.jpg)
ADVANCED TASKS AND CONFIG
RATE LIMITS
▸ In a nutshell:
▸ manage access log (api key & time) in DB or key/value storage
▸ onTaffyRequest logs requests and check if limits are exceeded
▸ if not exceeded, process incoming request
▸ if exceeded, return status code “429 Too Many Requests”
![Page 41: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/41.jpg)
ADVANCED TASKS AND CONFIG
API VERSIONING
▸ Multiple schools of thought:
▸ URI vs header
▸ Make sure you version from day 0!
▸ I tend to use /v1/product, /v2/product etc.
▸ Maps nicely on directory structures in /resources
▸ Update version when breaking compatibility
▸ Consider SemVer (Semantic Versioning) if your API is changing a lot
![Page 42: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/42.jpg)
API BLUEPRINT AND OTHER TOOLS
https://www.flickr.com/photos/cardoso/2196726835/
![Page 43: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/43.jpg)
API BLUEPRINT
WHAT IS IT?
▸ Description and specification language for web APIs (http://apiblueprint.org)
▸ From Apiary.io - but can be used independently from that
▸ Language spec: https://github.com/apiaryio/api-blueprint
▸ Offers platform-neutral documentation and additional tooling
▸ Aglio
▸ API-Mock
![Page 44: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/44.jpg)
API BLUEPRINT
DOCUMENTATION WITH AGLIO
▸ Very simple markup language
▸ npm install -g aglio (https://www.npmjs.com/package/aglio)
▸ aglio -i documentation.md -o documentation.html
▸ MD structure:
▸ # Group
▸ ## Resource
▸ ### Action
![Page 45: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/45.jpg)
API BLUEPRINT
MOCK SERVER WITH API-MOCK
▸ Creates a mock server for your API (https://github.com/localmed/api-mock)
▸ npm install -g api-mock
▸ api-mock ./documentation.md
▸ Defaults to port 3000
![Page 46: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/46.jpg)
API BLUEPRINT
PAW
▸ REST API test and management tool on OS X
▸ Recording/Playback/Testing etc
▸ Has API Blueprint support through extensions
![Page 47: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/47.jpg)
FINAL THOUGHTS
https://www.flickr.com/photos/brickset/16099265973/
![Page 48: API management with Taffy and API Blueprint](https://reader033.vdocument.in/reader033/viewer/2022042517/58a3461f1a28ab62248b5963/html5/thumbnails/48.jpg)
FINAL THOUGHTS
WHAT DID WE COVER?
▸ Taffy - what is it?
▸ How to setup and the foundations
▸ Discussed some advanced topics in more detail
▸ High-level overview of API Blueprint