Rolodex v0.4.0 Rolodex.Route

Collects metadata associated with an API route. new/2 takes in a Phoenix.Router.Route, finds the controller action function associated with the route, and collects metadata set in the @doc annotations for the function.

Route Annotations

Details about all the valid annotations that new/2 will look for. Each one has a default, so they each can be omitted if not needed for the current route.

desc

Default: ""

Set via an @doc comment

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

body

Default: %{}

Request body parameters. Valid inputs: Rolodex.Schema, a map, or a list.

@doc [
  # A request body defined via a reusable schema
  body: SomeSchema,

  # 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]
  ]
]

headers

Default: %{}

Request headers. Valid input is 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 Rolodex.Schema, 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 [
  # 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. Maybe some of the have nested attributes too
  headers: [
    "X-Request-ID": :uuid,
    "Custom-Data": [
      id: :uuid,
      checksum: :string
    ],
    "Header-Via-Schema": MyHeaderSchema
  ]
]

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 a Rolodex.Schema, an atom, a map, or a list.

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

@doc [
  # Simplest 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 a Rolodex.Schema, an atom, a map, or a list.

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

@doc [
  # Simplest 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
    ]
  ],

  # Multiple query values. Maybe some of the have nested attributes too
  query_params: [
    id: :uuid,
    some_object: [
      id: :uuid,
      checksum: :string
    ],
    via_schema: QueryParamSchema
  ]
]

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.Schema, an atom, a map, or a list.

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

    # 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 => [MyResponseSchema],

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

    # Response is one of multiple possible results
    200 => %{type: :one_of, of: [MyResponseSchema, OtherSchema]},
    200 => [type: :one_of, of: [MyResponseSchema, OtherSchema]],
  }
]

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}
}

Link to this section Summary

Functions

Checks to see if the given route matches any filter(s) stored in Rolodex.Config

Looks up a Phoenix.Router.Route controller action function, parses any doc annotations, and returns as a struct

Link to this section Types

Link to this type

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

Link to this section Functions

Link to this function

matches_filter?(route, config)
matches_filter?(t(), Rolodex.Config.t()) :: boolean()

Checks to see if the given route matches any filter(s) stored in Rolodex.Config.

Link to this function

new(phoenix_route, config)

Looks up a Phoenix.Router.Route controller action function, parses any doc annotations, and returns as a struct.