Boost C++ Libraries

PrevUpHomeNext

Introduction

Boost.Taar is a portable, header-only C++20 library that provides building blocks for writing HTTP servers on top of Boost.Asio, Boost.Beast, Boost.URL, and Boost.JSON.

The HTTP layer is organised around four ideas:

On top of that transport sit three optional protocol layers that reuse the same callables and the same state objects: a JSON-RPC 2.0 endpoint, a Model Context Protocol (MCP) server endpoint, and an OpenAPI document generator.

The library is header-only and does not require linking against a Taar binary. It does depend on the compiled Boost libraries that Boost.Asio, Boost.Beast, Boost.URL, Boost.JSON, and Boost.System require.

A matcher is a small object that inspects an HTTP request and answers the question does this request belong to me?. Matchers compose with the usual boolean operators (&&, ||, !) and with relational operators (==, !=) where it makes sense:

method == http::verb::get && target == "/api/sum/{a}/{b}"

Every matcher also carries a compile-time description of the constraints it imposes, which is what lets the OpenAPI generator document a route without re-parsing the expression.

A handler turns an HTTP request into an HTTP response. The library ships with two adapters:

  • taar::handler::rest wraps a plain callable. Arguments declared on the callable are produced by argument providers such as path_arg, query_arg, header_arg, cookie_arg, string_body_arg, json_body_arg and url_encoded_form_data_arg. The return value of the callable is converted into an HTTP response via the tag_invoke-based response_from extension point, so user-defined return types are supported out of the box.
  • taar::handler::htdocs serves static documents from a root directory: safe path resolution, content types, validators and conditional requests, ranges, precompressed variants and caching.

You can also supply a hand-written callable with the signature (request, context) -> http::message_generator, or one returning a chunked_response / async_generator for streaming.

Contexts

A callable may start with parameters of the form T&, T const& or std::shared_ptr<T> where T is a context type in scope. Those parameters are not fed by argument providers; the library injects the matching object:

  • the connection context of a taar::session::basic_http<T>, one object per TCP connection, shared by every request on it;
  • a keyed context added by taar::handler::with_session, looked up in a taar::context_store by a cookie or header value, with idle expiry and per-key serialisation;
  • in the MCP layer, the session object identified by Mcp-Session-Id.

Asking for a type that is not in scope is a compile-time error at the registration site, so a handler cannot silently run without the state it expects.

The taar::session::http coroutine holds a list of (matcher, handler) pairs registered through register_request_handler. For each incoming request the session walks the list, runs the first matching handler, writes the response, and continues to the next request on the same keep-alive connection.

The session distinguishes soft errors (recoverable, application-visible problems like a missing query parameter that can be turned into a 400 response) from hard errors (connection-level problems that take the connection down). Both have pluggable handlers, defaulting to sane behaviour. A known path asked with the wrong method gets 405 with an Allow header, and HEAD is served from the matching GET route.

register_request_handler accepts trailing registration observers, callables invoked once with the route's matcher metadata and handler. This is how openapi::generator::describe learns about a route.

The taar::server::tcp coroutine binds, listens, and accepts connections, spawning one HTTP session per connection. It integrates with Asio cancellation signals so a single signal can shut down the whole server.

Each layer is an ordinary object you own. It keeps its own registry of callables and hands you a handler to register on one HTTP route.

  • taar::jsonrpc::endpoint<Context...> implements JSON-RPC 2.0 on a single POST route: named parameters bound with rpc_arg, batches, notifications (answered 202), the standard error codes, and a replaceable mapping from exceptions to error objects.
  • taar::mcp::endpoint<Session, Context...> implements the Model Context Protocol over Streamable HTTP by composing a JSON-RPC endpoint: tools with input schemas derived from parameter types, resources and URI templates, the initialize lifecycle, sessions identified by Mcp-Session-Id, and a server-to-client event stream fed by notify and broadcast.
  • taar::openapi::generator records REST routes at registration time and renders an OpenAPI 3.1 document from the matcher metadata, the argument providers and the callable's return type.

The same domain function can serve all three surfaces; each layer maps its arguments and its exceptions natively, so domain code stays protocol-agnostic. See the design notes for the rationale.


PrevUpHomeNext