1
0
Fork 0
mirror of https://gitlab.com/msrd0/gotham-restful.git synced 2025-02-22 20:52:27 +00:00

documentation

This commit is contained in:
Dominic 2019-10-14 00:59:02 +02:00
parent 4429fced3b
commit 853ee3e94c
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
8 changed files with 274 additions and 35 deletions

View file

@ -2,8 +2,21 @@
stages:
- check
check:
check-none:
stage: check
image: msrd0/rust-pq
script:
- cargo check
- cargo check --all --no-default-features
check-all:
stage: check
image: msrd0/rust-pq
script:
- cargo check --all --all-features
readme:
stage: check
image: msrd0/rust:alpine-readme
script:
- cargo readme -r gotham_restful -t ../README.tpl >README.md.new
- diff README.md README.md.new

66
README.md Normal file
View file

@ -0,0 +1,66 @@
# gotham_restful [![Build Status](https://gitlab.com/msrd0/gotham-restful/badges/master/build.svg)](https://gitlab.com/msrd0/gotham-restful/commits/master)
This crate is an extension to the popular [gotham web framework][gotham] for Rust. The idea is to
have several RESTful resources that can be added to the gotham router. This crate will take care
of everything else, like parsing path/query parameters, request bodies, and writing response
bodies, relying on [`serde`][serde] and [`serde_json`][serde_json] for (de)serializing. If you
enable the `openapi` feature, you can also generate an OpenAPI Specification from your RESTful
resources.
## Usage
To use this crate, add the following to your `Cargo.toml`:
```toml
[dependencies]
gotham_restful = "0.0.1"
```
A basic server with only one resource, handling a simple `GET` request, could look like this:
```rust
#
/// Our RESTful Resource.
#[derive(Resource)]
#[rest_resource(read_all)]
struct UsersResource;
/// Our return type.
#[derive(Deserialize, Serialize)]
struct User {
id: i64,
username: String,
email: String
}
/// Our handler method.
#[rest_read_all(UsersResource)]
fn read_all(_state: &mut State) -> Success<Vec<User>> {
vec![User {
id: 1,
username: "h4ck3r".to_string(),
email: "h4ck3r@example.org".to_string()
}].into()
}
/// Our main method.
fn main() {
gotham::start("127.0.0.1:8080", build_simple_router(|route| {
route.resource::<UsersResource, _>("users");
}));
}
```
Look at the [example] for more methods and usage with the `openapi` feature.
## License
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THE ECLIPSE <br/>
PUBLIC LICENSE VERSION 2.0. ANY USE, REPRODUCTION OR DISTRIBUTION <br/>
OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS LICENSE.
[example]: https://gitlab.com/msrd0/gotham-restful/tree/master/example
[gotham]: https://gotham.rs/
[serde]: https://github.com/serde-rs/serde#serde-----
[serde_json]: https://github.com/serde-rs/json#serde-json----

3
README.tpl Normal file
View file

@ -0,0 +1,3 @@
# {{crate}} {{badges}}
{{readme}}

View file

@ -1,8 +1,79 @@
/*!
This crate is an extension to the popular [gotham web framework][gotham] for Rust. The idea is to
have several RESTful resources that can be added to the gotham router. This crate will take care
of everything else, like parsing path/query parameters, request bodies, and writing response
bodies, relying on [`serde`][serde] and [`serde_json`][serde_json] for (de)serializing. If you
enable the `openapi` feature, you can also generate an OpenAPI Specification from your RESTful
resources.
# Usage
To use this crate, add the following to your `Cargo.toml`:
```toml
[dependencies]
gotham_restful = "0.0.1"
```
A basic server with only one resource, handling a simple `GET` request, could look like this:
```rust,no_run
# #[macro_use] extern crate gotham_restful_derive;
# use gotham::{router::builder::*, state::State};
# use gotham_restful::{DrawResources, Resource, Success};
# use serde::{Deserialize, Serialize};
#
/// Our RESTful Resource.
#[derive(Resource)]
#[rest_resource(read_all)]
struct UsersResource;
/// Our return type.
#[derive(Deserialize, Serialize)]
# #[derive(OpenapiType)]
struct User {
id: i64,
username: String,
email: String
}
/// Our handler method.
#[rest_read_all(UsersResource)]
fn read_all(_state: &mut State) -> Success<Vec<User>> {
vec![User {
id: 1,
username: "h4ck3r".to_string(),
email: "h4ck3r@example.org".to_string()
}].into()
}
/// Our main method.
fn main() {
gotham::start("127.0.0.1:8080", build_simple_router(|route| {
route.resource::<UsersResource, _>("users");
}));
}
```
Look at the [example] for more methods and usage with the `openapi` feature.
# License
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THE ECLIPSE <br/>
PUBLIC LICENSE VERSION 2.0. ANY USE, REPRODUCTION OR DISTRIBUTION <br/>
OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS LICENSE.
[example]: https://gitlab.com/msrd0/gotham-restful/tree/master/example
[gotham]: https://gotham.rs/
[serde]: https://github.com/serde-rs/serde#serde-----
[serde_json]: https://github.com/serde-rs/json#serde-json----
*/
#[macro_use] extern crate gotham_derive;
#[macro_use] extern crate serde;
pub use hyper::StatusCode;
use serde::{de::DeserializeOwned, Serialize};
pub use gotham_restful_derive::*;
@ -17,7 +88,7 @@ pub mod export
}
#[cfg(feature = "openapi")]
pub mod openapi;
mod openapi;
#[cfg(feature = "openapi")]
pub use openapi::{
router::{GetOpenapi, OpenapiRouter},
@ -49,29 +120,5 @@ pub use routing::{DrawResources, DrawResourceRoutes};
#[cfg(feature = "openapi")]
pub use routing::WithOpenapi;
/// A type that can be used inside a request or response body. Implemented for every type
/// that is serializable with serde, however, it is recommended to use the rest_struct!
/// macro to create one.
#[cfg(not(feature = "openapi"))]
pub trait ResourceType : DeserializeOwned + Serialize
{
}
#[cfg(not(feature = "openapi"))]
impl<T : DeserializeOwned + Serialize> ResourceType for T
{
}
/// A type that can be used inside a request or response body. Implemented for every type
/// that is serializable with serde, however, it is recommended to use the rest_struct!
/// macro to create one.
#[cfg(feature = "openapi")]
pub trait ResourceType : OpenapiType + DeserializeOwned + Serialize
{
}
#[cfg(feature = "openapi")]
impl<T : OpenapiType + DeserializeOwned + Serialize> ResourceType for T
{
}
mod types;
pub use types::ResourceType;

View file

@ -27,6 +27,12 @@ use openapiv3::{
use serde::de::DeserializeOwned;
use std::panic::RefUnwindSafe;
/**
This type is required to build routes while adding them to the generated OpenAPI Spec at the
same time. There is no need to use this type directly. See [`WithOpenapi`] on how to do this.
[`WithOpenapi`]: trait.WithOpenapi.html
*/
pub struct OpenapiRouter(OpenAPI);
impl OpenapiRouter
@ -159,6 +165,7 @@ impl Handler for OpenapiHandler
}
}
/// This trait adds the `get_openapi` method to an OpenAPI-aware router.
pub trait GetOpenapi
{
fn get_openapi(&mut self, path : &str);

View file

@ -10,18 +10,32 @@ use openapiv3::{
#[cfg(feature = "chrono")]
use openapiv3::{StringFormat, VariantOrUnknownOrEmpty};
/**
This struct needs to be available for every type that can be part of an OpenAPI Spec. It is
already implemented for primitive types, String, Vec, Option and the like. To have it available
for your type, simply derive from [`OpenapiType`].
[`OpenapiType`]: trait.OpenapiType.html
*/
#[derive(Debug, Clone, PartialEq)]
pub struct OpenapiSchema
{
/// The name of this schema. If it is None, the schema will be inlined.
pub name : Option<String>,
/// Whether this particular schema is nullable. Note that there is no guarantee that this will
/// make it into the final specification, it might just be interpreted as a hint to make it
/// an optional parameter.
pub nullable : bool,
/// The actual OpenAPI schema.
pub schema : SchemaKind,
/// Other schemas that this schema depends on. They will be included in the final OpenAPI Spec
/// along with this schema.
pub dependencies : IndexMap<String, OpenapiSchema>
}
impl OpenapiSchema
{
/// Create a new schema that has no name.
pub fn new(schema : SchemaKind) -> Self
{
Self {
@ -31,7 +45,8 @@ impl OpenapiSchema
dependencies: IndexMap::new()
}
}
/// Convert this schema to an `openapiv3::Schema` that can be serialized to the OpenAPI Spec.
pub fn into_schema(self) -> Schema
{
Schema {
@ -52,6 +67,20 @@ impl OpenapiSchema
}
}
/**
This trait needs to be implemented by every type that is being used in the OpenAPI Spec. It gives
access to the [`OpenapiSchema`] of this type. It is provided for primitive types, String and the
like. For use on your own types, there is a derive macro:
```
# #[macro_use] extern crate gotham_restful_derive;
#
#[derive(OpenapiType)]
struct MyResponse {
message: String
}
```
*/
pub trait OpenapiType
{
fn schema() -> OpenapiSchema;
@ -115,7 +144,7 @@ macro_rules! str_types {
(format = $format:ident, $($str_ty:ty),*) => {$(
impl OpenapiType for $str_ty
{
fn to_schema() -> OpenapiSchema
fn schema() -> OpenapiSchema
{
OpenapiSchema::new(SchemaKind::Type(Type::String(StringType {
format: VariantOrUnknownOrEmpty::Item(StringFormat::$format),

View file

@ -68,7 +68,31 @@ impl<R : ResourceType, E : Error> ResourceResult for Result<R, E>
}
}
/// This can be returned from a resource when there is no cause of an error.
/**
This can be returned from a resource when there is no cause of an error. For example:
```
# #[macro_use] extern crate gotham_restful_derive;
# use gotham::state::State;
# use gotham_restful::Success;
# use serde::{Deserialize, Serialize};
#
# #[derive(Resource)]
# struct MyResource;
#
#[derive(Deserialize, Serialize)]
# #[derive(OpenapiType)]
struct MyResponse {
message: String
}
#[rest_read_all(MyResource)]
fn read_all(_state: &mut State) -> Success<MyResponse> {
let res = MyResponse { message: "I'm always happy".to_string() };
res.into()
}
```
*/
pub struct Success<T>(T);
impl<T> From<T> for Success<T>
@ -93,7 +117,24 @@ impl<T : ResourceType> ResourceResult for Success<T>
}
}
/// This can be returned from a resource when there is no content to send.
/**
This is the return type of a resource that doesn't actually return something. It will result
in a _204 No Content_ answer by default. You don't need to use this type directly if using
the function attributes:
```
# #[macro_use] extern crate gotham_restful_derive;
# use gotham::state::State;
#
# #[derive(Resource)]
# struct MyResource;
#
#[rest_read_all(MyResource)]
fn read_all(_state: &mut State) {
// do something
}
```
*/
#[derive(Default)]
pub struct NoContent;
@ -107,17 +148,20 @@ impl From<()> for NoContent
impl ResourceResult for NoContent
{
/// This will always be a _204 No Content_ together with an empty string.
fn to_json(&self) -> Result<(StatusCode, String), SerdeJsonError>
{
Ok((StatusCode::NO_CONTENT, "".to_string()))
Ok((Self::default_status(), "".to_string()))
}
/// Returns the schema of the `()` type.
#[cfg(feature = "openapi")]
fn schema() -> OpenapiSchema
{
<()>::schema()
}
/// This will always be a _204 No Content_
#[cfg(feature = "openapi")]
fn default_status() -> StatusCode
{

View file

@ -0,0 +1,30 @@
#[cfg(feature = "openapi")]
use crate::OpenapiType;
use serde::{de::DeserializeOwned, Serialize};
/// A type that can be used inside a request or response body. Implemented for every type
/// that is serializable with serde, however, it is recommended to use the rest_struct!
/// macro to create one.
#[cfg(not(feature = "openapi"))]
pub trait ResourceType : DeserializeOwned + Serialize
{
}
#[cfg(not(feature = "openapi"))]
impl<T : DeserializeOwned + Serialize> ResourceType for T
{
}
/// A type that can be used inside a request or response body. Implemented for every type
/// that is serializable with serde, however, it is recommended to use the rest_struct!
/// macro to create one.
#[cfg(feature = "openapi")]
pub trait ResourceType : OpenapiType + DeserializeOwned + Serialize
{
}
#[cfg(feature = "openapi")]
impl<T : OpenapiType + DeserializeOwned + Serialize> ResourceType for T
{
}