No REST for the Wicked

E5b31154e4e71265a60728fef2bacbde?s=47 Ben Wilson
September 01, 2016

No REST for the Wicked

Build a GraphQL API with http://absinthe-graphql.org/

E5b31154e4e71265a60728fef2bacbde?s=128

Ben Wilson

September 01, 2016
Tweet

Transcript

  1. the Wicked for No REST http://absinthe-graphql.org Ben Wilson @benwilson512

  2. CARGOSENSE

  3. The BEAM http://absinthe-graphql.org Ben Wilson @benwilson512 some reasons to like

  4. REST GET /users/1 { name: "Joe Bob" email: "joe.bob@foo.com" friends:

    [ "/users/5", "/users/7", "/users/9", ], organization_id: 1 } http://absinthe-graphql.org Ben Wilson @benwilson512
  5. None
  6. REST, Camp 2 GET /users/1 { name: "Joe Bob”, organization_id:

    1, friends: [ { name: "Fred Jones", organization: { name: "Cool Folks LLC", payment_plan_id: 5 } }, … } http://absinthe-graphql.org Ben Wilson @benwilson512
  7. None
  8. { name: "Joe Bob” organization_id: 1, friends: [ { name:

    "Fred Jones", organization: { name: "Cool Folks LLC", payment_plan_id: 5 } }, … ] } GET /users/1 REST, Camp 2 http://absinthe-graphql.org Ben Wilson @benwilson512
  9. GraphQL Declarative & Hierarchical Strongly Typed Concurrent Application-Focused http://absinthe-graphql.org Ben

    Wilson @benwilson512 some reasons to like
  10. Declarative & Hierarchical http://absinthe-graphql.org Ben Wilson @benwilson512 it’s

  11. GraphQL http://absinthe-graphql.org Ben Wilson @benwilson512 { user: { name: "Joe

    Bob", email: "joe.bob@foo.com", friends: [ {name: "Fred Jones"}, {name: "Jane Smith"}, {name: "Rebecca Jones"}, ... ] } } { user(id: 1) { name email friends { name } } }
  12. http://absinthe-graphql.org Ben Wilson @benwilson512 Strongly Typed it’s

  13. Directive http://absinthe-graphql.org Ben Wilson @benwilson512 List Interface Enum Union Scalar

    Object NonNull
  14. GET /events?date=2016-08-30&location_id=4 http://absinthe-graphql.org Ben Wilson @benwilson512 @valid_filters ~w(date location_id name)a

    def index(conn, params) do filters = @valid_filters |> Enum.reduce(%{}, fn key, filters -> case Map.fetch(params, Atom.to_string(key)) do {:ok, value} -> add_filter(key, value, filters) _ -> query end end) render("index.json", events: Event.list(filters)) end
  15. But wait! there’s more… def add_filter(:date, date, filters) do case

    Calendar.parse(date) do {:ok, date} -> Map.put(filters, :date, date) _ -> filters end end def add_filter(key, value, filters) do Map.put(filters, key, value) end
  16. GET /events?date=2016-08-30&location_id=4 http://absinthe-graphql.org Ben Wilson @benwilson512 @valid_filters ~w(date location_id name)a

    def index(conn, params) do filters = @valid_filters |> Enum.reduce(%{}, fn key, filters -> case Map.fetch(params, Atom.to_string(key)) do {:ok, value} -> add_filter(key, value, filters) _ -> query end end) render("index.json", events: Event.list(filters)) end
  17. { events(location_id: 4, date: "2016-08-30") { name } } http://absinthe-graphql.org

    Ben Wilson @benwilson512 Using: def events(filters, _) do {:ok, Event.list(filters)} end
  18. { events(location_id: 4, date: "2016-08-30") { name } } http://absinthe-graphql.org

    Ben Wilson @benwilson512 def events(filters, _) do ... end field :events, list_of(:event) do arg :date, :date arg :location_id, :id arg :name, :string resolve &events/2 end
  19. http://absinthe-graphql.org Ben Wilson @benwilson512 Custom Scalar @desc """ ISO Date

    2015-11-21 2015-01-02 """ scalar :date do parse &Calendar.Date.Parse.iso8601/1 serialize &Calendar.Date.Format.iso8601/1 end
  20. http://absinthe-graphql.org Ben Wilson @benwilson512 Built-in Scalar @desc """ The `String`

    scalar type represents textual data, represented as UTF-8 character sequences. ... """ scalar :string do serialize &to_string/1 parse &parse_string/1 end
  21. http://absinthe-graphql.org Ben Wilson @benwilson512 @desc """ A planned occasion, like

    a meeting or conference """ object :event do @desc "The date on which the event occurs" field :date, non_null(:date) @desc "The location at which the event happens" field :location, non_null(:location) @desc "The name of the event" field :name, non_null(:string) field :attendees, list_of(:person) end
  22. Introspection http://absinthe-graphql.org Ben Wilson @benwilson512 { __schema { types {

    name description } } } { __schema: { types: [ { name: "Event", description: "A planned …" }, { name: "Person", description: "Someone …" }, ... ] } }
  23. GraphiQL http://absinthe-graphql.org Ben Wilson @benwilson512 https://github.com/graphql/graphiql

  24. { user: { name: "Bob", primaryOrganization: { id: 7, name:

    "Elixir Co INC" } }, location: { name: "Headquarters", organization: { id: 7, name: "Elixir Co INC" } } } http://absinthe-graphql.org Ben Wilson @benwilson512
  25. Directives http://absinthe-graphql.org Ben Wilson @benwilson512 { feed: { stories: [

    { author: { name: "Ben Wilson" }, message: "Elixir Rocks!" }, { author: { name: "Bruce Williams" }, message: "GraphQL is the bomb!" }, ... ] } } { feed { stories { author { name } comments @defer { author { name } } message } } }
  26. Deferred Content http://absinthe-graphql.org Ben Wilson @benwilson512 { path: ["feed", "stories",

    0, "comments"], data: [ { author: { name: "Joe Bob", message: "Commenting is fun" } }, ... ] }
  27. Directives http://absinthe-graphql.org Ben Wilson @benwilson512 { feed { stories @stream

    { author { name } comments @defer { author { name } } message } } } { feed { stories @live { author { name } comments @defer { author { name } } message } } } { feed { stories { author { name } comments @defer { author { name } } message } } }
  28. Absinthe Goals Correct Easy to Use Idiomatic Performant Community Oriented

    http://absinthe-graphql.org Ben Wilson @benwilson512
  29. Schema Errors web/schema.ex:12: Users :usre is not defined in your

    schema. Types must exist if referenced. object :organization do field :name, :string field :users, list_of(:usre) end http://absinthe-graphql.org Ben Wilson @benwilson512
  30. Schema Compilation http://absinthe-graphql.org Ben Wilson @benwilson512 @desc "A faction in

    the Star Wars saga" node object :faction do @desc "The name of the faction" field :name, :string @desc "The ships used by the faction." connection field :ships, node_type: :ship do resolve &Ship.list/2 end end
  31. Absinthe v1.2

  32. ? http://absinthe-graphql.org Ben Wilson @benwilson512 { user: { name: "Joe

    Bob", email: "joe.bob@foo.com", friends: [ {name: "Fred Jones"}, {name: "Jane Smith"}, {name: "Rebecca Jones"}, ... ] } } { user(id: 1) { name email friends { name } } }
  33. Absinthe vNext http://absinthe-graphql.org Ben Wilson @benwilson512

  34. Query Compilation ~A"""
 query Fast($id: ID){ performanceCritical(id: $id) { stuff

    things { name } } } """ http://absinthe-graphql.org Ben Wilson @benwilson512
  35. Projection http://absinthe-graphql.org Ben Wilson @benwilson512 def events(filters, _) do {:ok

    Event.list(filters)} end def list(filters) do Event |> where(^filters) |> Repo.all end
  36. Projection http://absinthe-graphql.org Ben Wilson @benwilson512 def events(filters, graphql_info) do preloads

    = Absinthe.Ecto.preloads(graphql_info) selections = Absinthe.Ecto.preloads(graphql_info) {:ok Event.list(filters, preloads, selections)} end def list(filters, preloads, selections) do Event |> where(^filters) |> select(^selections) |> preload(^preloads) |> Repo.all end
  37. Real Time Data http://absinthe-graphql.org Ben Wilson @benwilson512 { feed {

    stories @live { author { name } comments @defer { author { name } } message } } } subscription { stories(author_id: 1) { message author { name } } }
  38. Questions? http://absinthe-graphql.org Ben Wilson @benwilson512 Background image green by Ana

    C., license available here.