hive_router_plan_executor/plugins/hooks/on_http_request.rs
1use ntex::{
2 http::Response,
3 web::{self, DefaultError, WebRequest},
4};
5
6use crate::{
7 plugin_context::PluginContext,
8 plugin_trait::{EndHookPayload, EndHookResult, StartHookPayload, StartHookResult},
9};
10
11pub struct OnHttpRequestHookPayload<'req> {
12 /// The raw incoming HTTP request to the router
13 /// It includes all the details of the request such as headers, body, etc.
14 ///
15 /// Example:
16 /// ```
17 /// use hive_router::{
18 /// plugins::hooks::on_http_request::{OnHttpRequestHookPayload, OnHttpRequestHookResult},
19 /// };
20 ///
21 /// fn on_http_request<'req>(mut payload: OnHttpRequestHookPayload<'req>) -> OnHttpRequestHookResult<'req> {
22 /// let my_header = payload.router_http_request.headers().get("my-header");
23 /// // do something with the header...
24 /// payload.proceed()
25 /// }
26 /// ```
27 pub router_http_request: WebRequest<DefaultError>,
28 /// The context object that can be used to share data across different plugin hooks for the same request.
29 /// It is unique per request and is dropped after the response is sent.
30 ///
31 /// [Learn more about the context data sharing in the docs](https://the-guild.dev/graphql/hive/docs/router/extensibility/plugin_system#context-data-sharing)
32 ///
33 /// Example:
34 /// ```
35 /// use hive_router::{
36 /// plugins::hooks::{
37 /// on_http_request::{OnHttpRequestHookPayload, OnHttpRequestHookResult},
38 /// on_execute::{OnExecuteStartHookPayload, OnExecuteStartHookResult}
39 /// },
40 /// plugin_context::PluginContext,
41 /// async_trait::async_trait,
42 /// };
43 ///
44 /// struct ContextData {
45 /// greetings: String
46 /// }
47 ///
48 /// #[async_trait]
49 /// impl RouterPlugin for MyPlugin {
50 /// fn on_http_request<'req>(mut payload: OnHttpRequestHookPayload<'req>) -> OnHttpRequestHookResult<'req> {
51 /// let context_data = ContextData {
52 /// greetings: "Hello from context!".to_string()
53 /// };
54 ///
55 /// payload.context.insert(context_data);
56 ///
57 /// payload.proceed()
58 /// }
59 ///
60 /// async fn on_execute<'exec>(&'exec self, payload: OnExecuteStartHookPayload<'exec>) -> OnExecuteStartHookResult<'exec> {
61 /// let context_data = payload.context.get::<ContextData>().unwrap();
62 /// println!("{}", context_data.greetings); // prints "Hello from context!"
63 /// payload.proceed()
64 /// }
65 /// }
66 /// ```
67 pub context: &'req PluginContext,
68}
69
70impl<'req> StartHookPayload<OnHttpResponseHookPayload<'req>, Response>
71 for OnHttpRequestHookPayload<'req>
72{
73}
74
75pub type OnHttpRequestHookResult<'req> = StartHookResult<
76 'req,
77 OnHttpRequestHookPayload<'req>,
78 OnHttpResponseHookPayload<'req>,
79 Response,
80>;
81
82pub struct OnHttpResponseHookPayload<'req> {
83 pub response: web::WebResponse,
84 pub context: &'req PluginContext,
85}
86
87impl<'req> OnHttpResponseHookPayload<'req> {
88 /// Manipulate the outgoing HTTP response before it's sent to the client.
89 /// This can be used to modify headers, change the body, etc.
90 ///
91 /// Example:
92 /// ```
93 /// fn on_http_request<'req>(
94 /// &'req self,
95 /// payload: OnHttpRequestHookPayload<'req>,
96 /// ) -> OnHttpRequestHookResult<'req> {
97 /// payload.on_end(|payload| {
98 /// payload.map_response(|mut response| {
99 /// response.response_mut().headers_mut().insert(
100 /// "x-served-by",
101 /// "hive-router".parse().unwrap(),
102 /// );
103 /// response
104 /// }).proceed()
105 /// })
106 /// }
107 /// ```
108 pub fn map_response<F>(mut self, f: F) -> Self
109 where
110 F: FnOnce(web::WebResponse) -> web::WebResponse,
111 {
112 self.response = f(self.response);
113 self
114 }
115}
116
117impl<'req> EndHookPayload<Response> for OnHttpResponseHookPayload<'req> {}
118
119pub type OnHttpResponseHookResult<'req> = EndHookResult<OnHttpResponseHookPayload<'req>, Response>;