# `Oaskit.Plugs.ValidateRequest`
[🔗](https://github.com/lud/oaskit/blob/v0.13.1/lib/oaskit/plugs/validate_request.ex#L1)

This plug will match incoming requests to operations defined with the
`Oaskit.Controller.operation/2` or
`Oaskit.Controller.use_operation/2` macros and retrieved from a
provided OpenAPI Specification module.

## Pluggin' in

To use this plug in a controller, the `Oaskit.Plugs.SpecProvider`
plug must be used in the router for the corresponding routes.

    defmodule MyAppWeb.Router do
      use Phoenix.Router

      pipeline :api do
        plug Oaskit.Plugs.SpecProvider, spec: MyAppWeb.OpenAPISpec
      end

      scope "/api" do
        pipe_through :api

        scope "/users", MyAppWeb do
          get "/", UserController, :list_users
        end
      end
    end

This plug must then be used in controllers. It is possible to call the plug in
every controller where you want validation, or to define it globally in your
`MyAppWeb` module.

While you can directly patch the `MyAppWeb.controller` function if all your
controllers belong to the HTTP API, we suggest to create a new
`api_controller` function in your `MyAppWeb` module.

Duplicate the `controller` function and add this plug and also `use
Oaskit.Controller`.

    defmodule MyAppWeb do
      def controller do
        # ...
      end

      def api_controller do
        quote do
          use Phoenix.Controller, formats: [:json], layouts: []

          # Use the controller helpers to define operations
          use Oaskit.Controller

          use Gettext, backend: MyAppWeb.Gettext
          import Plug.Conn

          # Use the plug here. This has to be after `use Phoenix.Controller`.
          plug Oaskit.Plugs.ValidateRequest

          unquote(verified_routes())
        end
      end
    end

Finally, request body validation will only work if the body is fetched from
the conn. This is generally done by the `Plug.Parsers` plug. It can also be
done by a custom plug if you are implementing an API that is working with
plaintext or custom formats.

## Request validation

Requests will be validated according to the request body schemas and parameter
schemas defined in operations. The data will also be cast to the expected
types:

* Parameters whose schemas define a `type` of `boolean` or `integer` will be
  cast to that type. Arrays of such types are supported as well.
* Parameters with type `string` and a `format` supported by `JSV` will be also
  cast according to that format. Output values for formats are described in
  the [JSV
  documentation](https://hexdocs.pm/jsv/validation-basics.html#formats). This
  includes, URI, Date, DateTime and Duration.
* Request bodies are cast to their given schema too. When using raw schemas
  defined as maps, the main changes to the data is the cast of formats, just
  as for parameters. When schemas are defined using module names, and when
  those modules' structs are created with `JSV.defschema/1`, the request
  bodies will be cast to those structs.

Request bodies will be validated according to the expected operation
content-types, and the actual content-type of the request.

## Options

* `:query_reader_opts` - If a Plug.Conn struct enters this plug without its
  query parameters being fetched, this plug will fetch them automatically
  using `Conn.fetch_query_params(conn, query_reader_opts)`. The default value
  is `[length: 1000000, validate_utf8: true]`.
* `:pretty_errors` - A boolean to control pretty printing of JSON errors
  payload in error handlers. Defaults to `true` when `Mix.env() != :prod`,
  defaults to `false` otherwise.
* `:html_errors` - A boolean to control whether the default error handler is
  allowed to return HTML errors when the request accepts HTML. This is useful
  to quickly read errors when opening an url directly from the browser.
  Defaults to `true`.
* `:security` - A plug module or `{module, options}`. This plug will be
  invoked when an operation declares the `:security` option, or when the
  OpenAPI specification declares security at the root level.
* `:error_handler` - A module or `{module, argument}` tuple. The error handler
  must implement the `Oaskit.ErrorHandler` behaviour. It will be
  called on validation errors. Defaults to `Oaskit.ErrorHandler.Default`.
* Other unknown options are preserved and passed to the error handler.

## Non-required bodies

A request body is considered empty if `""`, `nil` or an empty map (`%{}`). In
that case, if the operation defines the request body with `required: false`
(which is the default value!), the body validation will be skipped.

The empty map is a special case because `Plug.Parsers` implementations cannot
return anything else than a map. If a client sends an HTTP request with an
`"application/json"` content-type but no body, the JSON parser in the Plug
library will still return an empty map.

To avoid problems, always define request bodies as required if you can. This
is made automatically when using the "definition shortcuts" described in
`Oaskit.Controller.operation/2`.

## Security

To enable security validation, set the `:security` option on this plug:

    plug Oaskit.Plugs.ValidateRequest,
      security: MyApp.Plugs.ApiSecurity

    # Or with custom options. The argument MUST be a keyword list.
    plug Oaskit.Plugs.ValidateRequest,
      security: {MyApp.Plugs.ApiSecurity, log_level: :debug}

For details on implementing security plugs and handling authorization, see the [Security Guide](guides/security.md).

## Error handling

Validation can fail at various steps:

* Parameters validation
* Content-type matching
* Body validation

On failure, the validation stops immediately. If a parameter is invalid, the
body is not validated and the error handler is called with a single category
of errors. In the case of parameters, multiple errors can be passed to the
handler if multiple parameters are invalid or missing.

Custom error handlers must implement the `Oaskit.ErrorHandler` behaviour and
be ready to accept all error reasons that this plug can generate. Such reasons
are described in the `t:Oaskit.ErrorHandler.reason/0` type.

The 3rd argment passed to the `c:Oaskit.ErrorHandler.handle_error/3` depends
on the `:error_handler` function. When defined as a module, that argument
contains the options passed to the plug.

    plug Oaskit.Plugs.ValidateRequest,
      error_handler: MyErrorHandler,
      pretty_errors: true,
      custom_opt: "foo"

This will allow the handler to receive `:pretty_errors` and `:custom_opt`.

When passing a tuple, the second element will be passed as-is:

    plug Oaskit.Plugs.ValidateRequest,
      error_handler: {MyErrorHandler, "foo"}

In the example above, the error handler will only receive `"foo"` as the 3rd
argument of `c:Oaskit.ErrorHandler.handle_error/3`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
