thegraph_headers/graph_indexed.rs
1//! An HTTP _typed header_ for the `graph-indexed` header.
2//!
3//! The `graph-indexed` header contains a JSON-encoded [`BlockInfo`] struct indicating the latest
4//! indexed block information.
5//!
6//! # Using the `headers::HeaderMapExt` extension trait
7//!
8//! ```rust
9//! use headers::HeaderMapExt as _;
10//! use thegraph_headers::graph_indexed::{GraphIndexed, HEADER_NAME};
11//!
12//! let mut header_map = http::HeaderMap::new();
13//! # let value = thegraph_headers::graph_indexed::BlockInfo {
14//! # hash: thegraph_core::alloy::primitives::BlockHash::new([0x55; 32]),
15//! # number: 42,
16//! # timestamp: None,
17//! # };
18//!
19//! // Insert a `graph-indexed` HTTP header
20//! header_map.typed_insert(GraphIndexed(value));
21//!
22//! // Get the `graph-indexed` HTTP header by name
23//! let header_by_name = header_map.get(HEADER_NAME);
24//! assert!(header_by_name.is_some());
25//!
26//! // Get the `graph-indexed` HTTP header by type
27//! let header_typed = header_map.typed_get::<GraphIndexed>();
28//! assert!(matches!(header_typed, Some(GraphIndexed(..))));
29//! ```
30
31use headers::{Error as HeaderError, Header, HeaderName, HeaderValue};
32use thegraph_core::alloy::primitives::{BlockHash, BlockNumber};
33
34/// The HTTP header name for the `graph-indexed` header.
35pub const HEADER_NAME: &str = "graph-indexed";
36
37/// An HTTP _typed header_ for the `graph-indexed` header.
38///
39/// The `graph-indexed` header contains a JSON-encoded [`BlockInfo`] struct indicating the latest
40/// indexed block information.
41pub struct GraphIndexed(pub BlockInfo);
42
43impl Header for GraphIndexed {
44 fn name() -> &'static HeaderName {
45 static HTTP_HEADER_NAME: HeaderName = HeaderName::from_static(HEADER_NAME);
46 &HTTP_HEADER_NAME
47 }
48
49 fn decode<'i, I>(values: &mut I) -> Result<Self, HeaderError>
50 where
51 Self: Sized,
52 I: Iterator<Item = &'i HeaderValue>,
53 {
54 let value = values.next().ok_or_else(HeaderError::invalid)?;
55 let info = serde_json::from_slice::<'_, BlockInfo>(value.as_bytes())
56 .map_err(|_| HeaderError::invalid())?;
57 Ok(Self(info))
58 }
59
60 fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
61 let bytes = serde_json::to_vec(&self.0).expect("header to be valid json");
62 let value = HeaderValue::from_bytes(&bytes).expect("header to be valid utf-8");
63 values.extend(std::iter::once(value));
64 }
65}
66
67/// A struct containing information about the latest block.
68///
69/// Type ported from the Graph Node.
70///
71/// See Graph Node's [`LatestBlockInfo`][1].
72///
73/// [1]: https://github.com/graphprotocol/graph-node/blob/a8b590f7d3fbabf2968ce7ced30bfd1485ce5f31/graph/src/data/query/result.rs#L68-L74
74#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
75pub struct BlockInfo {
76 /// The hash of the latest block.
77 pub hash: BlockHash,
78 /// The number of the latest block.
79 pub number: BlockNumber,
80 /// The timestamp of the latest block.
81 #[serde(skip_serializing_if = "Option::is_none")]
82 pub timestamp: Option<u64>,
83}