[go: up one dir, main page]

Extending Resto Service to support headers

Motivation

Defining custom headers as input or output to services is pretty much unsupported in Resto. To access the headers, developers needs to dip into the cohttp layer and figure how to "connect" that layer with the shell and protocol, a feature that Resto abstracts away in its current usage. Header fields are useful to add metadata to endpoints that are sent/received by intermediate infrastructure, alter the behaviour of an endpoint in ways that are unrelated to the core logic of the blockchain and are otherwise not commonly found in requests/response bodies or query/path params. For example, Cache-control response headers are useful to provide invalidation times of heavy/popular head queries to Cache servers. Such a feature requires calculating the current block's round end time which depends on the node store and protocol plugins.

High level design

A service in Resto is the semantic representation of an RPC service. It abstracts away the actual http library by simply focusing on the data needed to represent such a service. Additionally, a registered_service is the handler part of the resto_directory that knows how to "answer" for a service given its inputs. Below is the type definition for service and registered_service.

type (+'meth, 'prefix, 'params, 'query, 'input, 'output, 'error) service = ...
type registered_service =
    | Service : {
        types : ('q, 'i, 'o, 'e) types;
        handler : 'q -> 'i -> ('o, 'e) Answer.t Lwt.t;
      }
        -> registered_service

The handler of a service is a function that maps inputs (query parameter and input body) to outputs (output and error)

If we view headers as simply inputs and outputs, then the service and registered_service can be extended with

type (+'meth, 'prefix, 'params, 'query, 'header, 'input, 'output,''header, 'error) service = ...
type registered_service =
    | Service : {
        types : ('q, 'i, 'o, 'e) types;
        handler : 'q -> 'h -> 'i -> ('o, ''h, 'e) Answer.t Lwt.t;
      }
        -> registered_service

where 'h and ''h are the input and output headers respectively. This post is intended to be high level but a feasible implementation of the Header type would be to re-use the t Arg.t data types and extend the Resto/Cohttp integration with capability to capture the corresponding header arguments as part of the handler set up, similar to what is being done for query/path params.

For the majority of cases, developers don't need this capability so keeping the current Service structure as syntactic sugar of this new structure seems reasonable.

This would give developers finer control over their service definitions when needed.

Edited by Ryan Tan