Craft GraphQL APIs in Elixir with Absinthe (Pragprog)

Just picked this up - thanks for the forum discount! New to elixir, and in-between jobs right now so it really helps!

Take care, dave

2 Likes

Hey everyone! The book is officially out! https://pragprog.com/book/wwgraphql/craft-graphql-apis-in-elixir-with-absinthe

Many thanks to our reviewers, beta-readers, and Absinthe contributors!

17 Likes

Congrats!!!

5 Likes

Is there an updated version of the code which accompanies the book anywhere?

Running the initial mix ecto.setup results in a load of deprecation warnings but fails with this:

== Compilation error in file lib/plate_slate_web/schema.ex ==
** (Absinthe.Schema.Error) Invalid schema:
Elixir.PlateSlateWeb.Schema:0: The root query type must be implemented and be a of type Object

I’m guessing that having installed Phoenix 1.4 isn’t going to help much either however.

Would it be simpler for me to recreate the initial project from an empty one and add in up-to-date deps and bear that in mind as I work through the book?

What version of elixir are you on? Does your schema have a root query object? If so, upgrade Absinthe to the latest version.

Thanks Ben. I’m on Elixir 1.7.3.

I’m using the code from the PragProg site (in the 02-chp.schema/1-start folder).

I’ve just commented out the contents of the PlateSlateWeb.Schema module and then mix ecto.setup works and generates the database.

Simply uncommenting use Absinthe.Schema causes the error I mentioned earlier.

At the bottom of the error output is:

lib/absinthe/schema.ex:258: Absinthe.Schema.__after_compile__/2
(stdlib) lists.erl:1263: :lists.foldl/3
(stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
(elixir) lib/kernel/parallel_compiler.ex:206: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6

I will have more of a dig into it later but I’ve started a new project and am slowly building it up using a combination of the book, your blog post (https://www.howtographql.com/graphql-elixir/0-introduction/) and the Absinthe documentation.

As I say, I’m pretty sure it’s an Elixir or Phoenix update issue because I did work through the first chapters of the book a while ago without this problem.

I’ll let you know if I get to the bottom of it.

Yeah just upgrade Absinthe, Elixir 1.7 fixed a bug that Absinthe was apparently relying on during schema generation. We fixed it a while ago but the book code still ships with relatively older versions of Absinthe since, well, it’s hard to change print.

2 Likes

Thanks Ben, that did the trick (as long as I left everything else alone). There are still a lot of deprecation warnings but I completely understand about the book being published at a fixed point in time.

Fingers crossed that one day you and Bruce have the willpower to work on a revised edition. Now that I’ve started tinkering with it, GraphQL and Absinthe are fantastic. Thank you for all of your hard work, it’s very much appreciated, even by those of us who might not have time to contribute to the project (but maybe I will as I get more into using it).

1 Like

This book mentions that we should use the following versions of technologies used,
• Erlang (v20.0+)
• Elixir (v1.5.0+)
• PostgreSQL (v9.4+)

But when I peeked into the code it says,

def project do
    [
      ...
      elixir: "~> 1.4",
      ...
  end

which means that it’s using Elixir version 1.4 or above and 1.4 depends on Erlang v18/v19 (Erlang v20 from Elixir v1.4.5).

So what versions of Erlang and Elixir should I use?
A month or two months ago I tried to follow this book and failed because some versions issue, so this time I want to be sure that I’m using the correct versions.
@benwilson512

@pillaiindu Use the versions mentioned in the book. The code was first generated in Elixir 1.4 and we simply forgot to update that one spot.

Should I change that line from elixir: "~> 1.4", to elixir: "~> 1.5" after copying the code?

It won’t make any difference. That line is only used to validate that you’re running the project in at least Elixir 1.4, it doesn’t choose the elixir version.

Thank you for your time! :slight_smile:

1 Like

Thanks for using Absinthe!

1 Like

So what versions of Erlang and Elixir should I use?

I’ve reread the book recently and worked through the examples with elixir 1.8.1 and latest absinthe, dataloader, phoenix, ecto, etc. Don’t remember encountering any major problems, so I’d say the latest versions of everything should work.

2 Likes

This is also correct. The main thing that has tripped people up in the past is that they have tried to use the latest Elixir / Erlang without upgrading Absinthe. This leads to compilation errors. If however you upgrade Absinthe and other dependencies, it should all be smooth sailing.

5 Likes

I just got the P2 version.

Thanks for updating :slight_smile:

1 Like

I’m excited to read P2 before the start of my next large project!

1 Like

Has anyone found a nice way of doing the challenge at the end of chapter 7 (Resolution Middleware)?

I’ve been trying to do it today and I’m getting nowhere. I think I don’t understand where the time taken is meant to be stored? Should it be on the response?

JFYI the challenge is to ā€œBuild some middleware that can be used to measure how long it takes to resolve a fieldā€.

I know I’m showing lack of effort here but I can only do Elixir in my spare time (Python/JS dev by day) so any guidance or hints would be greatly appreciated.

To answer my own question, today I started chapter 9 and it does exactly this thing with a ā€œbookendedā€ middleware using :start and :finish calls. So anyone else doing this, keep reading and all will become clear.

To elaborate, I just expanded the Debug middleware from chapter 9 like this:

defmodule PlateSlateWeb.Schema.Middleware.Debug do
  @behaviour Absinthe.Middleware

  def call(resolution, :start) do
    path = resolution |> Absinthe.Resolution.path |> Enum.join(".")
    time1 = :erlang.timestamp
    IO.puts """
    ========START==========
    started: #{path}
    with source: #{inspect resolution.source}
    """
    %{resolution | middleware: resolution.middleware ++ [{__MODULE__, {:finish, path, time1}}]}
  end

  def call(resolution, {:finish, path, time1}) do
    time2 = :erlang.timestamp
    time_taken = :timer.now_diff(time2, time1)
    IO.puts """
    completed: #{path}
    time taken: #{time_taken} microseconds (#{:erlang.float_to_binary(time_taken * 1.0e-6, [{:decimals, 6}])} seconds )
    value: #{inspect resolution.value}
    ========END==========\
    """
    resolution
  end
end

It’s probably not the best solution but it works for me!

1 Like