Skip to content

Commit

Permalink
remove redundant status code assertions in API tests #256
Browse files Browse the repository at this point in the history
  • Loading branch information
nelsonic committed Jan 15, 2023
1 parent 0d2d369 commit 819db65
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 32 deletions.
52 changes: 25 additions & 27 deletions api.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
<div align="center">

# `REST`ful API integration
# `REST`ful `API` Integration

</div>

This guide demonstrates
how to *extend* our MVP `Phoenix` application
so it also acts as an **API**
how to *extend* our MVP `Phoenix` App
so it also acts as an **`API`**
returning `JSON` data.

We want our users to securely query
and manipulate their data
and want to ensure all actions
that are performed in the Web API
can also be done through our `RESTful` API
`people` want to securely query
and update their data.
We want to ensure all actions
that are performed in the Web UI
can also be done through our `REST API`
*and* `WebSocket API`
(for all real-time updates).

Let's get cracking! 🎉

## 1. Add `/api` scope and pipeline

We want all our API requests
to be made under the `/api` route.
This is easier for us to manage changes to API
that don't create unnecessary regressions to our liveviews.
We want all `API` requests
to be made under the `/api` namespace.
This is easier for us to manage changes to `API`
that don't create unnecessary complexity in the `LiveView` code.

Let's start by opening `lib/router.ex`
and create a new `:api` pipeline
to be used under `scope "/api"`.
to be used under `scope "/api"`:

```elixir

Expand All @@ -50,12 +50,12 @@ to be used under `scope "/api"`.
```

We are creating an `:api` pipeline
that will only accepts and returns `json` objects.
that will only accept and return `json` objects.
`:fetch_session` is added as a plug
because `:authOptional` requires us to do so.

Every request that is routed to `/api`
will be piped through both `:api` and `:authOptional` pipelines.
will be piped through both the `:api` and `:authOptional` pipelines.

You might have noticed two new controllers:
`API.ItemController` and `API.TimerController`.
Expand All @@ -71,7 +71,7 @@ Before creating our controller, let's define our requirements. We want the API t
- edit an `item`

We want each endpoint to respond appropriately if any data is invalid,
the response body and status should inform the user what went wrong.
the response body and status should inform the `person` what went wrong.
We can leverage changesets to validate the `item` and `timer`
and check if it's correctly formatted.

Expand All @@ -86,13 +86,15 @@ Create two new files:
- `test/app_web/api/timer_controller_test.exs`

Before implementing,
we recommend giving a look at [`learn-api-design`](https://github.com/dwyl/learn-api-design),
we are going to be using some tips coming from there!
we recommend giving a look at
[`learn-api-design`](https://github.com/dwyl/learn-api-design),
we are going to be using some best practices described there!

We want the API requests to be handled gracefully
We want the `API` requests
to be handled gracefully
when an error occurs.
The person using the API
[**should be shown meaningful errors**](https://github.com/dwyl/learn-api-design/blob/revamp/README.md#show-meaningful-errors).
The `person` using the `API`
[**should be shown _meaningful_ errors**](https://github.com/dwyl/learn-api-design/blob/main/README.md#show-meaningful-errors).
Therefore, we need to test how our API behaves
when invalid attributes are requested
and/or an error occurs **and where**.
Expand All @@ -113,7 +115,6 @@ defmodule AppWeb.API.ItemControllerTest do
{:ok, %{model: item, version: _version}} = Item.create_item(@create_attrs)
conn = get(conn, Routes.item_path(conn, :show, item.id))

assert conn.status == 200
assert json_response(conn, 200)["id"] == item.id
assert json_response(conn, 200)["text"] == item.text
end
Expand All @@ -134,7 +135,6 @@ defmodule AppWeb.API.ItemControllerTest do
test "a valid item", %{conn: conn} do
conn = post(conn, Routes.item_path(conn, :create, @create_attrs))

assert conn.status == 200
assert json_response(conn, 200)["text"] == Map.get(@create_attrs, "text")

assert json_response(conn, 200)["status"] ==
Expand All @@ -147,7 +147,6 @@ defmodule AppWeb.API.ItemControllerTest do
test "an invalid item", %{conn: conn} do
conn = post(conn, Routes.item_path(conn, :create, @invalid_attrs))

assert conn.status == 400
assert length(json_response(conn, 400)["errors"]["text"]) > 0
end
end
Expand All @@ -157,22 +156,21 @@ defmodule AppWeb.API.ItemControllerTest do
{:ok, %{model: item, version: _version}} = Item.create_item(@create_attrs)
conn = put(conn, Routes.item_path(conn, :update, item.id, @update_attrs))

assert conn.status == 200
assert json_response(conn, 200)["text"] == Map.get(@update_attrs, :text)
end

test "item with invalid attributes", %{conn: conn} do
{:ok, %{model: item, version: _version}} = Item.create_item(@create_attrs)
conn = put(conn, Routes.item_path(conn, :update, item.id, @invalid_attrs))

assert conn.status == 400
assert length(json_response(conn, 400)["errors"]["text"]) > 0
end
end
end
```

In `/item`, users will be able to
In `/item`,
a `person` will be able to
**create**, **update** or **query a single item**.
In each test we are testing
successful scenarios (the [Happy Path](https://en.wikipedia.org/wiki/Happy_path)),
Expand Down
5 changes: 0 additions & 5 deletions test/app_web/controllers/api/item_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ defmodule AppWeb.API.ItemControllerTest do
{:ok, %{model: item, version: _version}} = Item.create_item(@create_attrs)
conn = get(conn, Routes.item_path(conn, :show, item.id))

assert conn.status == 200
assert json_response(conn, 200)["id"] == item.id
assert json_response(conn, 200)["text"] == item.text
end
Expand All @@ -32,7 +31,6 @@ defmodule AppWeb.API.ItemControllerTest do
test "a valid item", %{conn: conn} do
conn = post(conn, Routes.item_path(conn, :create, @create_attrs))

assert conn.status == 200
assert json_response(conn, 200)["text"] == Map.get(@create_attrs, "text")

assert json_response(conn, 200)["status"] ==
Expand All @@ -45,7 +43,6 @@ defmodule AppWeb.API.ItemControllerTest do
test "an invalid item", %{conn: conn} do
conn = post(conn, Routes.item_path(conn, :create, @invalid_attrs))

assert conn.status == 400
assert length(json_response(conn, 400)["errors"]["text"]) > 0
end
end
Expand All @@ -55,15 +52,13 @@ defmodule AppWeb.API.ItemControllerTest do
{:ok, %{model: item, version: _version}} = Item.create_item(@create_attrs)
conn = put(conn, Routes.item_path(conn, :update, item.id, @update_attrs))

assert conn.status == 200
assert json_response(conn, 200)["text"] == Map.get(@update_attrs, :text)
end

test "item with invalid attributes", %{conn: conn} do
{:ok, %{model: item, version: _version}} = Item.create_item(@create_attrs)
conn = put(conn, Routes.item_path(conn, :update, item.id, @invalid_attrs))

assert conn.status == 400
assert length(json_response(conn, 400)["errors"]["text"]) > 0
end
end
Expand Down

0 comments on commit 819db65

Please sign in to comment.