.. index:: single: http_router
.. _http_router/0:

.. rst-class:: right

**category**

``http_router``
===============

Declarative HTTP router category for objects implementing the http_handler_protocol protocol.

| **Availability:** 
|    ``logtalk_load(http_router(loader))``

| **Author:** Paulo Moura
| **Version:** 1:0:0
| **Date:** 2026-07-17

| **Compilation flags:**
|    ``static``


| **Extends:**
|    ``public`` :ref:`http_json_term_helpers <http_json_term_helpers/0>`
|    ``public`` :ref:`http_text_helpers <http_text_helpers/0>`
| **Uses:**
|    :ref:`http_core <http_core/0>`
|    :ref:`list <list/0>`

| **Remarks:**
|    (none)

| **Inherited public predicates:**
|    (none)

.. contents::
   :local:
   :backlinks: top

Public predicates
-----------------

.. index:: handle/2
.. _http_router/0::handle/2:

``handle/2``
^^^^^^^^^^^^

Routes a normalized HTTP request using the importing object ``route/4`` clauses.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``handle(Request,Response)``
| **Mode and number of proofs:**
|    ``handle(+compound,-compound)`` - ``one_or_error``

| **Exceptions:**
|    A middleware handler is not valid:
|        ``domain_error(http_router_middleware,Handler)``
|    A middleware action is not valid:
|        ``domain_error(http_router_middleware_action,Action)``
|    A response middleware handler is not valid:
|        ``domain_error(http_router_response_middleware,Handler)``
|    A response middleware result is not a valid normalized HTTP response term:
|        ``domain_error(http_router_response_middleware_response,Response)``
|    A route authorization action is not valid:
|        ``domain_error(http_router_route_authorization_action,Action)``
|    A route ``produces`` declaration is not a non-empty list of media types:
|        ``domain_error(http_router_route_produces,ProducedMediaTypes)``
|    A route ``produces`` media type is invalid:
|        ``domain_error(http_router_route_media_type,ProducedMediaType)``
|    Route metadata is not a proper list:
|        ``domain_error(http_router_route_metadata,Metadata)``
|    A route metadata property is invalid:
|        ``domain_error(http_router_route_metadata_property,MetadataProperty)``
|    A route handler is not valid:
|        ``domain_error(http_router_handler,Handler)``
|    A route path template is invalid:
|        ``domain_error(http_router_path_template,Template)``
|    A route path template segment is invalid:
|        ``domain_error(http_router_path_template_segment,Segment)``
|    A request path is invalid:
|        ``domain_error(http_router_path,Path)``
|    The route handler reports parameter validation errors:
|        ``error(http_parameter_validation(Errors),Context)``


------------

.. index:: api_info/1
.. _http_router/0::api_info/1:

``api_info/1``
^^^^^^^^^^^^^^

Returns the top-level OpenAPI info descriptor used when a router object also implements the ``open_api_provider_protocol`` protocol. Importing objects can override the default descriptor by defining ``open_api_info/1``.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``api_info(Info)``
| **Mode and number of proofs:**
|    ``api_info(-compound)`` - ``one``


------------

.. index:: servers/1
.. _http_router/0::servers/1:

``servers/1``
^^^^^^^^^^^^^

Returns the OpenAPI server descriptors used when a router object also implements the ``open_api_provider_protocol`` protocol. Importing objects can override the default empty list by defining ``open_api_servers/1``.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``servers(Servers)``
| **Mode and number of proofs:**
|    ``servers(-list(compound))`` - ``one``


------------

.. index:: security/1
.. _http_router/0::security/1:

``security/1``
^^^^^^^^^^^^^^

Optional OpenAPI top-level security hook passthrough used when a router object also implements the ``open_api_provider_protocol`` protocol. Importing objects can define ``open_api_security/1`` to expose top-level security requirements.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``security(Security)``
| **Mode and number of proofs:**
|    ``security(-list(compound))`` - ``zero_or_one``


------------

.. index:: operations/1
.. _http_router/0::operations/1:

``operations/1``
^^^^^^^^^^^^^^^^

Derives OpenAPI operation descriptors from ``route/4``, ``route_metadata/2``, and ``route_produces/2`` when a router object also implements the ``open_api_provider_protocol`` protocol. Recognized route metadata terms are ``summary/1``, ``description/1``, ``tags/1``, ``deprecated/1``, ``security/1``, ``parameters/1``, ``request_body/1``, and ``responses/1``. When ``request_body/1`` or ``responses/1`` metadata is absent, the router first checks optional ``route_open_api_request_body_example/2`` and ``route_open_api_response_example/2`` hooks and then attempts to infer inline request and response schemas by probing the route handler with a synthetic annotated request. Explicit metadata always takes precedence over inferred descriptors.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``operations(Operations)``
| **Mode and number of proofs:**
|    ``operations(-list(compound))`` - ``one``


------------

.. index:: schema/2
.. _http_router/0::schema/2:

``schema/2``
^^^^^^^^^^^^

Optional OpenAPI schema hook passthrough used when a router object also implements the ``open_api_provider_protocol`` protocol. Importing objects can define ``open_api_schema/2`` to expose reusable schemas referenced by derived route operations.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``schema(Name,Schema)``
| **Mode and number of proofs:**
|    ``schema(?atom,?compound)`` - ``zero_or_more``


------------

.. index:: security_scheme/2
.. _http_router/0::security_scheme/2:

``security_scheme/2``
^^^^^^^^^^^^^^^^^^^^^

Optional OpenAPI security scheme hook passthrough used when a router object also implements the ``open_api_provider_protocol`` protocol. Importing objects can define ``open_api_security_scheme/2`` to expose reusable security schemes referenced by derived route operations.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``security_scheme(Name,SecurityScheme)``
| **Mode and number of proofs:**
|    ``security_scheme(?atom,?compound)`` - ``zero_or_more``


------------

Protected predicates
--------------------

.. index:: middleware/2
.. _http_router/0::middleware/2:

``middleware/2``
^^^^^^^^^^^^^^^^

Optional hook predicate that enumerates ordered middleware descriptors. ``Id`` is the middleware identifier and ``Handler`` is the name of a declared local predicate with arity 2, typically protected, that receives the current request and returns either ``continue(Request)`` or ``respond(Response)``.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``middleware(Id,Handler)``
| **Mode and number of proofs:**
|    ``middleware(?atom,?atom)`` - ``zero_or_more``


------------

.. index:: response_middleware/2
.. _http_router/0::response_middleware/2:

``response_middleware/2``
^^^^^^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that enumerates ordered response middleware descriptors. ``Id`` is the middleware identifier and ``Handler`` is the name of a declared local predicate with arity 3, typically protected, that receives the request used to produce the current response and returns the transformed response. Routed requests preserve their route metadata annotations and negotiated media type, when applicable.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``response_middleware(Id,Handler)``
| **Mode and number of proofs:**
|    ``response_middleware(?atom,?atom)`` - ``zero_or_more``


------------

.. index:: route/4
.. _http_router/0::route/4:

``route/4``
^^^^^^^^^^^

Hook predicate that enumerates route descriptors. ``Id`` is the route identifier, ``Method`` is a lowercase HTTP method atom, ``PathTemplate`` is a path-template atom using literal segments, anonymous ``*`` wildcard segments, and optional plain or typed placeholders such as ``{id}``, ``{id:integer}``, and ``{score:number}``, and ``Handler`` is the name of a declared local predicate with arity 2, typically protected, that receives the annotated request and returns the response.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``route(Id,Method,PathTemplate,Handler)``
| **Mode and number of proofs:**
|    ``route(?atom,?atom,?atom,?atom)`` - ``zero_or_more``


------------

.. index:: route_metadata/2
.. _http_router/0::route_metadata/2:

``route_metadata/2``
^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that declares additional metadata properties for a route. When defined, ``Metadata`` must be a list of compound terms. The router removes any existing request properties with the same functors, prepends the metadata to the matched request, and then adds the standard ``route/1`` and ``path_params/1`` annotations.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``route_metadata(Id,Metadata)``
| **Mode and number of proofs:**
|    ``route_metadata(?atom,?list(compound))`` - ``zero_or_one``


------------

.. index:: authorize_routed_request/2
.. _http_router/0::authorize_routed_request/2:

``authorize_routed_request/2``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that validates or decorates a routed request after route matching and metadata annotation but before route handler dispatch. It must return either ``continue(Request)`` or ``respond(Response)``. The default implementation continues with the routed request unchanged.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``authorize_routed_request(Request,Action)``
| **Mode and number of proofs:**
|    ``authorize_routed_request(+compound,-compound)`` - ``one_or_error``

| **Exceptions:**
|    ``Action`` is not a valid route authorization action:
|        ``domain_error(http_router_route_authorization_action,Action)``


------------

.. index:: route_open_api_request_body_example/2
.. _http_router/0::route_open_api_request_body_example/2:

``route_open_api_request_body_example/2``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that enumerates example request bodies for OpenAPI inference. Each ``Body`` must be either ``empty`` or a normalized ``content(MediaType, Payload)`` term. These examples are only consulted when explicit ``request_body/1`` route metadata is absent.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``route_open_api_request_body_example(Id,Body)``
| **Mode and number of proofs:**
|    ``route_open_api_request_body_example(?atom,?compound)`` - ``zero_or_more``


------------

.. index:: route_open_api_response_example/2
.. _http_router/0::route_open_api_response_example/2:

``route_open_api_response_example/2``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that enumerates example normalized HTTP responses for OpenAPI inference. These examples are only consulted when explicit ``responses/1`` route metadata is absent.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``route_open_api_response_example(Id,Response)``
| **Mode and number of proofs:**
|    ``route_open_api_response_example(?atom,?compound)`` - ``zero_or_more``


------------

.. index:: open_api_info/1
.. _http_router/0::open_api_info/1:

``open_api_info/1``
^^^^^^^^^^^^^^^^^^^

Hook predicate that importing router objects can override to customize the default top-level OpenAPI info descriptor.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``open_api_info(Info)``
| **Mode and number of proofs:**
|    ``open_api_info(-compound)`` - ``one``


------------

.. index:: open_api_servers/1
.. _http_router/0::open_api_servers/1:

``open_api_servers/1``
^^^^^^^^^^^^^^^^^^^^^^

Hook predicate that importing router objects can override to customize the default OpenAPI server descriptors.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``open_api_servers(Servers)``
| **Mode and number of proofs:**
|    ``open_api_servers(-list(compound))`` - ``one``


------------

.. index:: open_api_security/1
.. _http_router/0::open_api_security/1:

``open_api_security/1``
^^^^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that importing router objects can define to expose top-level OpenAPI security requirements.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``open_api_security(Security)``
| **Mode and number of proofs:**
|    ``open_api_security(-list(compound))`` - ``zero_or_one``


------------

.. index:: open_api_schema/2
.. _http_router/0::open_api_schema/2:

``open_api_schema/2``
^^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that importing router objects can define to expose reusable OpenAPI schemas.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``open_api_schema(Name,Schema)``
| **Mode and number of proofs:**
|    ``open_api_schema(?atom,?compound)`` - ``zero_or_more``


------------

.. index:: open_api_security_scheme/2
.. _http_router/0::open_api_security_scheme/2:

``open_api_security_scheme/2``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that importing router objects can define to expose reusable OpenAPI security schemes.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``open_api_security_scheme(Name,SecurityScheme)``
| **Mode and number of proofs:**
|    ``open_api_security_scheme(?atom,?compound)`` - ``zero_or_more``


------------

.. index:: route_produces/2
.. _http_router/0::route_produces/2:

``route_produces/2``
^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that declares the response media types produced by a route. When defined, ``MediaTypes`` must be a non-empty list of media type atoms. The router negotiates the request ``Accept`` header against this list, annotates successful matches with ``response_media_type(MediaType)``, and returns ``406 Not Acceptable`` when no produced type matches.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``route_produces(Id,MediaTypes)``
| **Mode and number of proofs:**
|    ``route_produces(?atom,?list(atom))`` - ``zero_or_one``


------------

.. index:: path_template_parameters/2
.. _http_router/0::path_template_parameters/2:

``path_template_parameters/2``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Returns the normalized placeholder descriptors declared in a path template as ``parameter(Name, Type)`` terms.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``path_template_parameters(PathTemplate,Parameters)``
| **Mode and number of proofs:**
|    ``path_template_parameters(+atom,-list(compound))`` - ``one_or_error``

| **Exceptions:**
|    ``PathTemplate`` is not a valid router path template:
|        ``domain_error(http_router_path_template,PathTemplate)``
|    A segment in ``PathTemplate`` is not a valid router path template segment:
|        ``domain_error(http_router_path_template_segment,Segment)``


------------

.. index:: route_not_found_response/2
.. _http_router/0::route_not_found_response/2:

``route_not_found_response/2``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that customizes ``404 Not Found`` responses. When defined by the importing object, it is called with the unmatched request and must return the response to send.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``route_not_found_response(Request,Response)``
| **Mode and number of proofs:**
|    ``route_not_found_response(+compound,-compound)`` - ``zero_or_one``


------------

.. index:: route_bad_request_response/3
.. _http_router/0::route_bad_request_response/3:

``route_bad_request_response/3``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that customizes ``400 Bad Request`` responses generated from dedicated parameter-validation exceptions raised by route handlers. When defined by the importing object, it is called with the routed request, the structured parameter error list, and must return the response to send.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``route_bad_request_response(Request,Errors,Response)``
| **Mode and number of proofs:**
|    ``route_bad_request_response(+compound,+list(compound),-compound)`` - ``zero_or_one``


------------

.. index:: route_method_not_allowed_response/3
.. _http_router/0::route_method_not_allowed_response/3:

``route_method_not_allowed_response/3``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that customizes ``405 Method Not Allowed`` responses. When defined by the importing object, it is called with the request, the effective allowed methods list as lowercase atoms, and must return the response to send.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``route_method_not_allowed_response(Request,AllowedMethods,Response)``
| **Mode and number of proofs:**
|    ``route_method_not_allowed_response(+compound,+list(atom),-compound)`` - ``zero_or_one``


------------

.. index:: route_automatic_options_response/3
.. _http_router/0::route_automatic_options_response/3:

``route_automatic_options_response/3``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that customizes automatic ``OPTIONS`` responses when no explicit ``options`` route matches. When defined by the importing object, it is called with the annotated synthetic request, the effective allowed methods list as lowercase atoms, and must return the response to send.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``route_automatic_options_response(Request,EffectiveMethods,Response)``
| **Mode and number of proofs:**
|    ``route_automatic_options_response(+compound,+list(atom),-compound)`` - ``zero_or_one``


------------

.. index:: route_not_acceptable_response/3
.. _http_router/0::route_not_acceptable_response/3:

``route_not_acceptable_response/3``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Optional hook predicate that customizes ``406 Not Acceptable`` responses. When defined by the importing object, it is called with the request, the normalized produced media types for the matched route, and must return the response to send.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``route_not_acceptable_response(Request,ProducedMediaTypes,Response)``
| **Mode and number of proofs:**
|    ``route_not_acceptable_response(+compound,+list(atom),-compound)`` - ``zero_or_one``


------------

Private predicates
------------------

(no local declarations; see entity ancestors if any)

Operators
---------

(none)

