package resto-cohttp-server

  1. Overview
  2. Docs
type step = Resto_directory.Make(Encoding).step =
  1. | Static of string
    (*

    A literal chunk

    *)
  2. | Dynamic of Resto.Arg.descr
    (*

    A chunk which describes a argument to a service

    *)
  3. | DynamicTail of Resto.Arg.descr
    (*

    The remainder of the chunks are to be interpreted as a list of arguments

    *)

The different chunks of a path

E.g., /archive/<year>/<months>/ has a Static "archive" step followed by a Dynamic _ step followed by a Dynamic _ step. Each Dynamic _ step has an Resto.Arg payload describing the chunk.

type conflict = Resto_directory.Make(Encoding).conflict =
  1. | CService of Resto.meth
    (*

    A collision with a service that has been already defined for the given method at the certain path.

    *)
  2. | CDir
    (*

    An incompatibility with the directory at a certain path.

    *)
  3. | CBuilder
    (*

    A collision with the builder part of another dynamic directory of a certain path.

    *)
  4. | CDynDescr of string * string
    (*

    A collision between the descriptions of two given dynamic directories.

    *)
  5. | CTail
    (*

    A collision with another dynamic tail directory of a certain path.

    *)
  6. | CTypes of Resto.Arg.descr * Resto.Arg.descr
    (*

    A typing incompatibility with an URI parameter of a certain type when another parameter type was expected.

    *)
  7. | CType of Resto.Arg.descr * string list
    (*

    A typing impompatibility with an URI parameter with the given subdirectories.

    *)

Possible kind of conflictual error that can occur while registering services into a directory or while merging directories.

exception Conflict of step list * conflict
type ('query, 'input, 'output, 'error) types = ('query, 'input, 'output, 'error) Resto_directory.Make(Encoding).types = {
  1. query : 'query Resto.Query.t;
  2. input : 'input Service.input;
  3. output : 'output Encoding.t;
  4. error : 'error Encoding.t;
}
type registered_service = Resto_directory.Make(Encoding).registered_service =
  1. | Service : {
    1. types : ('q, 'i, 'o, 'e) types;
    2. handler : 'q -> 'i -> ('o, 'e) Resto_directory.Answer.t Lwt.t;
    } -> registered_service
type 'prefix t = 'prefix Resto_directory.Make(Encoding).t

Dispatch tree

type 'prefix directory = 'prefix t
type lookup_error = [
  1. | `Not_found
  2. | `Method_not_allowed of Resto.meth list
  3. | `Cannot_parse_path of string list * Resto.Arg.descr * string
]
val string_of_step : step -> string

string_of_step step converts the given steps into a string.

val string_of_conflict_kind : conflict -> string

string_of_conflict_kind conflict_kind converts the given conflict_kind into a string.

val string_of_conflict : (step list * conflict) -> string

string_of_conflict conflict converts the given conflict into a string.

val lookup : 'prefix directory -> 'prefix -> Resto.meth -> string list -> (registered_service, [> lookup_error ]) result Lwt.t

lookup d m p is Ok (Service _) if there is a service s registered in d and both the method of s is m and the path of s matches p. It is Error _ otherwise.

If it is Ok (Service _) then the returned value corresponds to the registered service.

val lookup_uri_desc : 'prefix directory -> 'prefix -> Resto.meth -> string list -> (string, [> lookup_error ]) result Lwt.t

lookup_uri_desc d p is Ok u where u is a formated URI description, if there is a service s registered in d and the path of s matches p. It is Error _ otherwise.

For instance, given the following path p: "/entries-by-date/2022/01/10" where "2022", "01", and "10" are expected to be paramaters in the path of s, the function will evaluate in "/entries-by-date/<year>/<month>/<day>".

val allowed_methods : 'prefix directory -> 'prefix -> string list -> (Resto.meth list, [> lookup_error ]) result Lwt.t

allowed_methods d p is the set of methods m such that lookup d m p is Ok _. In other words, it is the set of methods m such that a service has been registered in d for a path that matches p.

val transparent_lookup : 'prefix directory -> ('meth, 'prefix, 'params, 'query, 'input, 'output, 'error) Service.t -> 'params -> 'query -> 'input -> [> ('output, 'error) Resto_directory.Answer.t ] Lwt.t
val empty : 'prefix directory

Empty tree

val map : ('a -> 'b Lwt.t) -> 'b directory -> 'a directory
val prefix : ('pr, 'p) Resto.Path.path -> 'p directory -> 'pr directory

prefix p d is a directory of services which includes a service registered on the path p / q for each service registered on the path q in d.

  • raises [Invalid_argument]

    if p is a dynamic path.

val merge : ?strategy:[ `Raise | `Pick_left | `Pick_right ] -> 'a directory -> 'a directory -> 'a directory

merge ~strategy d1 d2 is a directory which includes all the services of d1 and d2.

It is possible to merge both static and dynamic trees.

  • In case of static trees, the resulting merge will occur in a eager way at function call.
  • In case of dynamic trees and because of their nature, the resulting merging directory can't however be computed directly: We don't know the subtree of such a tree before resolving it whith a proper argument key and thus don't have a way to merge it directly at function call. In such a case, the merging computation will be delayed at resolving time. This may not be a problem in most cases. But merging directories containing a lot of nested dynamic directories should still be avoided as it may impact queries performances.

As a few elements that constitutes a directory tree are not mergeable, it may be possible to come upon a collision case during a merge. Unmergeable elements are:

  • Services
  • Dynamic directories description.

If one or more of these elements from d1 collides with one or more element from d2, the function will make a choice depending on the given merging strategy:

  • `Raise will raise a Conflict exception. This is the default choice.
  • `Pick_left will pick the element from d1 to be part of the resulting directory.
  • `Pick_right will pick the element from d2 to be part of the resulting directory.
  • raises [Conflict]

    if:

    • One or more unmergeable element from d1 collides with one or more unmergeable element from d2 and the merging strategy is `Raise or unspecified.
    • Sub-directories can't be merged because of a structural conflict. For instance, if a path leads from d1 to a sub-directory d1' that is an URI parameter, but path also leads from d2 to a sub-directory d2' that is only a static segment of the URI.
    • Sub-directories can't be merged because of a typing conflict. For instance, if a path leads from d1 to a sub-directory d1' that is an URI parameter of type int, but path, also leads from d2 to a sub-directory d2' that is an URI parameter of type float.
val register : 'prefix directory -> ('meth, 'prefix, 'params, 'query, 'input, 'output, 'error) Service.t -> ('params -> 'query -> 'input -> [< ('output, 'error) Resto_directory.Answer.t ] Lwt.t) -> 'prefix directory

register d s h is a directory that contains all the services registered in d plus the service s. Requests to the service s are handled by the handler h.

val register0 : unit directory -> ('m, unit, unit, 'q, 'i, 'o, 'e) Service.t -> ('q -> 'i -> [< ('o, 'e) Resto_directory.Answer.t ] Lwt.t) -> unit directory

Registring handler in service tree. Curryfied variant.

val register1 : 'prefix directory -> ('m, 'prefix, unit * 'a, 'q, 'i, 'o, 'e) Service.t -> ('a -> 'q -> 'i -> [< ('o, 'e) Resto_directory.Answer.t ] Lwt.t) -> 'prefix directory
val register2 : 'prefix directory -> ('m, 'prefix, (unit * 'a) * 'b, 'q, 'i, 'o, 'e) Service.t -> ('a -> 'b -> 'q -> 'i -> [< ('o, 'e) Resto_directory.Answer.t ] Lwt.t) -> 'prefix directory
val register3 : 'prefix directory -> ('m, 'prefix, ((unit * 'a) * 'b) * 'c, 'q, 'i, 'o, 'e) Service.t -> ('a -> 'b -> 'c -> 'q -> 'i -> [< ('o, 'e) Resto_directory.Answer.t ] Lwt.t) -> 'prefix directory
val register4 : 'prefix directory -> ('m, 'prefix, (((unit * 'a) * 'b) * 'c) * 'd, 'q, 'i, 'o, 'e) Service.t -> ('a -> 'b -> 'c -> 'd -> 'q -> 'i -> [< ('o, 'e) Resto_directory.Answer.t ] Lwt.t) -> 'prefix directory
val register5 : 'prefix directory -> ('m, 'prefix, ((((unit * 'a) * 'b) * 'c) * 'd) * 'f, 'q, 'i, 'o, 'e) Service.t -> ('a -> 'b -> 'c -> 'd -> 'f -> 'q -> 'i -> [< ('o, 'e) Resto_directory.Answer.t ] Lwt.t) -> 'prefix directory
val register_dynamic_directory : ?descr:string -> 'prefix directory -> ('prefix, 'a) Resto.Path.path -> ('a -> 'a directory Lwt.t) -> 'prefix directory

Registring dynamic subtree.

val register_dynamic_directory1 : ?descr:string -> 'prefix directory -> ('prefix, unit * 'a) Resto.Path.path -> ('a -> (unit * 'a) directory Lwt.t) -> 'prefix directory

Registring dynamic subtree. (Curryfied variant)

val register_dynamic_directory2 : ?descr:string -> 'prefix directory -> ('prefix, (unit * 'a) * 'b) Resto.Path.path -> ('a -> 'b -> ((unit * 'a) * 'b) directory Lwt.t) -> 'prefix directory
val register_dynamic_directory3 : ?descr:string -> 'prefix directory -> ('prefix, ((unit * 'a) * 'b) * 'c) Resto.Path.path -> ('a -> 'b -> 'c -> (((unit * 'a) * 'b) * 'c) directory Lwt.t) -> 'prefix directory
val register_describe_directory_service : 'prefix directory -> ('prefix, 'prefix, 'error) Service.description_service -> 'prefix directory

Registring a description service.

val describe_directory : recurse:bool -> ?arg:'a -> 'a directory -> Encoding.schema Resto.Description.directory Lwt.t
OCaml

Innovation. Community. Security.