Macro ruma_common::api::ruma_api
source · [−]ruma_api!() { /* proc-macro */ }
Expand description
Generates IncomingRequest
and OutgoingRequest
from a concise definition.
The macro expects the following structure as input:
ruma_api! {
metadata: {
description: &'static str,
method: http::Method,
name: &'static str,
path: &'static str,
rate_limited: bool,
authentication: ruma_common::api::AuthScheme,
}
request: {
// Struct fields for each piece of data required
// to make a request to this API endpoint.
}
response: {
// Struct fields for each piece of data expected
// in the response from this API endpoint.
}
// The error returned when a response fails, defaults to `MatrixError`.
error: path::to::Error
}
This will generate a Metadata
value to be used for the associated constants of
IncomingRequest
and OutgoingRequest
, single Request
and Response
structs, and
the necessary trait implementations to convert the request into a http::Request
and to
create a response from a http::Response
and vice versa.
The details of each of the three sections of the macros are documented below.
Metadata
description
: A short description of what the endpoint does.method
: The HTTP method used for requests to the endpoint. It’s not necessary to importhttp::Method
’s associated constants. Just write the value as if it was imported, e.g.GET
.name
: A unique name for the endpoint. Generally this will be the same as the containing module.path
: The path component of the URL for the endpoint, e.g. “/foo/bar”. Components of the path that are parameterized can indicate a variable by using a Rust identifier prefixed with a colon, e.g./foo/:some_parameter
. A corresponding query string parameter will be expected in the request struct (see below for details).rate_limited
: Whether or not the endpoint enforces rate limiting on requests.authentication
: What authentication scheme the endpoint uses.
Request
The request block contains normal struct field definitions. Doc comments and attributes are
allowed as normal. There are also a few special attributes available to control how the
struct is converted into an http::Request
:
#[ruma_api(header = HEADER_NAME)]
: Fields with this attribute will be treated as HTTP headers on the request. The value must implementAsRef<str>
. Generally this is aString
. The attribute value shown above asHEADER_NAME
must be a header name constant fromhttp::header
, e.g.CONTENT_TYPE
.#[ruma_api(path)]
: Fields with this attribute will be inserted into the matching path component of the request URL.#[ruma_api(query)]
: Fields with this attribute will be inserting into the URL’s query string.#[ruma_api(query_map)]
: Instead of individual query fields, one query_map field, of any type that implementsIntoIterator<Item = (String, String)>
(e.g.HashMap<String, String>
, can be used for cases where an endpoint supports arbitrary query parameters.
Any field that does not include one of these attributes will be part of the request’s JSON body.
Response
Like the request block, the response block consists of normal struct field definitions.
Doc comments and attributes are allowed as normal.
There is also a special attribute available to control how the struct is created from a
http::Request
:
#[ruma_api(header = HEADER_NAME)]
: Fields with this attribute will be treated as HTTP headers on the response. The value must implementAsRef<str>
. Generally this is aString
. The attribute value shown above asHEADER_NAME
must be a header name constant fromhttp::header
, e.g.CONTENT_TYPE
.
Any field that does not include the above attribute will be expected in the response’s JSON body.
Newtype bodies
Both the request and response block also support “newtype bodies” by using the
#[ruma_api(body)]
attribute on a field. If present on a field, the entire request or
response body will be treated as the value of the field. This allows you to treat the
entire request or response body as a specific type, rather than a JSON object with named
fields. Only one field in each struct can be marked with this attribute. It is an error to
have a newtype body field and normal body fields within the same struct.
There is another kind of newtype body that is enabled with #[ruma_api(raw_body)]
. It is
used for endpoints in which the request or response body can be arbitrary bytes instead of
a JSON objects. A field with #[ruma_api(raw_body)]
needs to have the type Vec<u8>
.
Examples
pub mod some_endpoint {
use ruma_common::api::ruma_api;
ruma_api! {
metadata: {
description: "Does something.",
method: POST,
name: "some_endpoint",
stable_path: "/_matrix/some/endpoint/:baz",
rate_limited: false,
authentication: None,
added: 1.1,
}
request: {
pub foo: String,
#[ruma_api(header = CONTENT_TYPE)]
pub content_type: String,
#[ruma_api(query)]
pub bar: String,
#[ruma_api(path)]
pub baz: String,
}
response: {
#[ruma_api(header = CONTENT_TYPE)]
pub content_type: String,
pub value: String,
}
}
}
pub mod newtype_body_endpoint {
use ruma_common::api::ruma_api;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct MyCustomType {
pub foo: String,
}
ruma_api! {
metadata: {
description: "Does something.",
method: PUT,
name: "newtype_body_endpoint",
stable_path: "/_matrix/some/newtype/body/endpoint",
rate_limited: false,
authentication: None,
added: 1.1,
}
request: {
#[ruma_api(raw_body)]
pub file: &'a [u8],
}
response: {
#[ruma_api(body)]
pub my_custom_type: MyCustomType,
}
}
}
A procedural macro for easily generating API endpoints.
Note that for technical reasons, the ruma_api!
macro is only documented in ruma-common, not
here.