Pro Yearly is on sale from $80 to $50! »

Building Resilient API Clients

Building Resilient API Clients

D200a17dd269fd4001bacb11662dab4b?s=128

Kyle Fuller

June 18, 2015
Tweet

Transcript

  1. Building!Resilient!API!Clients !KyleFuller

  2. None
  3. None
  4. None
  5. Building!Resilient!API!Clients

  6. None
  7. None
  8. None
  9. None
  10. None
  11. None
  12. How$does$it$work?

  13. GET /questions

  14. DELETE /questions/{id}

  15. GET /questions/{id}

  16. POST /questions/{id}/choices/{choice_id}

  17. POST /questions

  18. Applica'on*was*built*from*an*out3 of3band*specifica'on

  19. Tight&Coupling

  20. We#want#to#change#something.

  21. /v1

  22. /v2

  23. Move%Fast%and%Break&Things

  24. Move%Fast%and%Break%Things

  25. None
  26. None
  27. "Each&version&will&remain&for&at&least& 2&years&from&release."

  28. Eventually*have*to*switch

  29. API$Team$maintains$legacy$API

  30. Move%Fast%and%Break&Nothing

  31. REST

  32. What%is%REST?

  33. “An$cipa$ng*change*is*one*of*the* central*themes*of*REST”

  34. REST%is%not... • CRUD • Pre)y+URLs • JSON • HTTP+"Verbs" •

    Rou9ng
  35. It’s%not%about%exposing%your% database%via%an%API

  36. These%are%implementa)on%details

  37. Representa)onal,State,Transfer

  38. Transfer(State(from(Server(to(Client?

  39. Ques%on(Resource

  40. HATEOAS

  41. None
  42. Hypermedia*as*the*Engine*of* Applica6on*State

  43. Ques%ons • create • list

  44. Ques%on • delete • choices

  45. Choice • vote

  46. Teaching)the)client)the)seman.c) meaning)of)the)domain

  47. Without'knowledge'about'the' implementa3on'details

  48. Root questions

  49. Ques%on delete

  50. Choice vote

  51. Ques%on create • ques&on • choices

  52. Why$are$we$not$doing$this?

  53. Hyperdrive

  54. One$Does$Not$Simply$Use$JSON

  55. HAL$+$Siren

  56. HAL Hypertext(Applica.on(Language

  57. None
  58. HAL { "_links": { "self": { "self": "/questions/1" } }

    }
  59. HAL { "_embedded": { "choices": [ { "_links": { "self":

    { "self": "/questions/1/choices/1" } }, "choice": "Swift", "votes": 2048 } ] } }
  60. None
  61. Siren { "actions": [ { "name": "vote", "href": "/questions/1/choices/3", "method":

    "POST" } ] }
  62. Siren { "actions": [ { "name": "create", "fields": [ {

    "name": "question", "type": "text", "title": "Question" }, { "name": "choices", "type": "array[text]", "title": "Choices" } ], "method": "POST", "type": "application/json", "href": "/questions" } ] }
  63. API$Blueprint$+$Hyperdrive

  64. apiblueprint.org

  65. None
  66. None
  67. hyperdrive.enter("https://polls.apiblueprint.org/") { result }

  68. representor

  69. None
  70. representor • a#ributes • transi,ons

  71. representor • a#ributes • transi,ons • representors

  72. if let questions = representor.transitions["questions"] { }

  73. hyperdrive.request(questions) { result in }

  74. if let questions = representor.representors["questions"] { map(questions, viewQuestion) }

  75. } else { println("Looks like there are no questions yet.")

    }
  76. func viewQuestion(question:Representor<HTTPTransition>) { println(question.attributes["question"]) if let choices = question.representors["choices"] {

    map(choices, viewChoice) } else { println("-> This question does not have any choices.") } if let delete = question.transitions["delete"] { // User may delete this question } }
  77. func viewChoice(choice:Representor<HTTPTransition>) { let text = choice.attributes["choice"] let votes =

    choice.attributes["votes"] println('-> \(text) (\(votes))') if let vote = choice.transitions["vote"] { // User may vote on this choice } }
  78. hyperdrive.request(vote)

  79. if let create = questions.transitions["create"] { // We may create

    a new question for attribute in create.attributes { // Creation takes `attribute.name` } } else { // Gracefully handle the lack of being able to create a question }
  80. Why?

  81. Change'business'rules

  82. Remove&transi-ons

  83. Add#transi*ons

  84. Coupling

  85. TaaS Toaster(as(a(Service

  86. Toaster(Applica.on

  87. None
  88. None
  89. None
  90. Demo

  91. How$does$API$Blueprint$work?

  92. ## Questions Collection [/questions] ### List All Questions [GET] +

    Relation: questions + Response 200 (application/json) + Attributes (array[Question])
  93. ### Create a New Question [POST] + Relation: create +

    Request (application/json) + Attributes + question (string, required) - The question + choices (array[string]) - A collection of choices. + Response 201 (application/json) + Attributes (Question)
  94. ## Question [/questions/{question_id}] + Attributes + question: `Favourite programming language?`

    (string, required) + published_at: `2014-11-11T08:40:51.620Z` (string) - An ISO8601 date when the question was published + choices (array[Choice], required) - An array of Choice objects
  95. { "id": 1, "question": "Favourite programming language?", "choices": [ {

    "id": 1, "choice": "Swift", "votes": 128 }, { "id": 2, "choice": "Objective-C", "votes": 2 } ] }
  96. ### Delete a Question [DELETE] + Relation: delete + Response

    204
  97. ## Choice [/questions/{question_id}/choices/{choice_id}] + Attributes + choice: Swift (string, required)

    + votes: 0 (number, required)
  98. ### Vote on a Choice [POST] This action allows you

    to vote on a question's choice. + Relation: vote + Response 201
  99. Conclusion • Move&Faster • Write&Less&Code • Don't&Break&Things • Embrace&Change

  100. Move%Fast,%Break%Nothing

  101. the$hypermedia$project!/!Hyperdrive the$hypermedia$project!/!representor*swi- !apiaryio!/!polls'app apiaryio!/!polls'api

  102. Ques%ons?

  103. fuller.li/slides !KyleFuller