|
1 | | -//! # Serve the web |
2 | | -//! |
3 | | -//! Tide is a friendly HTTP server built for casual Rustaceans and veterans alike. It's completely |
4 | | -//! modular, and built directly for `async/await`. Whether it's a quick webhook, or an L7 load |
5 | | -//! balancer, Tide will make it work. |
6 | | -//! |
7 | | -//! # Features |
8 | | -//! |
9 | | -//! - __Fast:__ Written in Rust, and built on Futures, Tide is incredibly efficient. |
10 | | -//! - __Friendly:__ With thorough documentation, and a complete API, Tide helps cover your every |
11 | | -//! need. |
12 | | -//! - __Minimal:__ With only a few concepts to learn, Tide is easy to pick up and become productive |
13 | | -//! with. |
| 1 | +//! Tide is a minimal and pragmatic Rust web application framework built for |
| 2 | +//! rapid development. It comes with a robust set of features that make |
| 3 | +//! building database-backed web applications easier and more fun. |
14 | 4 | //! |
15 | 5 | //! # Getting started |
16 | 6 | //! |
17 | | -//! Add two dependencies to your project's `Cargo.toml` file: `tide` itself, and `async-std` with the feature `attributes` enabled: |
| 7 | +//! In order to build a web app in Rust you need an HTTP server, and an async |
| 8 | +//! runtime. After running `cargo init` add the following lines to your |
| 9 | +//! `Cargo.toml` file: |
| 10 | +//! |
18 | 11 | //! ```toml |
19 | 12 | //! # Example, use the version numbers you need |
20 | | -//! tide = "0.7.0" |
21 | | -//! async-std = { version = "1.5.0", features = ["attributes"] } |
| 13 | +//! tide = "0.13.0" |
| 14 | +//! async-std = { version = "1.6.0", features = ["attributes"] } |
22 | 15 | //!``` |
23 | 16 | //! |
24 | 17 | //! # Examples |
25 | 18 | //! |
26 | | -//! __hello world__ |
27 | | -//! ```no_run |
28 | | -//! # use async_std::task::block_on; |
29 | | -//! # fn main() -> Result<(), std::io::Error> { block_on(async { |
30 | | -//! # |
31 | | -//! let mut app = tide::new(); |
32 | | -//! app.at("/").get(|_| async { Ok("Hello, world!") }); |
33 | | -//! app.listen("127.0.0.1:8080").await?; |
34 | | -//! # |
35 | | -//! # Ok(()) }) } |
36 | | -//! ``` |
| 19 | +//! Create an HTTP server that takes JSON, validates it, and responds with a |
| 20 | +//! confirmation message. |
37 | 21 | //! |
38 | | -//! __echo server__ |
39 | 22 | //! ```no_run |
40 | | -//! # use async_std::task::block_on; |
41 | | -//! # fn main() -> Result<(), std::io::Error> { block_on(async { |
42 | | -//! # |
43 | | -//! let mut app = tide::new(); |
44 | | -//! app.at("/").get(|req| async { Ok(req) }); |
45 | | -//! app.listen("127.0.0.1:8080").await?; |
46 | | -//! # |
47 | | -//! # Ok(()) }) } |
48 | | -//! ```` |
49 | | -//! |
50 | | -//! __send and receive json__ |
51 | | -//! ```no_run |
52 | | -//! # use async_std::task::block_on; |
53 | | -//! # fn main() -> Result<(), std::io::Error> { block_on(async { |
54 | | -//! # use tide::{Body, Request, Response}; |
55 | | -//! # |
56 | | -//! #[derive(Debug, serde::Deserialize, serde::Serialize)] |
57 | | -//! struct Counter { count: usize } |
58 | | -//! |
59 | | -//! let mut app = tide::new(); |
60 | | -//! app.at("/").get(|mut req: Request<()>| async move { |
61 | | -//! let mut counter: Counter = req.body_json().await?; |
62 | | -//! println!("count is {}", counter.count); |
63 | | -//! counter.count += 1; |
64 | | -//! let mut res = Response::new(200); |
65 | | -//! res.set_body(Body::from_json(&counter)?); |
66 | | -//! Ok(res) |
67 | | -//! }); |
68 | | -//! app.listen("127.0.0.1:8080").await?; |
69 | | -//! # |
70 | | -//! # Ok(()) }) } |
71 | | -//! ``` |
| 23 | +//! use tide::Request; |
| 24 | +//! use tide::prelude::*; |
72 | 25 | //! |
73 | | -//! # Concepts |
74 | | -//! |
75 | | -//! ## Request-Response |
76 | | -//! |
77 | | -//! Each Tide endpoint takes a [`Request`] and returns a [`Response`]. Because async functions |
78 | | -//! allow us to wait without blocking, this makes Tide feel similar to synchronous servers. Except |
79 | | -//! it's incredibly efficient. |
80 | | -//! |
81 | | -//! ```txt |
82 | | -//! async fn endpoint(req: Request) -> Result; |
83 | | -//! ``` |
84 | | -//! |
85 | | -//! ## Middleware |
86 | | -//! |
87 | | -//! Middleware wrap each request and response pair, allowing code to be run before the endpoint, |
88 | | -//! and after each endpoint. Additionally each handler can choose to never yield to the endpoint |
89 | | -//! and abort early. This is useful for e.g. authentication middleware. Tide's middleware works |
90 | | -//! like a stack. A simplified example of the logger middleware is something like this: |
91 | | -//! |
92 | | -//! ```ignore |
93 | | -//! async fn log(req: Request, next: Next) -> tide::Result { |
94 | | -//! println!("Incoming request from {} on url {}", req.peer_addr(), req.url()); |
95 | | -//! let res = next().await?; |
96 | | -//! println!("Outgoing response with status {}", res.status()); |
97 | | -//! res |
| 26 | +//! #[derive(Debug, Deserialize)] |
| 27 | +//! struct Animal { |
| 28 | +//! name: String, |
| 29 | +//! legs: u8, |
98 | 30 | //! } |
99 | | -//! ``` |
100 | | -//! |
101 | | -//! As a new request comes in, we perform some logic. Then we yield to the next |
102 | | -//! middleware (or endpoint, we don't know when we yield to `next`), and once that's |
103 | | -//! done, we return the Response. We can decide to not yield to `next` at any stage, |
104 | | -//! and abort early. This can then be used in applications using the [`Server::middleware`] |
105 | | -//! method. |
106 | | -//! |
107 | | -//! ## State |
108 | | -//! |
109 | | -//! Middleware often needs to share values with the endpoint. This is done through "request scoped |
110 | | -//! state". Request scoped state is built using a typemap that's available through |
111 | | -//! [`Request::ext`]. |
112 | 31 | //! |
113 | | -//! If the endpoint needs to share values with middleware, response scoped state can be set via |
114 | | -//! [`Response::insert_ext`] and is available through [`Response::ext`]. |
115 | | -//! |
116 | | -//! Application scoped state is used when a complete application needs access to a particular |
117 | | -//! value. Examples of this include: database connections, websocket connections, or |
118 | | -//! network-enabled config. Every `Request<State>` has an inner value that must |
119 | | -//! implement `Send + Sync + Clone`, and can thus freely be shared between requests. |
120 | | -//! |
121 | | -//! By default `tide::new` will use `()` as the shared state. But if you want to |
122 | | -//! create a new app with shared state you can use the [`with_state`] function. |
123 | | -//! |
124 | | -//! ## Extension Traits |
125 | | -//! |
126 | | -//! Sometimes having application and request scoped context can require a bit of setup. There are |
127 | | -//! cases where it'd be nice if things were a little easier. This is why Tide |
128 | | -//! encourages people to write _extension traits_. |
129 | | -//! |
130 | | -//! By using an _extension trait_ you can extend [`Request`] or [`Response`] with more |
131 | | -//! functionality. For example, an authentication package could implement a `user` method on |
132 | | -//! `Request`, to access the authenticated user provided by middleware. |
133 | | -//! |
134 | | -//! Extension traits are written by defining a trait + trait impl for the struct that's being |
135 | | -//! extended: |
136 | | -//! |
137 | | -//! ```no_run |
138 | | -//! # use tide::Request; |
139 | | -//! # |
140 | | -//! pub trait RequestExt { |
141 | | -//! fn bark(&self) -> String; |
142 | | -//! } |
143 | | -//! |
144 | | -//! impl<State> RequestExt for Request<State> { |
145 | | -//! fn bark(&self) -> String { |
146 | | -//! "woof".to_string() |
147 | | -//! } |
148 | | -//! } |
149 | | -//! ``` |
150 | | -//! |
151 | | -//! Tide apps will then have access to the `bark` method on `Request`: |
152 | | -//! |
153 | | -//! ```no_run |
154 | | -//! # use tide::Request; |
155 | | -//! # |
156 | | -//! # pub trait RequestExt { |
157 | | -//! # fn bark(&self) -> String; |
158 | | -//! # } |
159 | | -//! # |
160 | | -//! # impl<State> RequestExt for Request<State> { |
161 | | -//! # fn bark(&self) -> String { |
162 | | -//! # "woof".to_string() |
163 | | -//! # } |
164 | | -//! # } |
165 | | -//! # |
166 | 32 | //! #[async_std::main] |
167 | | -//! async fn main() -> Result<(), std::io::Error> { |
| 33 | +//! async fn main() -> tide::Result<()> { |
168 | 34 | //! let mut app = tide::new(); |
169 | | -//! app.at("/").get(|req: Request<()>| async move { Ok(req.bark()) }); |
170 | | -//! app.listen("127.0.0.1:8080").await |
| 35 | +//! app.at("/orders/shoes").post(order_shoes); |
| 36 | +//! app.listen("127.0.0.1:8080").await?; |
| 37 | +//! Ok(()) |
171 | 38 | //! } |
172 | | -//! ``` |
173 | 39 | //! |
174 | | -//! # HTTP Version 1.1 only |
| 40 | +//! async fn order_shoes(mut req: Request<()>) -> tide::Result { |
| 41 | +//! let Animal { name, legs } = req.body_json().await?; |
| 42 | +//! Ok(format!("Hello, {}! I've put in an order for {} shoes", name, legs).into()) |
| 43 | +//! } |
| 44 | +//! ```` |
175 | 45 | //! |
176 | | -//! Tide's default backend currently only supports HTTP/1.1. In order |
177 | | -//! to use nginx as reverse proxy for Tide, your upstream proxy |
178 | | -//! configuration must include this line: |
| 46 | +//! ```sh |
| 47 | +//! $ curl localhost:8000/orders/shoes -d '{ "name": "Chashu", "legs": 4 }' |
| 48 | +//! Hello, Chashu! I've put in an order for 4 shoes |
179 | 49 | //! |
180 | | -//! ```text |
181 | | -//! proxy_http_version 1.1; |
| 50 | +//! $ curl localhost:8000/orders/shoes -d '{ "name": "Mary Millipede", "legs": 750 }' |
| 51 | +//! number too large to fit in target type |
182 | 52 | //! ``` |
183 | | -//! |
184 | | -//! # API Stability |
185 | | -//! |
186 | | -//! It's still early in Tide's development cycle. While the general shape of Tide might have |
187 | | -//! roughly established, the exact traits and function parameters may change between versions. In |
188 | | -//! practice this means that building your core business on Tide is probably not a wise idea... |
189 | | -//! yet. |
190 | | -//! |
191 | | -//! However we *are* committed to closely following semver, and documenting any and all breaking |
192 | | -//! changes we make. Also as time goes on you may find that fewer and fewer changes occur, until we |
193 | | -//! eventually remove this notice entirely. The goal of Tide is to build a premier HTTP experience |
194 | | -//! for Async Rust. We have a long journey ahead of us. But we're excited you're here with us! |
| 53 | +//! See more examples in the [examples](https://github.com/http-rs/tide/tree/main/examples) directory. |
195 | 54 |
|
196 | 55 | #![cfg_attr(feature = "docs", feature(doc_cfg))] |
197 | 56 | // #![warn(missing_docs)] |
|
0 commit comments