Skip to main content

cratestack_client_rust/client/
views.rs

1// `get_view` / `list_view` / `list_view_paged` are projection-view
2// reads. The server advertises both `application/cbor` and
3// `application/json` on the model read routes that back these
4// projections (see `model_read_transport_capabilities_tokens` in
5// `cratestack-macros`), so we deliberately do **not** hardcode a
6// JSON content type — the request goes out with the client's
7// configured Accept (`self.codec.accept_header_value()`) and the
8// response is decoded through the same codec into
9// `serde_json::Value`, which `CborCodec` and `JsonCodec` both
10// support. That keeps the projection-view client surface available
11// under either codec configuration; only the `JsonCodec` wrapper
12// type itself is gated on `codec-json`.
13
14use cratestack_core::{Page, ProjectionDecoder};
15use reqwest::Method;
16use serde_json::Value as JsonValue;
17
18use crate::client::core::CratestackClient;
19use crate::client::decode::decode_typed_response;
20use crate::client::helpers::canonical_query_from_selection;
21use crate::codec::HttpClientCodec;
22use crate::error::{ClientError, HeaderPair, QueryPair};
23
24impl<C> CratestackClient<C>
25where
26    C: HttpClientCodec,
27{
28    pub async fn get_view<P>(
29        &self,
30        path: &str,
31        projection: &P,
32        headers: &[HeaderPair<'_>],
33    ) -> Result<P::Output, ClientError>
34    where
35        P: ProjectionDecoder,
36    {
37        let selection = projection.selection_query();
38        let canonical_query = canonical_query_from_selection(&selection, &[])?;
39        let response = self
40            .request_raw_with_query(Method::GET, path, None, canonical_query.as_deref(), headers)
41            .await?;
42        let value: JsonValue = decode_typed_response(&self.codec, &response)?;
43        projection.decode_one(value).map_err(ClientError::from)
44    }
45
46    pub async fn list_view<P>(
47        &self,
48        path: &str,
49        projection: &P,
50        extra_query: &[QueryPair<'_>],
51        headers: &[HeaderPair<'_>],
52    ) -> Result<Vec<P::Output>, ClientError>
53    where
54        P: ProjectionDecoder,
55    {
56        let selection = projection.selection_query();
57        let canonical_query = canonical_query_from_selection(&selection, extra_query)?;
58        let response = self
59            .request_raw_with_query(Method::GET, path, None, canonical_query.as_deref(), headers)
60            .await?;
61        let value: JsonValue = decode_typed_response(&self.codec, &response)?;
62        projection.decode_many(value).map_err(ClientError::from)
63    }
64
65    pub async fn list_view_paged<P>(
66        &self,
67        path: &str,
68        projection: &P,
69        extra_query: &[QueryPair<'_>],
70        headers: &[HeaderPair<'_>],
71    ) -> Result<Page<P::Output>, ClientError>
72    where
73        P: ProjectionDecoder,
74    {
75        let selection = projection.selection_query();
76        let canonical_query = canonical_query_from_selection(&selection, extra_query)?;
77        let response = self
78            .request_raw_with_query(Method::GET, path, None, canonical_query.as_deref(), headers)
79            .await?;
80        let value: JsonValue = decode_typed_response(&self.codec, &response)?;
81        projection.decode_page(value).map_err(ClientError::from)
82    }
83}