36
Crafting Evolvable API Responses

Crafting Evolvable Api Responses

Embed Size (px)

DESCRIPTION

Create evolvable responses to avoid versioning your Web API for as long as possible.

Citation preview

Page 1: Crafting Evolvable Api Responses

Crafting Evolvable API Responses

Page 2: Crafting Evolvable Api Responses

Who am I?

• Twitter: @darrel_miller• http://www.bizcoder.com/

Page 3: Crafting Evolvable Api Responses

Journey

• Versioning sucks, let’s just not do it• Why we think we need it?• How can we avoid it?• Example time

Page 4: Crafting Evolvable Api Responses

Objects over the wire

Page 5: Crafting Evolvable Api Responses

We have been here before

• CORBA, DCOM• SOAP, WSDL• DTOs• JSON

Page 6: Crafting Evolvable Api Responses

The ASP.NET Web API Project Template

public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1", "value2" };}

// GET api/values/5 public string Get(int id) { return "value"; }

// POST api/values public void Post([FromBody]string value) { }

// PUT api/values/5 public void Put(int id, [FromBody]string value) { }

// DELETE api/values/5 public void Delete(int id) { } }

Page 7: Crafting Evolvable Api Responses

The ASP.NET Web API Starter Tutorialpublic class ProductsController : ApiController { //…

public IEnumerable<Product> GetAllProducts() { return products; }

public IHttpActionResult GetProduct(int id) { var product = products.FirstOrDefault((p) => p.Id == id); if (product == null) { return NotFound(); } return Ok(product); } }

http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api

Page 8: Crafting Evolvable Api Responses

ServiceStack

public class ReqstarsService : Service { public List<Reqstar> Get(AllReqstars request) { return Db.Select<Reqstar>(); } }

Page 9: Crafting Evolvable Api Responses

NancyFX

public class SampleModule : Nancy.NancyModule{ public SampleModule() { Get["/"] = _ => "Hello World!"; }}

Page 10: Crafting Evolvable Api Responses

Python Flask

@app.route('/todo/api/v1.0/tasks', methods=['GET'])def get_tasks(): return jsonify({'tasks': tasks})

Page 11: Crafting Evolvable Api Responses

Rails

# Returns the resource from the created instance variable # @return [Object] def get_resource instance_variable_get("@#{resource_name}") end

Page 12: Crafting Evolvable Api Responses

But, what’s the problem?

Page 13: Crafting Evolvable Api Responses

Which objects to map?

• Domain objects • How do we hide content we don’t want to expose?• How do we create different views of data?• Changes to domain model cause changes to API

• DTOs• whole lot of busy work• Only indirect control over serialization process

Page 14: Crafting Evolvable Api Responses

Automatic Serialization

• All the properties• Non standard data types: datetime, timespan• Does null mean unspecified, or explicitly null?• Empty collection or no collection• Capitalization• Links• Loops• Changes to behavior in the frameworks

Page 15: Crafting Evolvable Api Responses

Take back control

Page 16: Crafting Evolvable Api Responses

Use a DOM to build your document

dynamic jspeaker = new JObject();jspeaker.name = speakerInfo.Name;jspeaker.bio = speakerInfo.Bio;

dynamic links = new JObject();

dynamic iconLink = new JObject();iconLink.href = speakerInfo.ImageUrl;links.icon = iconLink;

dynamic sessionsLink = new JObject();sessionsLink.href = SessionsLinkHelper.CreateLink(request, speakerInfo).Target;links[LinkHelper.GetLinkRelationTypeName<SessionsLink>()] = sessionsLink;

jspeaker["_links"] = links;return new DynamicHalContent(jspeaker);

Page 17: Crafting Evolvable Api Responses

What to do with your new found freedom?

Page 18: Crafting Evolvable Api Responses

Anatomy of an HTTP representation

• Status line• Headers• Body

Page 19: Crafting Evolvable Api Responses

Headers

• Performance• Timing • Naming• Content• Compression

Page 20: Crafting Evolvable Api Responses

Let’s build some payloads

Page 21: Crafting Evolvable Api Responses

{"description" :"There is a hole in my bucket"

}

The smallest thing that is actionable

Page 22: Crafting Evolvable Api Responses

{"issue" : {

"description" :"There is a hole in my bucket"}

}

Define a vocabulary for things of interest

application/json application/vnd.myapirespones+json application/vnd.issue+json

Page 23: Crafting Evolvable Api Responses

{"issues" : [

{"description" :"There is a hole in my bucket"

}]

}

Beware of structural changes

Page 24: Crafting Evolvable Api Responses

{"description" :"There is a hole in my bucket","stepsToReproduce" : "Pour water in bucket. Lift bucket off ground.

Look for water dripping", "dateReported": "2012-04-21T18:25:43-05:00"

}

Just enough data to solve the problem

Page 25: Crafting Evolvable Api Responses

{"description" :"The font is too big","applicationName" : "Wordament","applicationVersion" : "1.2.0.2392","environment_OSVersion" : "NT4.0","environment_MemoryFree" : "10MB","environment_DiskSpaceFree" : "100TB",

}

Why do they need that data?

Page 26: Crafting Evolvable Api Responses

{"description" :"The font is too big","applicationName" : "Wordament","applicationVersion" : "1.2.0.2392","environment" : { "osVersion" : "NT4.0",

"memoryFree" : "10MB","diskSpaceFree" : "100TB"

}}

Attribute Groups

Page 27: Crafting Evolvable Api Responses

{"description" :"The font is too big","history" : [

{"status" : "reported", "date" :"2014-02-01"},{"status" : "triaged", "date" :"2014-02-04"},{"status" : "assigned", "date" :"2014-02-12"},{"status" : "resolved", "date" :"2014-02-19"},

]}

Attribute Groups for multiple instances

Page 28: Crafting Evolvable Api Responses

{"description" :"The font is too big","reportedByUser" : { "name" : "Bob Bing",

"email" : "[email protected]", "twitter" : "@bobbing", "dateHired" : "2001-01-21"

}}

Attribute Groups for related data

Page 29: Crafting Evolvable Api Responses

{"description" :"The font is too big","reportedByUser_url" : "http://api.acme.com/users/75"

}

Linking related data

Page 30: Crafting Evolvable Api Responses

{"description" :"The font is too big","Links" : [

{ "href" :"http://api.acme.com/users/75", "rel": "reportedByUser" },{ "href" :"http://api.acme.com/users/24", "rel": "assignedToUser" }

] }

Multiple Links

Page 31: Crafting Evolvable Api Responses

Learn from others

application/hal+json

application/vnd.collection+json

application/vnd.siren+json

application/vnd.github.v3+json

application/vnd.heroku+json

application/json-ld

application/json-home

application/http-problem

application/activity+json

application/vnd.mason+json

Page 32: Crafting Evolvable Api Responses

{"description" :"The font is too big","_embedded" : {

"reportedByUser" : { "name" : "Bob Bing",

"email" : "[email protected]","_links" : { "self" : {"href" :"http://api.acme.com/users/75"}}

}

}

Meet application/hal+json

Page 33: Crafting Evolvable Api Responses

{ "collection": { "links": [], "items": [ { "data": [ { "name": "Title", "value": "\r\n\t\t\tLearning from Noda Time: a case study in API design and open source (good, bad and ugly)\r\n\t\t“ }, { "name": "Timeslot", "value": "04 December 2013 16:20 - 17:20“ }, { "name": "Speaker", "value": "Jon Skeet“ } ], "links": [ { "href": "http://conference.hypermediaapi.com/speaker/6", "rel": "http://tavis.net/rels/speaker" }, { "href": "http://conference.hypermediaapi.com/session/133/topics", "rel": "http://tavis.net/rels/topics" } ], "href": "http://conference.hypermediaapi.com/session/133" } ], "query": [], "template": { "data": [] }, "version": "1.0" }}

Meet application/vnd.collection+json

Page 34: Crafting Evolvable Api Responses

Wrap up

• Understand the limitations of “objects over the wire”• Consider taking back control of your representations• Think in terms of messages, instead of objects• Build software that is designed to survive change

Page 35: Crafting Evolvable Api Responses
Page 36: Crafting Evolvable Api Responses

Image Credits

• Package - https://flic.kr/p/3mrNyn• Freedom - https://flic.kr/p/4vwRDw• Treasure map - https://flic.kr/p/7jDJwi• Handshake - https://flic.kr/p/nbAu8Y• Telephone - https://flic.kr/p/7Q8bMd• Blindfolded Typing - https://flic.kr/p/53Q3JE• Magic Trick - https://flic.kr/p/7T8zk5• Donut machine - https://flic.kr/p/anncxf• GT-R Steering Wheel - https://flic.kr/p/fDUSDk• Anatomy - https://flic.kr/p/6bfUZn• Shapes - https://flic.kr/p/3aKUAq• Payloaders - https://flic.kr/p/dTU9sN• Birds on a Wire - https://flic.kr/p/4YdfK