Rolodex v0.10.1 Rolodex.Route

Parses and collects documentation metadata for a single Phoenix API route.

new/2 generates a Rolodex.Route.t(), a struct of route metdata passed into a Rolodex.Processor for serialization. This module also contains information on how to structure @doc annotations for your controller action functions.

Fields

  • desc (Default: "")

Set via an @doc comment

@doc [
  # Other annotations here
]
@doc "My route description"
def route(_, _), do: nil
  • id (Default: "")

Route identifier. Used as an optional unique identifier for the route.

@doc [
  id: "foobar"
]
  • body *(Default: %{})

Request body parameters. Valid inputs: Rolodex.RequestBody, or a map or keyword list describing a parameter schema. When providing a plain map or keyword list, the request body schema will be set under the default content type value set in Rolodex.Config.

@doc [
  # A shared request body defined via [`Rolodex.RequestBody`](Rolodex.RequestBody.html)
  body: SomeRequestBody,

  # Request body is a JSON object with two parameters: `id` and `name`
  body: %{id: :uuid, name: :string},
  body: [id: :uuid, name: :string],

  # Same as above, but here the top-level data structure `type` is specified
  # so that we can add `desc` metadata to it
  body: %{
    type: :object,
    desc: "The request body",
    properties: %{id: :uuid}
  },
  body: [
    type: :object,
    desc: "The request body",
    properties: [id: :uuid]
  ],

  # Request body is a JSON array of strings
  body: [:string],

  # Same as above, but here the top-level data structure `type` is specified
  body: %{type: :list, of: [:string]},
  body: [type: :list, of: [:string]],

  # All together
  body: [
    id: :uuid,
    name: [type: :string, desc: "The name"],
    ages: [:number]
  ]
]
  • auth (Default: %{})

Define auth requirements for the route. Valid input is a single atom or a list of auth patterns. We only support logical OR auth definitions: if you provide a list of auth patterns, Rolodex will serialize this as any one of those auth patterns is required.

@doc [
  # Simplest: auth pattern with no scope patterns
  auth: :MySimpleAuth,

  # One auth pattern with some scopes
  auth: [OAuth: ["user.read"]],

  # Multiple auth patterns
  auth: [
    :MySimpleAuth,
    OAuth: ["user.read"]
  ]
]
  • headers (Default: %{})

Request headers. Valid inputs: a module that has defined shared heads via Rolodex.Headers, or a map or keyword list, where each key is a header name and each value is a description of the value in the form of a an atom, a map, or a list.

Each header value can also specify the following: minimum (default: nil), maximum (default: nil), default (default: nil), and required (default: required).

@doc [
  # Shared headers
  headers: MySharedRequestHeaders

  # Simplest header description: a name with a concrete type
  headers: %{"X-Request-ID" => :uuid},
  headers: ["X-Request-ID": :uuid],

  # Specifying metadata for the header value
  headers: %{
    "X-Request-ID" => %{
      type: :integer,
      required: true,
      minimum: 0,
      maximum: 10,
      default: 0
    }
  },
  headers: [
    "X-Request-ID": [
      type: :integer,
      required: true,
      minimum: 0,
      maximum: 10,
      default: 0
    ]
  ],

  # Multiple header values
  headers: [
    "X-Request-ID": :uuid,
    "Custom-Data": [
      id: :uuid,
      checksum: :string
    ]
  ]
]
  • path_params (Default: %{})

Parameters in the route path. Valid input is a map or keyword list, where each key is a path parameter name and each value is a description of the value in the form of an atom, a map, or a list. Another valid input is a Rolodex.Schema module. The attributes at the top-level of the schema will be serialized as the path parameters.

Each parameter value can also specify the following: minimum (default: nil), maximum (default: nil), default (default: nil), and required (default: required).

@doc [
  # Reference to a schema module
  path_params: PathParamsSchema,

  # Simple inline path parameter description: a name with a concrete type
  path_params: %{id: :uuid},
  path_params: [id: :uuid],

  # Specifying metadata for the path value
  path_params: %{
    id: %{
      type: :integer,
      required: true,
      minimum: 0,
      maximum: 10,
      default: 0
    }
  },
  path_params: [
    id: [
      type: :integer,
      required: true,
      minimum: 0,
      maximum: 10,
      default: 0
    ]
  ]
]
  • query_params (Default: %{})

Query parameters. Valid input is a map or keyword list, where each key is a query parameter name and each value is a description of the value in the form of an atom, a map, or a list. Another valid input is a Rolodex.Schema module. The attributes at the top-level of the schema will be serialized as the query parameters.

Each query value can also specify the following: minimum (default: nil), maximum (default: nil), default (default: nil), and required (default: required).

@doc [
  # Reference to a schema module
  path_params: QueryParamsSchema,

  # Simple inline query parameter description: a name with a concrete type
  query_params: %{id: :uuid},
  query_params: [id: :uuid],

  # Specifying metadata for the parameter value
  query_params: %{
    id: %{
      type: :integer,
      required: true,
      minimum: 0,
      maximum: 10,
      default: 0
    }
  },
  query_params: [
    id: [
      type: :integer,
      required: true,
      minimum: 0,
      maximum: 10,
      default: 0
    ]
  ]
]
  • responses (Default: %{})

Response(s) for the route action. Valid input is a map or keyword list, where each key is a response code and each value is a description of the response in the form of a Rolodex.Response, an atom, a map, or a list.

@doc [
  responses: %{
    # A response defined via a reusable schema
    200 => MyResponse,

    # Use `:ok` for simple success responses
    200 => :ok,

    # Response is a JSON object with two parameters: `id` and `name`
    200 => %{id: :uuid, name: :string},
    200 => [id: :uuid, name: :string],

    # Same as above, but here the top-level data structure `type` is specified
    # so that we can add `desc` metadata to it
    200 => %{
      type: :object,
      desc: "The response body",
      properties: %{id: :uuid}
    },
    200 => [
      type: :object,
      desc: "The response body",
      properties: [id: :uuid]
    ],

    # Response is a JSON array of a schema
    200 => [MyResponse],

    # Same as above, but here the top-level data structure `type` is specified
    200 => %{type: :list, of: [MyResponse]},
    200 => [type: :list, of: [MyResponse]],

    # Response is one of multiple possible results
    200 => %{type: :one_of, of: [MyResponse, OtherResponse]},
    200 => [type: :one_of, of: [MyResponse, OtherResponse]],
  }
]
  • metadata (Default: %{})

Any metadata for the route. Valid input is a map or keyword list.

  • tags (Default: [])

Route tags. Valid input is a list of strings.

Handling Route Pipelines

In your Rolodex.Config, you can specify shared route parameters for your Phoenix pipelines. For each route, if it is part of a pipeline, new/2 will merge in shared pipeline config data into the route metadata

# Your Phoenix router
defmodule MyRouter do
  pipeline :api do
    plug MyPlug
  end

  scope "/api" do
    pipe_through [:api]

    get "/test", MyController, :index
  end
end

# Your controller
defmodule MyController do
  @doc [
    headers: ["X-Request-ID": uuid],
    responses: %{200 => :ok}
  ]
  @doc "My index action"
  def index(conn, _), do: conn
end

# Your config
config = %Rolodex.Config{
  pipelines: %{
    api: %{
      headers: %{"Shared-Header" => :string}
    }
  }
}

# Parsed route
%Rolodex.Route{
  headers: %{
    "X-Request-ID" => %{type: :uuid},
    "Shared-Header" => %{type: :string}
  },
  responses: %{200 => :ok}
}

Handling Multi-Path Actions

Sometimes, a Phoenix controller action function will be used for multiple API paths. In these cases, you can document the same controller action multiple times, split across either router path or HTTP method.

Sometimes, the documentation for each path will differ significantly. If you would like for each router path to pair with its own docs, you can use the multi flag.

# Your router
defmodule MyRouter do
  scope "/api" do
    # Same action used across multiple paths
    get "/first", MyController, :index
    get "/:id/second", MyController, :index

    # Same action used across multiple HTTP methods
    get "/search", MyController, :search
    post "/search", MyController :search
  end
end

# Your controller
defmodule MyController do
  @doc [
    # Flagged as an action with multiple docs
    multi: true,

    # All remaining top-level keys should be router paths
    "/api/first": [
      responses: %{200 => MyResponse}
    ],
    "/api/:id/second": [
      path_params: [
        id: [type: :integer, required: true]
      ],
      responses: ${200 => MyResponse}
    ]
  ]
  def index(conn, _), do: conn

  @doc [
    multi: true,
    get: [
      query_params: SearchQuery
      responses: %{200 => MyResponse}
    ],
    post: [
      body: SearchBody,
      responses: %{200 => MyResponse}
    ]
  ]
  def search(conn, _), do: conn
end

Link to this section Summary

Functions

Takes a Rolodex.Router.RouteInfo.t() and parses the doc annotation metadata into a structured form a Rolodex.Processor can serialize into a docs output

Link to this section Types

Link to this type

t()
t() :: %Rolodex.Route{
  auth: map(),
  body: map(),
  desc: binary(),
  headers: %{},
  id: binary(),
  metadata: %{},
  path: binary(),
  path_params: %{},
  pipe_through: [atom()],
  query_params: %{},
  responses: %{},
  tags: [binary()],
  verb: atom()
}

Link to this section Functions

Link to this function

new(route_info, config)
new(Rolodex.Router.RouteInfo.t() | nil, Rolodex.Config.t()) :: t() | nil

Takes a Rolodex.Router.RouteInfo.t() and parses the doc annotation metadata into a structured form a Rolodex.Processor can serialize into a docs output.