Building APIs on Rails 5 with AMS

Building APIs on Rails 5 with AMS

A lot of people have being using Rails to develop both their internal or external API, but building a high quality API can be hard, and performance is a key point to achieve it.
I'll share my stories with APIs, and tell you how Active Model Serializer, component of Rails-API, helped me. AMS have being used across thousands of applications bringing convention over configuration to JSON generation.
This talk will give you a sneak peek of a new version of AMS that we have being working on, it's new cache conventions, and how it's being considered to be shipped by default in new Rails 5.

98195776df79590269541395c699f816?s=128

João Moura

April 22, 2015
Tweet

Transcript

  1. 2.
  2. 3.

    API

  3. 5.
  4. 6.
  5. 7.
  6. 9.
  7. 11.
  8. 12.
  9. 13.
  10. 14.
  11. 15.
  12. 16.
  13. 17.
  14. 18.
  15. 22.
  16. 23.
  17. 24.
  18. 25.
  19. 26.
  20. 27.
  21. 29.
  22. 30.
  23. 39.
  24. 40.
  25. 44.
  26. 45.
  27. 48.

    An API should do one thing, and do it well.

    “ Joshua Blonch, Google tech talk, Jan 2007
  28. 49.
  29. 54.
  30. 62.
  31. 63.

    rails-api Subset of a normal Rails application, created for applications

    that don't require all functionality of a complete Rails application
  32. 64.
  33. 65.
  34. 66.
  35. 67.
  36. 68.
  37. 69.
  38. 70.
  39. 71.
  40. 74.

    AMS

  41. 76.
  42. 77.
  43. 82.
  44. 83.
  45. 84.
  46. 85.
  47. 86.
  48. 89.

    { "links": { "self": "http://example.com/posts", "next": "http://example.com/posts?page[offset]=2", "last": "http://example.com/posts?page[offset]=10" },

    "data": [{ "type": "posts", "id": "1", "title": "JSON API paints my bikeshed!", "links": { "self": "http://example.com/posts/1", "author": { "self": "http://example.com/posts/1/links/author", "related": "http://example.com/posts/1/author", "linkage": { "type": "people", "id": "9" } }, "comments": { "self": "http://example.com/posts/1/links/comments", "related": "http://example.com/posts/1/comments", "linkage": [ { "type": "comments", "id": "5" }, { "type": "comments", "id": "12" } ] } } }], "included": [{ "type": "people", "id": "9", "first-name": "Dan", "last-name": "Gebhardt", "twitter": "dgeb", "links": { "self": "http://example.com/people/9" } }, { "type": "comments", "id": "5", "body": "First!", "links": { "self": "http://example.com/comments/5" } }, { "type": "comments", "id": "12", "body": "I like XML better", "links": { "self": "http://example.com/comments/12" } }] }
  49. 90.

    2. JSONAPI { "links": { "self": "http://example.com/posts", "next": "http://example.com/posts?page[offset]=2", "last":

    "http://example.com/posts?page[offset]=10" }, "data": [{ "type": "posts", "id": "1", "title": "JSON API paints my bikeshed!", "links": { "self": "http://example.com/posts/1", "author": { "self": "http://example.com/posts/1/links/author", "related": "http://example.com/posts/1/author", "linkage": { "type": "people", "id": "9" } }, "comments": { "self": "http://example.com/posts/1/links/comments", "related": "http://example.com/posts/1/comments", "linkage": [ { "type": "comments", "id": "5" }, { "type": "comments", "id": "12" } ] } } }], "included": [{ "type": "people", "id": "9", "first-name": "Dan", "last-name": "Gebhardt", "twitter": "dgeb", "links": { "self": "http://example.com/people/9" } }, { "type": "comments", "id": "5", "body": "First!", "links": { "self": "http://example.com/comments/5" } }, { "type": "comments", "id": "12", "body": "I like XML better", "links": { "self": "http://example.com/comments/12" } }] }
  50. 91.

    2. JSONAPI A standard for building APIs in JSON. {

    "links": { "self": "http://example.com/posts", "next": "http://example.com/posts?page[offset]=2", "last": "http://example.com/posts?page[offset]=10" }, "data": [{ "type": "posts", "id": "1", "title": "JSON API paints my bikeshed!", "links": { "self": "http://example.com/posts/1", "author": { "self": "http://example.com/posts/1/links/author", "related": "http://example.com/posts/1/author", "linkage": { "type": "people", "id": "9" } }, "comments": { "self": "http://example.com/posts/1/links/comments", "related": "http://example.com/posts/1/comments", "linkage": [ { "type": "comments", "id": "5" }, { "type": "comments", "id": "12" } ] } } }], "included": [{ "type": "people", "id": "9", "first-name": "Dan", "last-name": "Gebhardt", "twitter": "dgeb", "links": { "self": "http://example.com/people/9" } }, { "type": "comments", "id": "5", "body": "First!", "links": { "self": "http://example.com/comments/5" } }, { "type": "comments", "id": "12", "body": "I like XML better", "links": { "self": "http://example.com/comments/12" } }] }
  51. 92.

    2. JSONAPI A standard for building APIs in JSON. {

    "links": { "self": "http://example.com/posts", "next": "http://example.com/posts?page[offset]=2", "last": "http://example.com/posts?page[offset]=10" }, "data": [{ "type": "posts", "id": "1", "title": "JSON API paints my bikeshed!", "links": { "self": "http://example.com/posts/1", "author": { "self": "http://example.com/posts/1/links/author", "related": "http://example.com/posts/1/author", "linkage": { "type": "people", "id": "9" } }, "comments": { "self": "http://example.com/posts/1/links/comments", "related": "http://example.com/posts/1/comments", "linkage": [ { "type": "comments", "id": "5" }, { "type": "comments", "id": "12" } ] } } }], "included": [{ "type": "people", "id": "9", "first-name": "Dan", "last-name": "Gebhardt", "twitter": "dgeb", "links": { "self": "http://example.com/people/9" } }, { "type": "comments", "id": "5", "body": "First!", "links": { "self": "http://example.com/comments/5" } }, { "type": "comments", "id": "12", "body": "I like XML better", "links": { "self": "http://example.com/comments/12" } }] }
  52. 94.

    +

  53. 96.
  54. 97.
  55. 105.

    class PostsController < ApplicationController def index @posts = Post.all render

    json: @posts end def show @post = Post.find(params[:id]) render json: @post end end
  56. 106.
  57. 109.

    class PostSerializer < ActiveModel::Serializer attributes :title, :body, :comments_count def title

    "Post - #{object.title}" end def comments_count object.comments.size end end
  58. 113.

    class PostSerializer < ActiveModel::Serializer attributes :title, :body, :comments_count def title

    "Post - #{object.title}" end def comments_count object.comments.size end end
  59. 114.

    class PostSerializer < ActiveModel::Serializer cache only: [:title] attributes :title, :body,

    :comments_count def title "Post - #{object.title}" end def comments_count object.comments.size end end
  60. 115.

    class PostSerializer < ActiveModel::Serializer cache except: [:comments_count] attributes :title, :body,

    :comments_count def title "Post - #{object.title}" end def comments_count object.comments.size end end
  61. 121.
  62. 123.
  63. 125.

    @post = Post.create(post_params) render json: @post, statue: :created end def

    post_params PostSerialization.deserialize(params) end
  64. 126.

    def create @post = Post.create(post_params) render json: @post, status: :created

    end def post_params PostSerialization.deserialize(params) end
  65. 127.
  66. 129.
  67. 131.
  68. 132.
  69. 133.
  70. 134.
  71. 135.
  72. 136.
  73. 137.
  74. 139.
  75. 140.
  76. 141.
  77. 142.
  78. 143.
  79. 145.
  80. 146.
  81. 148.
  82. 149.
  83. 150.
  84. 151.