conjure_http/server/
conjure.rs

1// Copyright 2024 Palantir Technologies, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Implementations for Conjure-generated endpoints.
16
17use std::{error, iter::FromIterator, marker::PhantomData};
18
19use bytes::Bytes;
20use conjure_error::{Error, InvalidArgument};
21use conjure_object::FromPlain;
22use futures_core::Stream;
23use http::{header::CONTENT_TYPE, HeaderMap, HeaderValue, Response};
24use serde::{de::DeserializeOwned, Serialize};
25
26use crate::private::APPLICATION_OCTET_STREAM;
27
28use super::{
29    AsyncDeserializeRequest, AsyncResponseBody, AsyncSerializeResponse, AsyncWriteBody,
30    ConjureRuntime, DecodeHeader, DecodeParam, DeserializeRequest, EmptyResponseSerializer,
31    LocalAsyncDeserializeRequest, LocalAsyncResponseBody, LocalAsyncSerializeResponse,
32    LocalAsyncWriteBody, ResponseBody, SerializeResponse, StdRequestDeserializer,
33    StdResponseSerializer, WriteBody,
34};
35
36/// A request deserializer for optional body types.
37pub enum OptionalRequestDeserializer {}
38
39impl<T, R> DeserializeRequest<Option<T>, R> for OptionalRequestDeserializer
40where
41    T: DeserializeOwned,
42    R: Iterator<Item = Result<Bytes, Error>>,
43{
44    fn deserialize(
45        runtime: &ConjureRuntime,
46        headers: &HeaderMap,
47        body: R,
48    ) -> Result<Option<T>, Error> {
49        if !headers.contains_key(CONTENT_TYPE) {
50            return Ok(None);
51        }
52
53        <StdRequestDeserializer as DeserializeRequest<_, _>>::deserialize(runtime, headers, body)
54    }
55}
56
57impl<T, R> AsyncDeserializeRequest<Option<T>, R> for OptionalRequestDeserializer
58where
59    T: DeserializeOwned,
60    R: Stream<Item = Result<Bytes, Error>> + Send,
61{
62    async fn deserialize(
63        runtime: &ConjureRuntime,
64        headers: &HeaderMap,
65        body: R,
66    ) -> Result<Option<T>, Error> {
67        if !headers.contains_key(CONTENT_TYPE) {
68            return Ok(None);
69        }
70
71        <StdRequestDeserializer as AsyncDeserializeRequest<_, _>>::deserialize(
72            runtime, headers, body,
73        )
74        .await
75    }
76}
77
78impl<T, R> LocalAsyncDeserializeRequest<Option<T>, R> for OptionalRequestDeserializer
79where
80    T: DeserializeOwned,
81    R: Stream<Item = Result<Bytes, Error>>,
82{
83    async fn deserialize(
84        runtime: &ConjureRuntime,
85        headers: &HeaderMap,
86        body: R,
87    ) -> Result<Option<T>, Error> {
88        if !headers.contains_key(CONTENT_TYPE) {
89            return Ok(None);
90        }
91
92        <StdRequestDeserializer as LocalAsyncDeserializeRequest<_, _>>::deserialize(
93            runtime, headers, body,
94        )
95        .await
96    }
97}
98
99/// A request deserializer for binary body types.
100pub enum BinaryRequestDeserializer {}
101
102impl BinaryRequestDeserializer {
103    fn deserialize_inner<R>(headers: &HeaderMap, body: R) -> Result<R, Error> {
104        if headers.get(CONTENT_TYPE) != Some(&APPLICATION_OCTET_STREAM) {
105            return Err(Error::service_safe(
106                "unexpected Content-Type",
107                InvalidArgument::new(),
108            ));
109        }
110
111        Ok(body)
112    }
113}
114
115impl<R> DeserializeRequest<R, R> for BinaryRequestDeserializer {
116    fn deserialize(_runtime: &ConjureRuntime, headers: &HeaderMap, body: R) -> Result<R, Error> {
117        Self::deserialize_inner(headers, body)
118    }
119}
120
121impl<R> AsyncDeserializeRequest<R, R> for BinaryRequestDeserializer
122where
123    R: Send,
124{
125    async fn deserialize(
126        _runtime: &ConjureRuntime,
127        headers: &HeaderMap,
128        body: R,
129    ) -> Result<R, Error> {
130        Self::deserialize_inner(headers, body)
131    }
132}
133
134impl<R> LocalAsyncDeserializeRequest<R, R> for BinaryRequestDeserializer {
135    async fn deserialize(
136        _runtime: &ConjureRuntime,
137        headers: &HeaderMap,
138        body: R,
139    ) -> Result<R, Error> {
140        Self::deserialize_inner(headers, body)
141    }
142}
143
144/// A body serializer for collection types.
145pub enum CollectionResponseSerializer {}
146
147impl<T, W> SerializeResponse<T, W> for CollectionResponseSerializer
148where
149    T: Serialize + PartialEq + Default,
150{
151    fn serialize(
152        runtime: &ConjureRuntime,
153        request_headers: &HeaderMap,
154        value: T,
155    ) -> Result<Response<ResponseBody<W>>, Error> {
156        if value == T::default() {
157            <EmptyResponseSerializer as SerializeResponse<_, _>>::serialize(
158                runtime,
159                request_headers,
160                (),
161            )
162        } else {
163            <StdResponseSerializer as SerializeResponse<_, _>>::serialize(
164                runtime,
165                request_headers,
166                value,
167            )
168        }
169    }
170}
171
172impl<T, W> AsyncSerializeResponse<T, W> for CollectionResponseSerializer
173where
174    T: Serialize + PartialEq + Default,
175{
176    fn serialize(
177        runtime: &ConjureRuntime,
178        request_headers: &HeaderMap,
179        value: T,
180    ) -> Result<Response<AsyncResponseBody<W>>, Error> {
181        if value == T::default() {
182            <EmptyResponseSerializer as AsyncSerializeResponse<_, _>>::serialize(
183                runtime,
184                request_headers,
185                (),
186            )
187        } else {
188            <StdResponseSerializer as AsyncSerializeResponse<_, _>>::serialize(
189                runtime,
190                request_headers,
191                value,
192            )
193        }
194    }
195}
196
197impl<T, W> LocalAsyncSerializeResponse<T, W> for CollectionResponseSerializer
198where
199    T: Serialize + PartialEq + Default,
200{
201    fn serialize(
202        runtime: &ConjureRuntime,
203        request_headers: &HeaderMap,
204        value: T,
205    ) -> Result<Response<LocalAsyncResponseBody<W>>, Error> {
206        if value == T::default() {
207            <EmptyResponseSerializer as LocalAsyncSerializeResponse<_, _>>::serialize(
208                runtime,
209                request_headers,
210                (),
211            )
212        } else {
213            <StdResponseSerializer as LocalAsyncSerializeResponse<_, _>>::serialize(
214                runtime,
215                request_headers,
216                value,
217            )
218        }
219    }
220}
221
222/// A response serializer for binary types.
223pub enum BinaryResponseSerializer {}
224
225impl BinaryResponseSerializer {
226    fn serialize_inner<B>(body: B) -> Result<Response<B>, Error> {
227        let mut response = Response::new(body);
228
229        response
230            .headers_mut()
231            .insert(CONTENT_TYPE, APPLICATION_OCTET_STREAM);
232        Ok(response)
233    }
234}
235
236impl<T, W> SerializeResponse<T, W> for BinaryResponseSerializer
237where
238    T: WriteBody<W> + 'static,
239{
240    fn serialize(
241        _runtime: &ConjureRuntime,
242        _request_headers: &HeaderMap,
243        value: T,
244    ) -> Result<Response<ResponseBody<W>>, Error> {
245        Self::serialize_inner(ResponseBody::Streaming(Box::new(value)))
246    }
247}
248
249impl<T, W> AsyncSerializeResponse<T, W> for BinaryResponseSerializer
250where
251    T: AsyncWriteBody<W> + 'static + Send,
252{
253    fn serialize(
254        _runtime: &ConjureRuntime,
255        _request_headers: &HeaderMap,
256        value: T,
257    ) -> Result<Response<AsyncResponseBody<W>>, Error> {
258        Self::serialize_inner(AsyncResponseBody::Streaming(super::BoxAsyncWriteBody::new(
259            value,
260        )))
261    }
262}
263
264impl<T, W> LocalAsyncSerializeResponse<T, W> for BinaryResponseSerializer
265where
266    T: LocalAsyncWriteBody<W> + 'static,
267{
268    fn serialize(
269        _runtime: &ConjureRuntime,
270        _request_headers: &HeaderMap,
271        value: T,
272    ) -> Result<Response<LocalAsyncResponseBody<W>>, Error> {
273        Self::serialize_inner(LocalAsyncResponseBody::Streaming(
274            super::BoxLocalAsyncWriteBody::new(value),
275        ))
276    }
277}
278
279/// A response serializer for optional binary types.
280pub enum OptionalBinaryResponseSerializer {}
281
282impl<T, W> SerializeResponse<Option<T>, W> for OptionalBinaryResponseSerializer
283where
284    T: WriteBody<W> + 'static,
285{
286    fn serialize(
287        runtime: &ConjureRuntime,
288        request_headers: &HeaderMap,
289        value: Option<T>,
290    ) -> Result<Response<ResponseBody<W>>, Error> {
291        match value {
292            Some(value) => <BinaryResponseSerializer as SerializeResponse<_, _>>::serialize(
293                runtime,
294                request_headers,
295                value,
296            ),
297            None => <EmptyResponseSerializer as SerializeResponse<_, _>>::serialize(
298                runtime,
299                request_headers,
300                (),
301            ),
302        }
303    }
304}
305
306impl<T, W> AsyncSerializeResponse<Option<T>, W> for OptionalBinaryResponseSerializer
307where
308    T: AsyncWriteBody<W> + 'static + Send,
309{
310    fn serialize(
311        runtime: &ConjureRuntime,
312        request_headers: &HeaderMap,
313        value: Option<T>,
314    ) -> Result<Response<AsyncResponseBody<W>>, Error> {
315        match value {
316            Some(value) => <BinaryResponseSerializer as AsyncSerializeResponse<_, _>>::serialize(
317                runtime,
318                request_headers,
319                value,
320            ),
321            None => <EmptyResponseSerializer as AsyncSerializeResponse<_, _>>::serialize(
322                runtime,
323                request_headers,
324                (),
325            ),
326        }
327    }
328}
329
330impl<T, W> LocalAsyncSerializeResponse<Option<T>, W> for OptionalBinaryResponseSerializer
331where
332    T: LocalAsyncWriteBody<W> + 'static,
333{
334    fn serialize(
335        runtime: &ConjureRuntime,
336        request_headers: &HeaderMap,
337        value: Option<T>,
338    ) -> Result<Response<LocalAsyncResponseBody<W>>, Error> {
339        match value {
340            Some(value) => {
341                <BinaryResponseSerializer as LocalAsyncSerializeResponse<_, _>>::serialize(
342                    runtime,
343                    request_headers,
344                    value,
345                )
346            }
347            None => <EmptyResponseSerializer as LocalAsyncSerializeResponse<_, _>>::serialize(
348                runtime,
349                request_headers,
350                (),
351            ),
352        }
353    }
354}
355
356/// A decoder which converts a single value using its [`FromPlain`] implementation.
357pub enum FromPlainDecoder {}
358
359impl<T> DecodeHeader<T> for FromPlainDecoder
360where
361    T: FromPlain,
362    T::Err: Into<Box<dyn error::Error + Sync + Send>>,
363{
364    fn decode<'a, I>(_: &ConjureRuntime, headers: I) -> Result<T, Error>
365    where
366        I: IntoIterator<Item = &'a HeaderValue>,
367    {
368        T::from_plain(
369            super::only_item(headers)?
370                .to_str()
371                .map_err(|e| Error::service(e, InvalidArgument::new()))?,
372        )
373        .map_err(|e| Error::service(e, InvalidArgument::new()))
374    }
375}
376
377impl<T> DecodeParam<T> for FromPlainDecoder
378where
379    T: FromPlain,
380    T::Err: Into<Box<dyn error::Error + Sync + Send>>,
381{
382    fn decode<I>(_: &ConjureRuntime, params: I) -> Result<T, Error>
383    where
384        I: IntoIterator,
385        I::Item: AsRef<str>,
386    {
387        T::from_plain(super::only_item(params)?.as_ref())
388            .map_err(|e| Error::service(e, InvalidArgument::new()))
389    }
390}
391
392/// A decoder which converts an optional value using its [`FromPlain`] implementation.
393pub enum FromPlainOptionDecoder {}
394
395impl<T> DecodeHeader<Option<T>> for FromPlainOptionDecoder
396where
397    T: FromPlain,
398    T::Err: Into<Box<dyn error::Error + Sync + Send>>,
399{
400    fn decode<'a, I>(_: &ConjureRuntime, headers: I) -> Result<Option<T>, Error>
401    where
402        I: IntoIterator<Item = &'a HeaderValue>,
403    {
404        let Some(header) = super::optional_item(headers)? else {
405            return Ok(None);
406        };
407        let value = T::from_plain(
408            header
409                .to_str()
410                .map_err(|e| Error::service(e, InvalidArgument::new()))?,
411        )
412        .map_err(|e| Error::service(e, InvalidArgument::new()))?;
413        Ok(Some(value))
414    }
415}
416
417impl<T> DecodeParam<Option<T>> for FromPlainOptionDecoder
418where
419    T: FromPlain,
420    T::Err: Into<Box<dyn error::Error + Sync + Send>>,
421{
422    fn decode<I>(_: &ConjureRuntime, params: I) -> Result<Option<T>, Error>
423    where
424        I: IntoIterator,
425        I::Item: AsRef<str>,
426    {
427        let Some(param) = super::optional_item(params)? else {
428            return Ok(None);
429        };
430        let value =
431            T::from_plain(param.as_ref()).map_err(|e| Error::service(e, InvalidArgument::new()))?;
432        Ok(Some(value))
433    }
434}
435
436/// A decoder which converts a sequence of values via its [`FromPlain`] implementation into a
437/// collection via a [`FromIterator`] implementation.
438pub struct FromPlainSeqDecoder<U> {
439    _p: PhantomData<U>,
440}
441
442impl<T, U> DecodeParam<T> for FromPlainSeqDecoder<U>
443where
444    T: FromIterator<U>,
445    U: FromPlain,
446    U::Err: Into<Box<dyn error::Error + Sync + Send>>,
447{
448    fn decode<I>(_: &ConjureRuntime, params: I) -> Result<T, Error>
449    where
450        I: IntoIterator,
451        I::Item: AsRef<str>,
452    {
453        params
454            .into_iter()
455            .map(|s| {
456                U::from_plain(s.as_ref()).map_err(|e| Error::service(e, InvalidArgument::new()))
457            })
458            .collect()
459    }
460}