1 #![deny(warnings)]
2 
3 use warp::Filter;
4 
5 #[tokio::main]
main()6 async fn main() {
7     pretty_env_logger::init();
8 
9     // We'll start simple, and gradually show how you combine these powers
10     // into super powers!
11 
12     // GET /hi
13     let hi = warp::path("hi").map(|| "Hello, World!");
14 
15     // How about multiple segments? First, we could use the `path!` macro:
16     //
17     // GET /hello/from/warp
18     let hello_from_warp = warp::path!("hello" / "from" / "warp").map(|| "Hello from warp!");
19 
20     // Fine, but how do I handle parameters in paths?
21     //
22     // GET /sum/:u32/:u32
23     let sum = warp::path!("sum" / u32 / u32).map(|a, b| format!("{} + {} = {}", a, b, a + b));
24 
25     // Any type that implements FromStr can be used, and in any order:
26     //
27     // GET /:u16/times/:u16
28     let times =
29         warp::path!(u16 / "times" / u16).map(|a, b| format!("{} times {} = {}", a, b, a * b));
30 
31     // Oh shoot, those math routes should be mounted at a different path,
32     // is that possible? Yep.
33     //
34     // GET /math/sum/:u32/:u32
35     // GET /math/:u16/times/:u16
36     let math = warp::path("math");
37     let _sum = math.and(sum);
38     let _times = math.and(times);
39 
40     // What! And? What's that do?
41     //
42     // It combines the filters in a sort of "this and then that" order. In
43     // fact, it's exactly what the `path!` macro has been doing internally.
44     //
45     // GET /bye/:string
46     let bye = warp::path("bye")
47         .and(warp::path::param())
48         .map(|name: String| format!("Good bye, {}!", name));
49 
50     // Ah, can filters do things besides `and`?
51     //
52     // Why, yes they can! They can also `or`! As you might expect, `or` creates
53     // a "this or else that" chain of filters. If the first doesn't succeed,
54     // then it tries the other.
55     //
56     // So, those `math` routes could have been mounted all as one, with `or`.
57     //
58     // GET /math/sum/:u32/:u32
59     // GET /math/:u16/times/:u16
60     let math = warp::path("math").and(sum.or(times));
61 
62     // We can use the end() filter to match a shorter path
63     let help = warp::path("math")
64         // Careful! Omitting the following line would make this filter match
65         // requests to /math/sum/:u32/:u32 and /math/:u16/times/:u16
66         .and(warp::path::end())
67         .map(|| "This is the Math API. Try calling /math/sum/:u32/:u32 or /math/:u16/times/:u16");
68     let math = help.or(math);
69 
70     // Let's let people know that the `sum` and `times` routes are under `math`.
71     let sum = sum.map(|output| format!("(This route has moved to /math/sum/:u16/:u16) {}", output));
72     let times =
73         times.map(|output| format!("(This route has moved to /math/:u16/times/:u16) {}", output));
74 
75     // It turns out, using `or` is how you combine everything together into
76     // a single API. (We also actually haven't been enforcing the that the
77     // method is GET, so we'll do that too!)
78     //
79     // GET /hi
80     // GET /hello/from/warp
81     // GET /bye/:string
82     // GET /math/sum/:u32/:u32
83     // GET /math/:u16/times/:u16
84 
85     let routes = warp::get().and(hi.or(hello_from_warp).or(bye).or(math).or(sum).or(times));
86 
87     // Note that composing filters for many routes may increase compile times (because it uses a lot of generics).
88     // If you wish to use dynamic dispatch instead and speed up compile times while
89     // making it slightly slower at runtime, you can use Filter::boxed().
90 
91     warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
92 }
93