|
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 async web applications and APIs 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 receives a JSON body, 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