Add complete documentation.
This commit is contained in:
parent
b292a3e776
commit
0f32ca01db
9
.travis.yml
Normal file
9
.travis.yml
Normal file
@ -0,0 +1,9 @@
|
||||
language: "rust"
|
||||
notifications:
|
||||
email: false
|
||||
irc:
|
||||
channels:
|
||||
- secure: "FiHwNDkLqlzn+fZnn42uZ+GWm59S9OJreUIz9r7+nXrxUBeBcthQlqamJUiuYryVohzqLydBVv6xmT5wgS/LxRnj4f363eBpKejuSktglnf2rl8JjuSXZVgrPMDmrfgkBdC+aMCPzdw2fIHSWmvQMr/t9kGW9cHl0VlLxPAhnAsry+E1Kxrrz4IuOJmyb43VqPf/GO6VCDzTpHiKHKe5Rp7i2IkbGus2GiSD/UMrgUTWmMOFoejl7fWX7SH9kvSrN/SCYldVOYA4nazeZfaHv7mCX6G8U3GGXTHwjAVAluXyYgUCYpsYKC5KGkUJFcLhjaBu5qpmlI0EZd/rsgscOBzqfJ0D/WkahWiKtlQEKZ7UEAhA3SaAhcrSh2kSQFf2GW1T8kfzqlnBtjpqSvCFuOpY5XQcSYEEX7qxT1aiK2UBi9iAKgMnG1SDEfeFERekw0KJPKbwJDMV7NhCg9kYVBHG1hxvFeYqMmnFrjLlRDQQrbDHrP9Avdtg0FScolsFVmT+uatBuRXDcqunssolfnWguyrQ0Z9KGauv0iqkwFwO7jQSA9f87wgsuzqlzstHRxoGGlPtGt4J/+MhyA3lOEXwBa5eotjILI7iykK+ykJ33cOTGcqyXbkWoYRZ6+fS2guI+f2CxxsYWUOK2UgMyYKEwtraC3duVIGtQR+zuvc="
|
||||
use_notice: true
|
||||
rust:
|
||||
- "nightly"
|
@ -25,5 +25,4 @@ serde_urlencoded = "0.5.1"
|
||||
url = "1.5.1"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
proc-macro = true
|
||||
|
19
LICENSE
Normal file
19
LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2017 Jimmy Cuadra
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
74
README.md
Normal file
74
README.md
Normal file
@ -0,0 +1,74 @@
|
||||
# ruma-api-macros
|
||||
|
||||
[](https://travis-ci.org/ruma/ruma-api-macros)
|
||||
|
||||
**ruma-api-macros** provides a procedural macro for easily generating [ruma-api](https://github.com/ruma/ruma-api)-compatible API endpoints.
|
||||
You define the endpoint's metadata, request fields, and response fields, and the macro generates all the necessary types and implements all the necessary traits.
|
||||
|
||||
## Usage
|
||||
|
||||
Here is an example that shows most of the macro's functionality.
|
||||
|
||||
``` rust
|
||||
#![feature(associated_consts, proc_macro, try_from)]
|
||||
|
||||
extern crate futures;
|
||||
extern crate hyper;
|
||||
extern crate ruma_api;
|
||||
extern crate ruma_api_macros;
|
||||
extern crate serde;
|
||||
#[macro_use] extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
extern crate serde_urlencoded;
|
||||
extern crate url;
|
||||
|
||||
pub mod some_endpoint {
|
||||
use ruma_api_macros::ruma_api;
|
||||
|
||||
ruma_api! {
|
||||
metadata {
|
||||
description: "Does something.",
|
||||
method: Method::Get, // A `hyper::Method` value. No need to import the name.
|
||||
name: "some_endpoint",
|
||||
path: "/_matrix/some/endpoint/:baz",
|
||||
rate_limited: false,
|
||||
requires_authentication: false,
|
||||
}
|
||||
|
||||
request {
|
||||
// With no attribute on the field, it will be put into the body of the request.
|
||||
pub foo: String,
|
||||
|
||||
// This value will be put into the "Content-Type" HTTP header.
|
||||
#[ruma_api(header)]
|
||||
pub content_type: ContentType,
|
||||
|
||||
// This value will be put into the query string of the request's URL.
|
||||
#[ruma_api(query)]
|
||||
pub bar: String,
|
||||
|
||||
// This value will be inserted into the request's URL in place of the
|
||||
// ":baz" path component.
|
||||
#[ruma_api(path)]
|
||||
pub baz: String,
|
||||
}
|
||||
|
||||
response {
|
||||
// This value will be extracted from the "Content-Type" HTTP header.
|
||||
#[ruma_api(header)]
|
||||
pub content_type: ContentType,
|
||||
|
||||
// With no attribute on the field, it will be extracted from the body of the response.
|
||||
pub value: String,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
ruma-api-macros has [comprehensive documentation](https://docs.rs/ruma-api-macros) available on docs.rs.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](http://opensource.org/licenses/MIT)
|
174
src/lib.rs
174
src/lib.rs
@ -1,5 +1,7 @@
|
||||
//! Crate `ruma-api-macros` provides a procedural macro for easily generating
|
||||
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
|
||||
//!
|
||||
//! See the documentation for the `ruma_api!` macro for usage details.
|
||||
|
||||
#![deny(missing_debug_implementations)]
|
||||
#![feature(proc_macro)]
|
||||
@ -21,7 +23,177 @@ use parse::parse_entries;
|
||||
mod api;
|
||||
mod parse;
|
||||
|
||||
/// Generates a `ruma-api` endpoint.
|
||||
/// Generates a `ruma_api::Endpoint` from a concise definition.
|
||||
///
|
||||
/// The macro expects the following structure as input:
|
||||
///
|
||||
/// ```text
|
||||
/// ruma_api! {
|
||||
/// metadata {
|
||||
/// description: &'static str
|
||||
/// method: hyper::Method,
|
||||
/// name: &'static str,
|
||||
/// path: &'static str,
|
||||
/// rate_limited: bool,
|
||||
/// requires_authentication: bool,
|
||||
/// }
|
||||
///
|
||||
/// 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.
|
||||
/// }
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
|
||||
/// associated constant, single `Request` and `Response` structs, and the necessary trait
|
||||
/// implementations to convert the request into a `hyper::Request` and to create a response from a
|
||||
/// `hyper::response`.
|
||||
///
|
||||
/// 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 import `hyper::Method`, you just write the value as if it was
|
||||
/// imported, e.g. `Method::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 varible 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.
|
||||
/// * `requires_authentication`: Whether or not the endpoint requires a valid access token.
|
||||
///
|
||||
/// ## 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 a
|
||||
/// `hyper::Request`:
|
||||
///
|
||||
/// * `#[ruma_api(header)]`: Fields with this attribute will be treated as HTTP headers on the
|
||||
/// request.
|
||||
/// The value must implement `hyper::header::Header`.
|
||||
/// * `#[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.
|
||||
///
|
||||
/// 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
|
||||
/// `hyper::Request`:
|
||||
///
|
||||
/// * `#[ruma_api(header)]`: Fields with this attribute will be treated as HTTP headers on the
|
||||
/// response.
|
||||
/// The value must implement `hyper::header::Header`.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// #![feature(associated_consts, proc_macro, try_from)]
|
||||
///
|
||||
/// extern crate futures;
|
||||
/// extern crate hyper;
|
||||
/// extern crate ruma_api;
|
||||
/// extern crate ruma_api_macros;
|
||||
/// extern crate serde;
|
||||
/// #[macro_use] extern crate serde_derive;
|
||||
/// extern crate serde_json;
|
||||
/// extern crate serde_urlencoded;
|
||||
/// extern crate url;
|
||||
///
|
||||
/// # fn main() {
|
||||
/// pub mod some_endpoint {
|
||||
/// use hyper::header::ContentType;
|
||||
/// use ruma_api_macros::ruma_api;
|
||||
///
|
||||
/// ruma_api! {
|
||||
/// metadata {
|
||||
/// description: "Does something.",
|
||||
/// method: Method::Get,
|
||||
/// name: "some_endpoint",
|
||||
/// path: "/_matrix/some/endpoint/:baz",
|
||||
/// rate_limited: false,
|
||||
/// requires_authentication: false,
|
||||
/// }
|
||||
///
|
||||
/// request {
|
||||
/// pub foo: String,
|
||||
/// #[ruma_api(header)]
|
||||
/// pub content_type: ContentType,
|
||||
/// #[ruma_api(query)]
|
||||
/// pub bar: String,
|
||||
/// #[ruma_api(path)]
|
||||
/// pub baz: String,
|
||||
/// }
|
||||
///
|
||||
/// response {
|
||||
/// #[ruma_api(header)]
|
||||
/// pub content_type: ContentType,
|
||||
/// pub value: String,
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// pub mod newtype_body_endpoint {
|
||||
/// use ruma_api_macros::ruma_api;
|
||||
///
|
||||
/// #[derive(Debug, Deserialize)]
|
||||
/// pub struct MyCustomType {
|
||||
/// pub foo: String,
|
||||
/// }
|
||||
///
|
||||
/// ruma_api! {
|
||||
/// metadata {
|
||||
/// description: "Does something.",
|
||||
/// method: Method::Get,
|
||||
/// name: "newtype_body_endpoint",
|
||||
/// path: "/_matrix/some/newtype/body/endpoint",
|
||||
/// rate_limited: false,
|
||||
/// requires_authentication: false,
|
||||
/// }
|
||||
///
|
||||
/// request {
|
||||
/// #[ruma_api(body)]
|
||||
/// pub file: Vec<u8>,
|
||||
/// }
|
||||
///
|
||||
/// response {
|
||||
/// #[ruma_api(body)]
|
||||
/// pub my_custom_type: MyCustomType,
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn ruma_api(input: TokenStream) -> TokenStream {
|
||||
let entries = parse_entries(&input.to_string()).expect("ruma_api! failed to parse input");
|
||||
|
Loading…
x
Reference in New Issue
Block a user