.. _library_rest:

``rest``
========

The ``rest`` library provides a small REST authoring layer on top of the
existing ``http_router`` library. It is implemented as a category so
that REST application objects can continue to implement the
``http_handler_protocol`` protocol directly while reusing the existing
router dispatch, request annotation, middleware, and OpenAPI derivation
logic.

This library reuses the ``http_core`` and ``http_router``. It derives
router hooks from higher-level endpoint descriptors, provides small
request and response helpers, and normalizes simple action result terms
into HTTP responses.

Layering
--------

``rest`` is the highest-level authoring layer in the current HTTP stack:

- Start with ``http_core`` library for normalized HTTP messages and with
  the ``http_router`` library for declarative routing.
- Use the ``rest`` library when you want to describe endpoints with
  ``endpoint/5``, keep the inherited ``handle/2`` entry point, and
  return small result terms instead of building every response manually.
- Stay with the ``http_router`` library when you need direct control
  over ``route/4``, custom handler predicates, or router hooks without
  the higher-level endpoint layer.
- Pair REST applications with the ``open_api`` library when you want
  derived OpenAPI documents or opt-in request and response contract
  validation.

API documentation
-----------------

Open the
`../../apis/library_index.html#rest <../../apis/library_index.html#rest>`__
link in a web browser.

Loading
-------

To load the library, load the ``loader.lgt`` file:

::

   | ?- logtalk_load(rest(loader)).

Testing
-------

To test this library, load the ``tester.lgt`` file:

::

   | ?- logtalk_load(rest(tester)).

Current scope
-------------

The current version provides one imported routing predicate through the
category inheritance from ``http_router`` plus request and response
helper predicates:

- ``handle/2``
- ``path_parameter/3``
- ``query_parameter/3``
- ``request_header/3``
- ``request_body/2``
- ``json_body/2``
- ``json_object_body/2``
- ``json_array_body/2``
- ``form_body/2``
- ``text_body/2``
- ``binary_body/2``
- ``json_response/4-5``
- ``created_response/4``
- ``no_content_response/2``
- ``problem_response/6``

The category also exposes optional OpenAPI contract validation hooks:

- ``open_api_validate_request/1``
- ``open_api_request_validation_error_response/4``
- ``open_api_validate_response/1``
- ``open_api_response_validation_error_response/5``

The category also exposes optional action failure and error
normalization hooks:

- ``rest_action_failure_response/3``
- ``rest_action_error_response/4``

Importing REST application objects are expected to define endpoint
descriptors using:

- ``endpoint(Id, Method, Path, Action, Options)``

Endpoint identifiers must be unique within the importing object. When
the object also exposes OpenAPI operations through ``http_router``,
those same identifiers are reused as operation identifiers.

The ``Action`` argument is the name of a declared local predicate with
arity 2, typically a protected predicate. The action predicate receives
the annotated request and returns or throws one of the currently
supported result terms:

- ``ok(JSON)``
- ``created(Location, JSON)``
- ``no_content``
- ``json(Status, JSON)``
- ``json(Status, Headers, JSON)``
- ``problem(Status, Type, Title, Detail)``
- ``response(Response)`` or a normalized ``response/5`` term directly

The category derives the ``http_router`` hooks from those endpoint
descriptors:

- ``route/4``
- ``route_metadata/2``
- ``route_produces/2``

All matched routes dispatch through a single internal action runner that
calls the endpoint action and normalizes its returned or thrown result.

Endpoint options are passed through as route metadata except for the
special ``produces(MediaTypes)`` option, which is translated into
``route_produces/2``. This keeps endpoint metadata available to action
predicates and response middleware and also allows router-level OpenAPI
derivation to keep working.

That same metadata pass-through also allows REST applications to reuse
router companion categories. For example, an object can import
``http_router_digest_auth(_, _, _)``, declare ``digest_auth(Options)``
in endpoint options, delegate ``authorize_routed_request/2`` to
``authorize_digest_auth_request/2``, and register
``add_digest_authentication_info/3`` as response middleware.

The current helper predicates read the normalized HTTP request terms
provided by ``http_core``:

::

   request(Method, Target, Version, Headers, Body, Properties)

They rely on router annotations such as ``route/1`` and
``path_params/1`` plus the normalized derived properties produced by the
``http_core`` library such as ``query_pairs/1``. The
``path_parameter/3`` and ``query_parameter/3`` helpers are deterministic
lookups. The decoded body helpers return ``400 Bad Request`` problem
responses when the current action expects a JSON, form, text, or binary
body and the normalized request body is missing or has a different
decoded shape. The ``json_object_body/2`` and ``json_array_body/2``
helpers build on ``json_body/2`` and additionally require the decoded
JSON payload to be an object or array term respectively.

Action result normalization currently builds normalized HTTP response
terms from returned or thrown supported result terms using these rules:

- successful JSON responses use the negotiated router media type when
  the request carries a JSON-compatible ``response_media_type/1``
  annotation and otherwise fall back to ``application/json``
- problem responses always use ``application/problem+json``

Plain action failure and unsupported exceptions still default to generic
``500 Internal Server Error`` problem responses, but importing objects
can override those defaults using ``rest_action_failure_response/3`` and
``rest_action_error_response/4``.

When ``open_api_validate_request/1`` succeeds for a matched endpoint,
the category validates the normalized request against the derived
OpenAPI operation descriptor before calling the endpoint action. When
``open_api_validate_response/1`` succeeds for a matched endpoint, the
category validates the normalized response after action result
normalization.

By default, request validation failures preserve three classes of client
error: unsupported request media types return
``415 Unsupported Media Type``, schema-invalid request bodies return
``422 Unprocessable Content``, and other request validation failures
return ``400 Bad Request``. Response validation failures still return a
``500 Internal Server Error`` ``application/problem+json`` response.
Importing objects can override those defaults using the corresponding
validation error response hooks. Validation is skipped for the synthetic
router requests used internally for OpenAPI request and response
inference.

OpenAPI integration
-------------------

When an importing object also implements the
``open_api_provider_protocol`` protocol, the inherited ``http_router``
OpenAPI derivation continues to work. Endpoint options such as
``summary/1``, ``description/1``, ``tags/1``, ``deprecated/1``,
``security/1``, ``parameters/1``, ``request_body/1``, and
``responses/1`` are exposed through ``route_metadata/2``, while
``produces(MediaTypes)`` drives ``route_produces/2`` and therefore
response media type inference.

Current limitations
-------------------

- Request and response OpenAPI contract validation is opt-in per
  endpoint using the validation hooks
- The library does not include dedicated pagination, filtering, or
  rate-limiting helpers of its own
- Result normalization focuses on JSON and problem responses; it does
  not provide specialized helpers for redirects, streaming, or multipart
  payloads
