Absinthe Journey with Wolfiton or How to Bring the Absinthe Tutorial UP to Date- Part 4 The Door
Tags: beginners, elixir, graphql, absinthe
Published: 2020-02-28 14:41:02

Hi everyone,

**Series navigation**
[PART 1 Introduction](https://dev.to/wolfiton/absinthe-journey-with-wolfiton-or-how-to-bring-the-absinthe-tutorial-up-to-date-part-1-introduction-5fgg)
[PART 2 Foundation](https://dev.to/wolfiton/absinthe-journey-with-wolfiton-or-how-to-bring-the-absinthe-tutorial-up-to-date-part-2-foundation-3jnh)
[PART 3 The Walls](https://dev.to/wolfiton/absinthe-journey-with-wolfiton-or-how-to-bring-the-absinthe-tutorial-up-to-date-part-3-the-walls-n86/)
[PART 4 The Door](https://dev.to/wolfiton/absinthe-journey-with-wolfiton-or-how-to-bring-the-absinthe-tutorial-up-to-date-part-4-the-door-10m0)
[PART 5 Testing](https://dev.to/wolfiton/testing-1ohn)
[PART 6 Can you fly?](https://dev.to/wolfiton/absinthe-journey-with-wolfiton-or-how-to-bring-the-absinthe-tutorial-up-to-date-part-6-can-you-fly-3al5)
[PART 7 The User](https://dev.to/wolfiton/absinthe-journey-with-wolfiton-or-how-to-bring-the-absinthe-tutorial-up-to-date-part-7-the-user-58)


Welcome to part 4 of the series but before we jump in let's recap what we did in the third part:

- We configured our project

- Added git version control

- created our first migration, schema, and context

- updated our post-migration using `alter table`

We are ready to start working with `Graphql`

#Section 1

Schema


Let's create a new feature using `hub`:

- navigate to the project root in the terminal 

```shell
cd ~/Codes/wolf_blog
```

- create a new feature(functionality)

```shell
hub checkout -b 01-The_Door 
```

The output should look like this 

```shell
hub checkout -b 01-The_Door                                                                                                     1 ✘  at 07:11:00 
Switched to a new branch '01-The_Door'

```

The schema file will be placed in `/lib/wolf_blog_web`

Create a new file and call it `schema.ex` and type in

```elixir
defmodule WolfBlogWeb.Schema do
  
end

```

> We use modules in Elixir to keep functions in different namespaces, also there are not classes or inheritance, this is Functional Programming.

**Bringing Absinthe(graphql library)**

If you remember **Dear Reader** in part 3 of this series we installed some packages and one of them was Absinthe.

Now we can call it and put it to work in our `schema.ex` type:

```elixir
defmodule WolfBlogWeb.Schema do
  use Absinthe.Schema # add this to power up our schema
end

```

But wait! this gives us an error that says that we don't have a type, an object, and a query.

Let's fix that by creating `/lib/wolf_blog_web/types`

Now create a new file in the types folder, called `post_types.ex` and type in:

```elixir
defmodule WolfBlogWeb.Types.PostTypes do
  use Absinthe.Schema.Notation

  @desc "Post fields that can be interrogated(get)"
  object :post do
    @desc "The post id"
    field :id, :id
    @desc "The title of the post"
    field :title, :string
    @desc "The post body"
    field :body, :string
  end

end


```

> We use desc to describe and document what each field is and also here we describe what the post type is representing. The **@desc documentation is recommended** and it should be used for others to be able to understand your code easier.

Also, this should look familiar to you because they represent the migration and the schema we used last time.

Let's add this to the schema to shutdown one error regarding the types.

> If you don't see an error **Dear reader**, it is because you haven't installed the Elixir_lsp extension yet(recommended in part 3 of this series).

Back to the `schema.ex` we go, let's add the types:

```elixir
defmodule WolfBlogWeb.Schema do
  use Absinthe.Schema
  alias WolfBlogWeb.Resolvers.PostResolver

  import_types WolfBlogWeb.Types.PostTypes

  query  do
    @desc "list_all_posts"
    field :posts, list_of(:post) do
      resolve &PostResolver.list_all_posts/3
    end
  end

end

```



#Section 2

Resolvers

We made our error go away from our `schema.ex` file but we still got an undefined function list_all_post().

So to fix this, we need to create a folder resolver and a file that will connect our context with the Absinthe Schema. This is done using a resolver. 


Let's create `/lib/wolf_blog_web/resolvers` and inside the folder a file called `post_resolver.ex`

In `post_resolver.ex` type:

```shell
defmodule WolfBlogWeb.Resolvers.PostResolver do
  alias WolfBlog.Blog

  def list_all_posts(_, _, _) do
    {:ok, Blog.list_posts()} #here we use an ok tuple 
  end
end

```

> The tuple above expects to receive an output(a value) from Blog.list_posts(). if it doesn't receive one it will throw an error.


#Section 3

Routes


To be able to interact with our Graphql API, we need to define some routes.

Let's open up `/lib/wolf_blog_web/router.ex`

It should look like this:

```elixir
defmodule WolfBlogWeb.Router do
  use WolfBlogWeb, :router

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/api", WolfBlogWeb do
    pipe_through :api
  end
end

```
 
We are interested in this part:

```shell
scope "/api", WolfBlogWeb do
    pipe_through :api
end

```


> So `scope` is a block of code that can group many routes. You can think of scope like a box that can have many things from the same type(only router related). For example, it can have 3 balls.

So let's add our routes for the Graphql Schema:

```shell

defmodule WolfBlogWeb.Router do
  use WolfBlogWeb, :router

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/" do
    pipe_through :api

    forward "/graphql", Absinthe.Plug , schema:   WolfBlogWeb.Absinthe.Schema

    forward "/graphiql", Absinthe.Plug.GraphiQL, schema: WolfBlogWeb.Schema, interface: :playground
  end
end

```

> `forward` will send the request to a specific route and add different route options on that request. In our case, it will add the Absinthe Plug and our Absinthe Schema we defined earlier in `schema.ex`.

> Note: Absinthe Plug offers two Graphql interfaces the playground and a simple interface.

Now we can start our API using the following command:
```shell
mix phx.server

```
You should see **Dear reader**, the Graphql playground interface image

![Graphql playground interface](https://dev-to-uploads.s3.amazonaws.com/i/xpr46v3cqmynhkb0z3d6.png)

If you click on the schema in the right-hand corner like in the image below.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/boql65iafw218wsxv9kf.png)

Then the following menu should pop up with information regarding our schema and query. Now click the posts: [Post] option in this menu and the following should appear.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/64mcr43wjwtmkrt2xu6m.png)


> As we can see the `@desc` from our query is present and also all our @desc from our fields are present.

> Now you can see that documenting the code really helps and anyone else that will use our API will understand what everything is.

Now close the browser and also stop the `mix phx.server`, command using `Ctrl + c`.

To make our lives easier let's add some seeds.

Section 4 

Seed data for dev and test

To be able to seed data we will need to use structs.

So let's change our post schema first:

`cd ~/Codes/wolf_blog/lib/wolf_blog/blog/post.ex`

```elixir
defmodule WolfBlog.Blog.Post do
  use Ecto.Schema
  import Ecto.Changeset

  schema "posts" do
    field :body, :string
    field :title, :string

    timestamps()
  end

  @doc false
  def changeset(%Post{} = post, attrs) do
    post
    |> cast(attrs, [:title, :body])
    |> validate_required([:title, :body])
    |> unique_constraint(:title)
  end
end

```

You might get an error that looks like this now

```elixir
** (CompileError) lib/wolf_blog/blog/post.ex:13: 
Post.__struct__/0 is undefined, cannot expand struct Post
    lib/wolf_blog/blog/post.ex:13: (module)

```

> It says in plain English that it doesn't understand where the Post struct is and can't extend it.

Let's fix it

```elixir
defmodule WolfBlog.Blog.Post do
  use Ecto.Schema
  import Ecto.Changeset
  alias WolfBlog.Blog.Post # add this to tell the struct what post is

  schema "posts" do
    field :body, :string
    field :title, :string

    timestamps()
  end

  @doc false
  def changeset(%Post{} = post, attrs) do
    post
    |> cast(attrs, [:title, :body])
    |> validate_required([:title, :body])
    |> unique_constraint(:title)
  end
end

```

The error is now gone so let's write our Seeder:

`cd ~/Codes/wolf_blog/lib/wolf_blog/seeder.ex`



Type in



```elixir

defmodule WolfBlog.Seeder do
  def power_up() do

    alias WolfBlog.Blog.Post
    alias WolfBlog.Repo

    absinthe_title =  "Absinthe is great"

    absinthe_body =  "Absinthe can really make working with Phoenix and Graphql much easier.The big advantage is that you can also test the code."

    _article = %Post{title: absinthe_title , body: absinthe_body} |> Repo.insert() #Bring the values from title and body and create
                                                                  # an article that get's added to the DB

    :ok
  end
end

```

> Thanks @NobbZ and @cevado for helping me realize that I was using the struct when I needed a string.

**Optional, how I did it wrong**

> `absinthe_title = %Post{"Absinthe is great"}` #this is a struct but due to a lot of work lately, I got tired and couldn't see it.

So they send me in the right direction by showing me the error I made.


The seed is ready but in order to activate it, we need to tell the `seeds.ex` file in:

`cd ~/Codes/wolf_blog/lib/priv/repo/seeds.exs` 

```elixir

WolfBlog.Seeder.power_up() # add this line after all 
                           # the comments in the file

```

Let's run our seed, using this command:

```shell
mix run priv/repo/seeds.exs
```

Let's try our first query!

Type in the terminal 

```shell
mix phx.server

```

- Navigate to http://localhost:4000/graphiql

- We are in the playground again

Now type in our first query in the left-hand side like in the image below:

```js
{
  posts{
    id
    title
    body
  }
}
```


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/v2u65gu2ohxmeedmte04.png)

 
Now hit the play button and you should get the data, we seeded earlier.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jr94bqj2x6ce132xn4cr.png)

Good now let's add all to our feature using:


```shell
hub add .
hub commit -m "Add Schema resolver types for post and the route for graphql"

hub push --set-upstream origin 01-The_Door
```
I hope you enjoy this part of the series **Dear Reader** and if you also find it useful, share it on social.

Credits:

Thanks, @NobbZ, and @cevado for helping me realize that I was using the struct when I needed a string.