Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Procore's API: The Next Generation

Procore's API: The Next Generation

Talk given at RailsConf 2017

Derek Carter

April 27, 2017
Tweet

Other Decks in Programming

Transcript

  1. procore • 22 squads, ~120 engineers • > 10 year

    old app • > 40 distinct tools • > 500 controllers
  2. guild squad model squad product manager ux designer qa engineer

    engineer engineer squad product manager ux designer qa engineer engineer engineer squad product manager ux designer qa engineer engineer engineer tribe
  3. squad model squad product manager ux designer qa engineer engineer

    engineer squad product manager ux designer qa engineer engineer engineer squad product manager ux designer qa engineer engineer engineer tribe guide squad varies as needed
  4. items_index.json GET “lists/19/items” [ { "id": 23, "completed": false, "due_date":

    "2017-04-27", "list_id": 19, "text": "Bread", "visible": true }, { "id": 24, "completed": false, "due_date": "2017-04-27", "list_id": 19, "text": "Milk", "visible": true } ]
  5. class Api::V1::ItemsController < Api::V1::ApplicationController def index completed_filter = params.dig(:filters, :completed)

    if completed_filter completed_bool = (completed_filter == true || completed_filter =~ (/true|t|yes|y|1/) || false ) @items = Item. where(list_id: params[:list_id], completed: completed_bool) else @items = Item.where(list_id: params[:list_id]) end render json: @items end end
  6. class Api::V1::ItemsController < Api::V1::ApplicationController include Filterable filter_on :completed, type: :boolean

    def index @items = Item.where(list_id: params[:list_id]) render json: filtrate(@items) end end
  7. class Api::V1::ItemsController < Api::V1::ApplicationController include Filterable filter_on :completed, type: :boolean

    sort_on :due_date, type: :datetime def index @items = Item.where(list_id: params[:list_id]) render json: filtrate(@items) end end
  8. class Api::V1::ItemsController < Api::V1::ApplicationController include Filterable filter_on :completed, type: :boolean

    filter_on :query, type: :scope, internal_name: :search sort_on :due_date, type: :datetime def index @items = Item.where(list_id: params[:list_id]) render json: filtrate(@items) end end
  9. [ { "id": 1, "completed": false, "created_at": "2017-04-25T00:52:31.696Z", "due_date": "2017-04-27T00:00:00.000Z",

    "note": "Free range only", "text": "Eggs", "visible": true, "list": { "id": 1, "name": "Grocery", "description": "Weekly grocery list", "created_at": "2017-04-25T00:52:02.913Z", "updated_at": "2017-04-25T00:52:02.913Z" } } ]
  10. class Api::V1::ItemsController < Api::V1::ApplicationController include Filterable filter_on :completed, type: :boolean

    def index @items = Item.includes(:list).where(list_id: params[:list_id]) render json: filtrate(@items) end def show @item = Item.includes(:list).find(params[:id]) render json: @item end end
  11. class Api::V1::ItemsController < Api::V1::ApplicationController include Filterable filter_on :completed, type: :boolean

    def index @items = Item.includes(:list).where(list_id: params[:list_id]) render json: filtrate(@items), fields: [:id, :text], include: [] end def show @item = Item.includes(:list).find(params[:id]) render json: @item end end
  12. class ItemSerializer < ApplicationSerializer attributes :id, :completed, :text include_in [:normal,

    :extended] do attributes :completed, :created_at, :due_date, :note end include_in [:extended] do belongs_to :list end end
  13. class Api::V1::ItemsController < Api::V1::ApplicationController include Filterable filter_on :completed, type: :boolean

    def index @items = Item.includes(:list).where(list_id: params[:list_id]) render json: filtrate(@items) end def show @item = Item.includes(:list).find(params[:id]) render json: @item, serializer_view: :extended end end
  14. [ { "id": 1, "completed": false, "text": "Eggs" } ]

    { "id": 1, "completed": false, "text": "Eggs", "created_at": "2017-04-25T00:52:31.696Z", "due_date": "2017-04-27T00:00:00.000Z", "note": "Free range only", "list": { "id": 1, "name": "Grocery", "description": "Weekly grocery list", "created_at": "2017-04-25T00:52:02.913Z", "updated_at": "2017-04-25T00:52:02.913Z" } } #show #index
  15. { "swagger": "2.0", "info": { "version": "1.0.0", "title": "Swagger Petstore",

    "license": { "name": "MIT" } }, "host": "petstore.swagger.io", "basePath": "/v1", "schemes": [ "http" ], "consumes": [ "application/json" ], "produces": [ "application/json" ], "paths": { "/pets": { "get": { "summary": "List all pets", "operationId": "listPets", "tags": [ "pets" ], "parameters": [ { "name": "limit",
  16. • don’t make them think • build a style guide

    • disagree and commit • make contracts first • use resusable components • document your damn API