mirror of
https://gitlab.com/msrd0/gotham-restful.git
synced 2025-02-22 20:52:27 +00:00
update doc
This commit is contained in:
parent
cc86d3396c
commit
a1acc06f6d
8 changed files with 348 additions and 111 deletions
|
@ -13,7 +13,6 @@ test-default:
|
|||
- cargo -V
|
||||
script:
|
||||
- cargo test --workspace --lib
|
||||
- cargo test --workspace --doc
|
||||
cache:
|
||||
paths:
|
||||
- cargo/
|
||||
|
@ -23,6 +22,7 @@ test-all:
|
|||
stage: test
|
||||
image: msrd0/rust:alpine-tarpaulin
|
||||
before_script:
|
||||
- apk add --no-cache postgresql-dev
|
||||
- cargo -V
|
||||
script:
|
||||
- cargo test --workspace --all-features --doc
|
||||
|
|
196
README.md
196
README.md
|
@ -23,58 +23,71 @@
|
|||
</div>
|
||||
<br/>
|
||||
|
||||
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.
|
||||
|
||||
**Note:** The `stable` branch contains some bugfixes against the last release. The `master`
|
||||
branch currently tracks gotham's master branch and the next release will use gotham 0.5.0 and be
|
||||
compatible with the new future / async stuff.
|
||||
|
||||
## Usage
|
||||
This crate is an extension to the popular [gotham web framework][gotham] for Rust. It allows you to
|
||||
create resources with assigned methods that aim to be a more convenient way of creating handlers
|
||||
for requests. Assuming you assign `/foobar` to your resource, you can implement the following
|
||||
methods:
|
||||
|
||||
A basic server with only one resource, handling a simple `GET` request, could look like this:
|
||||
| Method Name | Required Arguments | HTTP Verb | HTTP Path |
|
||||
| ----------- | ------------------ | --------- | ----------- |
|
||||
| read_all | | GET | /foobar |
|
||||
| read | id | GET | /foobar/:id |
|
||||
| search | query | GET | /foobar/search |
|
||||
| create | body | POST | /foobar |
|
||||
| change_all | body | PUT | /foobar |
|
||||
| change | id, body | PUT | /foobar/:id |
|
||||
| remove_all | | DELETE | /foobar |
|
||||
| remove | id | DELETE | /foobar/:id |
|
||||
|
||||
Each of those methods has a macro that creates the neccessary boilerplate for the Resource. A
|
||||
simple example could look like this:
|
||||
|
||||
```rust
|
||||
/// Our RESTful Resource.
|
||||
/// Our RESTful resource.
|
||||
#[derive(Resource)]
|
||||
#[rest_resource(read_all)]
|
||||
struct UsersResource;
|
||||
#[resource(read)]
|
||||
struct FooResource;
|
||||
|
||||
/// Our return type.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct User {
|
||||
id: i64,
|
||||
username: String,
|
||||
email: String
|
||||
/// The return type of the foo read method.
|
||||
#[derive(Serialize)]
|
||||
struct Foo {
|
||||
id: u64
|
||||
}
|
||||
|
||||
/// 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");
|
||||
}));
|
||||
/// The foo read method handler.
|
||||
#[read(FooResource)]
|
||||
fn read(id: u64) -> Success<Foo> {
|
||||
Foo { id }.into()
|
||||
}
|
||||
```
|
||||
|
||||
Uploads and Downloads can also be handled:
|
||||
## Arguments
|
||||
|
||||
Some methods require arguments. Those should be
|
||||
* **id** Should be a deserializable json-primitive like `i64` or `String`.
|
||||
* **body** Should be any deserializable object, or any type implementing [`RequestBody`].
|
||||
* **query** Should be any deserializable object whose variables are json-primitives. It will
|
||||
however not be parsed from json, but from HTTP GET parameters like in `search?id=1`. The
|
||||
type needs to implement [`QueryStringExtractor`].
|
||||
|
||||
Additionally, non-async handlers may take a reference to gotham's [`State`]. If you need to
|
||||
have an async handler (that is, the function that the method macro is invoked on is declared
|
||||
as `async fn`), consider returning the boxed future instead. Since [`State`] does not implement
|
||||
`Sync` there is unfortunately no more convenient way.
|
||||
|
||||
## Uploads and Downloads
|
||||
|
||||
By default, every request body is parsed from json, and every respone is converted to json using
|
||||
[serde_json]. However, you may also use raw bodies. This is an example where the request body
|
||||
is simply returned as the response again, no json parsing involved:
|
||||
|
||||
```rust
|
||||
#[derive(Resource)]
|
||||
#[rest_resource(create)]
|
||||
#[resource(create)]
|
||||
struct ImageResource;
|
||||
|
||||
#[derive(FromBody, RequestBody)]
|
||||
|
@ -84,23 +97,105 @@ struct RawImage {
|
|||
content_type: Mime
|
||||
}
|
||||
|
||||
#[rest_create(ImageResource)]
|
||||
fn create(_state : &mut State, body : RawImage) -> Raw<Vec<u8>> {
|
||||
#[create(ImageResource)]
|
||||
fn create(body : RawImage) -> Raw<Vec<u8>> {
|
||||
Raw::new(body.content, body.content_type)
|
||||
}
|
||||
```
|
||||
|
||||
Look at the [example] for more methods and usage with the `openapi` feature.
|
||||
## Features
|
||||
|
||||
## Known Issues
|
||||
To make life easier for common use-cases, this create offers a few features that might be helpful
|
||||
when you implement your web server.
|
||||
|
||||
These are currently known major issues. For a complete list please see
|
||||
[the issue tracker](https://gitlab.com/msrd0/gotham-restful/issues).
|
||||
If you encounter any issues that aren't yet reported, please report them
|
||||
[here](https://gitlab.com/msrd0/gotham-restful/issues/new).
|
||||
### Authentication Feature
|
||||
|
||||
- Enabling the `openapi` feature might break code ([#4](https://gitlab.com/msrd0/gotham-restful/issues/4))
|
||||
- For `chrono`'s `DateTime` types, the format is `date-time` instead of `datetime` ([openapiv3#14](https://github.com/glademiller/openapiv3/pull/14))
|
||||
In order to enable authentication support, enable the `auth` feature gate. This allows you to
|
||||
register a middleware that can automatically check for the existence of an JWT authentication
|
||||
token. Besides being supported by the method macros, it supports to lookup the required JWT secret
|
||||
with the JWT data, hence you can use several JWT secrets and decide on the fly which secret to use.
|
||||
None of this is currently supported by gotham's own JWT middleware.
|
||||
|
||||
A simple example that uses only a single secret could look like this:
|
||||
|
||||
```rust
|
||||
#[derive(Resource)]
|
||||
#[resource(read)]
|
||||
struct SecretResource;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Secret {
|
||||
id: u64,
|
||||
intended_for: String
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
struct AuthData {
|
||||
sub: String,
|
||||
exp: u64
|
||||
}
|
||||
|
||||
#[read(SecretResource)]
|
||||
fn read(auth: AuthStatus<AuthData>, id: u64) -> AuthSuccess<Secret> {
|
||||
let intended_for = auth.ok()?.sub;
|
||||
Ok(Secret { id, intended_for })
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let auth: AuthMiddleware<AuthData, _> = AuthMiddleware::new(
|
||||
AuthSource::AuthorizationHeader,
|
||||
AuthValidation::default(),
|
||||
StaticAuthHandler::from_array(b"zlBsA2QXnkmpe0QTh8uCvtAEa4j33YAc")
|
||||
);
|
||||
let (chain, pipelines) = single_pipeline(new_pipeline().add(auth).build());
|
||||
gotham::start("127.0.0.1:8080", build_router(chain, pipelines, |route| {
|
||||
route.resource::<SecretResource>("secret");
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
||||
### Database Feature
|
||||
|
||||
The database feature allows an easy integration of [diesel] into your handler functions. Please
|
||||
note however that due to the way gotham's diesel middleware implementation, it is not possible
|
||||
to run async code while holding a database connection. If you need to combine async and database,
|
||||
you'll need to borrow the connection from the [`State`] yourself and return a boxed future.
|
||||
|
||||
A simple non-async example could look like this:
|
||||
|
||||
```rust
|
||||
#[derive(Resource)]
|
||||
#[resource(read_all)]
|
||||
struct FooResource;
|
||||
|
||||
#[derive(Queryable, Serialize)]
|
||||
struct Foo {
|
||||
id: i64,
|
||||
value: String
|
||||
}
|
||||
|
||||
#[read_all(FooResource)]
|
||||
fn read_all(conn: &PgConnection) -> QueryResult<Vec<Foo>> {
|
||||
foo::table.load(conn)
|
||||
}
|
||||
|
||||
type Repo = gotham_middleware_diesel::Repo<PgConnection>;
|
||||
|
||||
fn main() {
|
||||
let repo = Repo::new(&env::var("DATABASE_URL").unwrap());
|
||||
let diesel = DieselMiddleware::new(repo);
|
||||
|
||||
let (chain, pipelines) = single_pipeline(new_pipeline().add(diesel).build());
|
||||
gotham::start("127.0.0.1:8080", build_router(chain, pipelines, |route| {
|
||||
route.resource::<FooResource>("foo");
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
There is a lack of good examples, but there is currently a collection of code in the [example]
|
||||
directory, that might help you. Any help writing more examples is highly appreciated.
|
||||
|
||||
## License
|
||||
|
||||
|
@ -109,7 +204,10 @@ Licensed under your option of:
|
|||
- [Eclipse Public License Version 2.0](https://gitlab.com/msrd0/gotham-restful/blob/master/LICENSE-EPL)
|
||||
|
||||
|
||||
[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----
|
||||
[diesel]: https://diesel.rs/
|
||||
[example]: https://gitlab.com/msrd0/gotham-restful/tree/master/example
|
||||
[gotham]: https://gotham.rs/
|
||||
[serde_json]: https://github.com/serde-rs/json#serde-json----
|
||||
[`QueryStringExtractor`]: ../gotham/extractor/trait.QueryStringExtractor.html
|
||||
[`RequestBody`]: trait.RequestBody.html
|
||||
[`State`]: ../gotham/state/struct.State.html
|
||||
|
|
|
@ -36,11 +36,12 @@ thiserror = "1.0.15"
|
|||
uuid = { version = ">= 0.1, < 0.9", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
diesel = { version = "1.4.4", features = ["postgres"] }
|
||||
futures-executor = "0.3.4"
|
||||
paste = "0.1.10"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["errorlog"]
|
||||
auth = ["gotham_restful_derive/auth", "base64", "cookie", "jsonwebtoken"]
|
||||
errorlog = []
|
||||
database = ["gotham_restful_derive/database", "gotham_middleware_diesel"]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::HeaderName;
|
||||
use crate::{AuthError, Forbidden, HeaderName};
|
||||
use cookie::CookieJar;
|
||||
use futures_util::{future, future::{FutureExt, TryFutureExt}};
|
||||
use gotham::{
|
||||
|
@ -58,6 +58,17 @@ where
|
|||
{
|
||||
}
|
||||
|
||||
impl<T : Send + 'static> AuthStatus<T>
|
||||
{
|
||||
pub fn ok(self) -> Result<T, AuthError>
|
||||
{
|
||||
match self {
|
||||
Self::Authenticated(data) => Ok(data),
|
||||
_ => Err(Forbidden)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The source of the authentication token in the request.
|
||||
#[derive(Clone, Debug, StateData)]
|
||||
pub enum AuthSource
|
||||
|
@ -134,7 +145,7 @@ simply add it to your pipeline and request it inside your handler:
|
|||
# use serde::{Deserialize, Serialize};
|
||||
#
|
||||
#[derive(Resource)]
|
||||
#[rest_resource(read_all)]
|
||||
#[resource(read_all)]
|
||||
struct AuthResource;
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
|
@ -143,7 +154,7 @@ struct AuthData {
|
|||
exp: u64
|
||||
}
|
||||
|
||||
#[rest_read_all(AuthResource)]
|
||||
#[read_all(AuthResource)]
|
||||
fn read_all(auth : &AuthStatus<AuthData>) -> Success<String> {
|
||||
format!("{:?}", auth).into()
|
||||
}
|
||||
|
|
|
@ -2,67 +2,85 @@
|
|||
#![warn(missing_debug_implementations, rust_2018_idioms)]
|
||||
#![deny(intra_doc_link_resolution_failure)]
|
||||
/*!
|
||||
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.
|
||||
|
||||
**Note:** The `stable` branch contains some bugfixes against the last release. The `master`
|
||||
branch currently tracks gotham's master branch and the next release will use gotham 0.5.0 and be
|
||||
compatible with the new future / async stuff.
|
||||
|
||||
# Usage
|
||||
This crate is an extension to the popular [gotham web framework][gotham] for Rust. It allows you to
|
||||
create resources with assigned methods that aim to be a more convenient way of creating handlers
|
||||
for requests. Assuming you assign `/foobar` to your resource, you can implement the following
|
||||
methods:
|
||||
|
||||
A basic server with only one resource, handling a simple `GET` request, could look like this:
|
||||
| Method Name | Required Arguments | HTTP Verb | HTTP Path |
|
||||
| ----------- | ------------------ | --------- | ----------- |
|
||||
| read_all | | GET | /foobar |
|
||||
| read | id | GET | /foobar/:id |
|
||||
| search | query | GET | /foobar/search |
|
||||
| create | body | POST | /foobar |
|
||||
| change_all | body | PUT | /foobar |
|
||||
| change | id, body | PUT | /foobar/:id |
|
||||
| remove_all | | DELETE | /foobar |
|
||||
| remove | id | DELETE | /foobar/:id |
|
||||
|
||||
Each of those methods has a macro that creates the neccessary boilerplate for the Resource. A
|
||||
simple example 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 gotham::router::builder::*;
|
||||
# use gotham_restful::*;
|
||||
# use serde::{Deserialize, Serialize};
|
||||
/// Our RESTful Resource.
|
||||
/// Our RESTful resource.
|
||||
#[derive(Resource)]
|
||||
#[rest_resource(read_all)]
|
||||
struct UsersResource;
|
||||
#[resource(read)]
|
||||
struct FooResource;
|
||||
|
||||
/// Our return type.
|
||||
#[derive(Deserialize, Serialize)]
|
||||
/// The return type of the foo read method.
|
||||
#[derive(Serialize)]
|
||||
# #[derive(OpenapiType)]
|
||||
struct User {
|
||||
id: i64,
|
||||
username: String,
|
||||
email: String
|
||||
struct Foo {
|
||||
id: u64
|
||||
}
|
||||
|
||||
/// 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");
|
||||
}));
|
||||
/// The foo read method handler.
|
||||
#[read(FooResource)]
|
||||
fn read(id: u64) -> Success<Foo> {
|
||||
Foo { id }.into()
|
||||
}
|
||||
# fn main() {
|
||||
# gotham::start("127.0.0.1:8080", build_simple_router(|route| {
|
||||
# route.resource::<FooResource>("foo");
|
||||
# }));
|
||||
# }
|
||||
```
|
||||
|
||||
Uploads and Downloads can also be handled:
|
||||
# Arguments
|
||||
|
||||
Some methods require arguments. Those should be
|
||||
* **id** Should be a deserializable json-primitive like `i64` or `String`.
|
||||
* **body** Should be any deserializable object, or any type implementing [`RequestBody`].
|
||||
* **query** Should be any deserializable object whose variables are json-primitives. It will
|
||||
however not be parsed from json, but from HTTP GET parameters like in `search?id=1`. The
|
||||
type needs to implement [`QueryStringExtractor`].
|
||||
|
||||
Additionally, non-async handlers may take a reference to gotham's [`State`]. If you need to
|
||||
have an async handler (that is, the function that the method macro is invoked on is declared
|
||||
as `async fn`), consider returning the boxed future instead. Since [`State`] does not implement
|
||||
`Sync` there is unfortunately no more convenient way.
|
||||
|
||||
# Uploads and Downloads
|
||||
|
||||
By default, every request body is parsed from json, and every respone is converted to json using
|
||||
[serde_json]. However, you may also use raw bodies. This is an example where the request body
|
||||
is simply returned as the response again, no json parsing involved:
|
||||
|
||||
```rust,no_run
|
||||
# #[macro_use] extern crate gotham_restful_derive;
|
||||
# use gotham::{router::builder::*, state::State};
|
||||
# use gotham_restful::{DrawResources, Mime, Raw, Resource, Success};
|
||||
# use gotham::router::builder::*;
|
||||
# use gotham_restful::*;
|
||||
# use serde::{Deserialize, Serialize};
|
||||
#[derive(Resource)]
|
||||
#[rest_resource(create)]
|
||||
#[resource(create)]
|
||||
struct ImageResource;
|
||||
|
||||
#[derive(FromBody, RequestBody)]
|
||||
|
@ -72,8 +90,8 @@ struct RawImage {
|
|||
content_type: Mime
|
||||
}
|
||||
|
||||
#[rest_create(ImageResource)]
|
||||
fn create(_state : &mut State, body : RawImage) -> Raw<Vec<u8>> {
|
||||
#[create(ImageResource)]
|
||||
fn create(body : RawImage) -> Raw<Vec<u8>> {
|
||||
Raw::new(body.content, body.content_type)
|
||||
}
|
||||
# fn main() {
|
||||
|
@ -83,17 +101,119 @@ fn create(_state : &mut State, body : RawImage) -> Raw<Vec<u8>> {
|
|||
# }
|
||||
```
|
||||
|
||||
Look at the [example] for more methods and usage with the `openapi` feature.
|
||||
# Features
|
||||
|
||||
# Known Issues
|
||||
To make life easier for common use-cases, this create offers a few features that might be helpful
|
||||
when you implement your web server.
|
||||
|
||||
These are currently known major issues. For a complete list please see
|
||||
[the issue tracker](https://gitlab.com/msrd0/gotham-restful/issues).
|
||||
If you encounter any issues that aren't yet reported, please report them
|
||||
[here](https://gitlab.com/msrd0/gotham-restful/issues/new).
|
||||
## Authentication Feature
|
||||
|
||||
- Enabling the `openapi` feature might break code ([#4](https://gitlab.com/msrd0/gotham-restful/issues/4))
|
||||
- For `chrono`'s `DateTime` types, the format is `date-time` instead of `datetime` ([openapiv3#14](https://github.com/glademiller/openapiv3/pull/14))
|
||||
In order to enable authentication support, enable the `auth` feature gate. This allows you to
|
||||
register a middleware that can automatically check for the existence of an JWT authentication
|
||||
token. Besides being supported by the method macros, it supports to lookup the required JWT secret
|
||||
with the JWT data, hence you can use several JWT secrets and decide on the fly which secret to use.
|
||||
None of this is currently supported by gotham's own JWT middleware.
|
||||
|
||||
A simple example that uses only a single secret could look like this:
|
||||
|
||||
```rust,no_run
|
||||
# #[macro_use] extern crate gotham_restful_derive;
|
||||
# use gotham::{router::builder::*, pipeline::{new_pipeline, single::single_pipeline}, state::State};
|
||||
# use gotham_restful::*;
|
||||
# use serde::{Deserialize, Serialize};
|
||||
#[derive(Resource)]
|
||||
#[resource(read)]
|
||||
struct SecretResource;
|
||||
|
||||
#[derive(Serialize)]
|
||||
# #[derive(OpenapiType)]
|
||||
struct Secret {
|
||||
id: u64,
|
||||
intended_for: String
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
struct AuthData {
|
||||
sub: String,
|
||||
exp: u64
|
||||
}
|
||||
|
||||
#[read(SecretResource)]
|
||||
fn read(auth: AuthStatus<AuthData>, id: u64) -> AuthSuccess<Secret> {
|
||||
let intended_for = auth.ok()?.sub;
|
||||
Ok(Secret { id, intended_for })
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let auth: AuthMiddleware<AuthData, _> = AuthMiddleware::new(
|
||||
AuthSource::AuthorizationHeader,
|
||||
AuthValidation::default(),
|
||||
StaticAuthHandler::from_array(b"zlBsA2QXnkmpe0QTh8uCvtAEa4j33YAc")
|
||||
);
|
||||
let (chain, pipelines) = single_pipeline(new_pipeline().add(auth).build());
|
||||
gotham::start("127.0.0.1:8080", build_router(chain, pipelines, |route| {
|
||||
route.resource::<SecretResource>("secret");
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
||||
## Database Feature
|
||||
|
||||
The database feature allows an easy integration of [diesel] into your handler functions. Please
|
||||
note however that due to the way gotham's diesel middleware implementation, it is not possible
|
||||
to run async code while holding a database connection. If you need to combine async and database,
|
||||
you'll need to borrow the connection from the [`State`] yourself and return a boxed future.
|
||||
|
||||
A simple non-async example could look like this:
|
||||
|
||||
```rust,no_run
|
||||
# #[macro_use] extern crate diesel;
|
||||
# #[macro_use] extern crate gotham_restful_derive;
|
||||
# use diesel::{table, PgConnection, QueryResult, RunQueryDsl};
|
||||
# use gotham::{router::builder::*, pipeline::{new_pipeline, single::single_pipeline}, state::State};
|
||||
# use gotham_middleware_diesel::DieselMiddleware;
|
||||
# use gotham_restful::*;
|
||||
# use serde::{Deserialize, Serialize};
|
||||
# use std::env;
|
||||
# table! {
|
||||
# foo (id) {
|
||||
# id -> Int8,
|
||||
# value -> Text,
|
||||
# }
|
||||
# }
|
||||
#[derive(Resource)]
|
||||
#[resource(read_all)]
|
||||
struct FooResource;
|
||||
|
||||
#[derive(Queryable, Serialize)]
|
||||
# #[derive(OpenapiType)]
|
||||
struct Foo {
|
||||
id: i64,
|
||||
value: String
|
||||
}
|
||||
|
||||
#[read_all(FooResource)]
|
||||
fn read_all(conn: &PgConnection) -> QueryResult<Vec<Foo>> {
|
||||
foo::table.load(conn)
|
||||
}
|
||||
|
||||
type Repo = gotham_middleware_diesel::Repo<PgConnection>;
|
||||
|
||||
fn main() {
|
||||
let repo = Repo::new(&env::var("DATABASE_URL").unwrap());
|
||||
let diesel = DieselMiddleware::new(repo);
|
||||
|
||||
let (chain, pipelines) = single_pipeline(new_pipeline().add(diesel).build());
|
||||
gotham::start("127.0.0.1:8080", build_router(chain, pipelines, |route| {
|
||||
route.resource::<FooResource>("foo");
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
||||
# Examples
|
||||
|
||||
There is a lack of good examples, but there is currently a collection of code in the [example]
|
||||
directory, that might help you. Any help writing more examples is highly appreciated.
|
||||
|
||||
# License
|
||||
|
||||
|
@ -102,10 +222,13 @@ Licensed under your option of:
|
|||
- [Eclipse Public License Version 2.0](https://gitlab.com/msrd0/gotham-restful/blob/master/LICENSE-EPL)
|
||||
|
||||
|
||||
[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----
|
||||
[diesel]: https://diesel.rs/
|
||||
[example]: https://gitlab.com/msrd0/gotham-restful/tree/master/example
|
||||
[gotham]: https://gotham.rs/
|
||||
[serde_json]: https://github.com/serde-rs/json#serde-json----
|
||||
[`QueryStringExtractor`]: ../gotham/extractor/trait.QueryStringExtractor.html
|
||||
[`RequestBody`]: trait.RequestBody.html
|
||||
[`State`]: ../gotham/state/struct.State.html
|
||||
*/
|
||||
|
||||
// weird proc macro issue
|
||||
|
|
|
@ -29,12 +29,13 @@ look something like this (assuming the `auth` feature is enabled):
|
|||
# use serde::Deserialize;
|
||||
#
|
||||
# #[derive(Resource)]
|
||||
# #[resource(read_all)]
|
||||
# struct MyResource;
|
||||
#
|
||||
# #[derive(Clone, Deserialize)]
|
||||
# struct MyAuthData { exp : u64 }
|
||||
#
|
||||
#[rest_read_all(MyResource)]
|
||||
#[read_all(MyResource)]
|
||||
fn read_all(auth : AuthStatus<MyAuthData>) -> AuthSuccess<NoContent> {
|
||||
let auth_data = match auth {
|
||||
AuthStatus::Authenticated(data) => data,
|
||||
|
@ -88,12 +89,13 @@ look something like this (assuming the `auth` feature is enabled):
|
|||
# use std::io;
|
||||
#
|
||||
# #[derive(Resource)]
|
||||
# #[resource(read_all)]
|
||||
# struct MyResource;
|
||||
#
|
||||
# #[derive(Clone, Deserialize)]
|
||||
# struct MyAuthData { exp : u64 }
|
||||
#
|
||||
#[rest_read_all(MyResource)]
|
||||
#[read_all(MyResource)]
|
||||
fn read_all(auth : AuthStatus<MyAuthData>) -> AuthResult<NoContent, io::Error> {
|
||||
let auth_data = match auth {
|
||||
AuthStatus::Authenticated(data) => data,
|
||||
|
|
|
@ -22,9 +22,10 @@ the function attributes:
|
|||
# use gotham_restful::*;
|
||||
#
|
||||
# #[derive(Resource)]
|
||||
# #[resource(read_all)]
|
||||
# struct MyResource;
|
||||
#
|
||||
#[rest_read_all(MyResource)]
|
||||
#[read_all(MyResource)]
|
||||
fn read_all(_state: &mut State) {
|
||||
// do something
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ Usage example:
|
|||
# use serde::{Deserialize, Serialize};
|
||||
#
|
||||
# #[derive(Resource)]
|
||||
# #[resource(read_all)]
|
||||
# struct MyResource;
|
||||
#
|
||||
#[derive(Deserialize, Serialize)]
|
||||
|
@ -33,7 +34,7 @@ struct MyResponse {
|
|||
message: &'static str
|
||||
}
|
||||
|
||||
#[rest_read_all(MyResource)]
|
||||
#[read_all(MyResource)]
|
||||
fn read_all(_state: &mut State) -> Success<MyResponse> {
|
||||
let res = MyResponse { message: "I'm always happy" };
|
||||
res.into()
|
||||
|
|
Loading…
Add table
Reference in a new issue