Introducing Radex

Radex is a new hex package that lets you document Phoenix APIs similar to rspec_api_documentation. By generating your API documentation to your tests, you can be sure that your documentation remains up-to-date as your API changes or evolves. It is like DocTests but at the endpoint of your Phoenix API.

We like this new approach because it generates the same output as rspec_api_documentation json does, while the existing approach generates markdown and swagger/slate.

Radex uses a simple declarative approach to define the resources in your REST API. Then passing your Plug.Conn into Radex's record function tells Radex to build a JSON file with the information about the request. You can then continue to test your response as you normally would in any other ConnCase test.

Getting Started

As expected, start by adding Radex to your mix.exs file:

defp deps do
  [
    {:radex, "~> 0.1.0"},
  ]
end

Then within a controller test for your API controllers, using your application's <Name>Web.ConnCase, describe an endpoint and use Radex.Endpoint

defmodule MyAPIWeb.MyControllerTest do
  use MyAPIWeb.ConnCase
  describe "index" do
    use Radex.Endpoint

Then you can define some metadata about the request...

    # inside the `describe`
    use Radex.Endpoint
    @resource "Items"
    @route {"GET", "/items"}

...and define your test, passing a Plug.Conn through your controller and into Radex's record

    # inside the `describe`
    test "Viewing Items", %{conn: conn} do
      conn =
        conn
        |> get(items_path(conn, :index))
        |> record()

Finally, you can ensure the response is correct, testing your API and ensuring that the recorded interaction is correct.

      # Inside the `test`
      assert json_response(conn, 200)["data"] == []
    end
  end
end

To generate documentation simply run the tests with a special formatter...

mix test --formatter Radex.Formatter

...or integrate it into your Mix file...

defp aliases do
  [
    "radex.test": ["test --formatter Radex.Formatter"],
  ]
end

...and then run:

MIX_ENV=test mix radex.test

A Full Example

defmodule StorefrontWeb.OrderControllerTest do
  use StorefrontWeb.ConnCase

  alias Storefront.Orders
  alias Storefront.Orders.Order

  # ...

  describe "index" do
    use Radex.Endpoint

    @resource "Orders"
    @route {"GET", "/orders"}

    test "Viewing orders", %{conn: conn} do
      conn =
        conn
        |> get(order_path(conn, :index))
        |> record()

      assert json_response(conn, 200)["data"] == []
    end
  end

  describe "create order" do
    use Radex.Endpoint

    @resource "Orders"
    @route {"POST", "/orders"}

    # Define parameters to show in the documentation
    @parameter {"order[email]", "Email address for the Order"}
    @parameter {"order[paid]", "Status of the order", type: :boolean}

    test "renders order when data is valid", %{conn: conn} do
      # Override the default description to let your test
      # title to be more descriptive
      radex_metadata(description: "Creating an order")

      conn =
        conn
        |> post(order_path(conn, :create), order: @create_attrs)
        |> record()

      assert %{"id" => id} = json_response(conn, 201)["data"]

      conn =
        conn
        |> get(order_path(conn, :show, id))
        |> record()

      assert json_response(conn, 200)["data"] == %{
        "id" => id,
        "email" => "some email",
        "paid" => true}
    end

    # This will not be documented as nothing is recorded
    test "renders errors when data is invalid", %{conn: conn} do
      conn =
        conn
        |> post(order_path(conn, :create), order: @invalid_attrs)

      assert json_response(conn, 422)["errors"] != %{}
    end
  end
end

Learning More and Helping Out

Here are all the Radex links:

We are open to suggestions and pull requests, and we will continue to evolve the library as we integrate it into new and existing projects.