conjure-http 5.11.0

HTTP interfaces for generated Conjure services
Documentation
use crate::server::{
    AsyncDeserializeRequest, AsyncResponseBody, AsyncSerializeResponse, ConjureRuntime,
    DecodeHeader, DecodeParam, DeserializeRequest, LocalAsyncDeserializeRequest,
    LocalAsyncResponseBody, LocalAsyncSerializeResponse, ResponseBody, SerializeResponse,
};
use crate::PathParams;
use conjure_error::{Error, PermissionDenied};
use conjure_object::BearerToken;
use http::header::{HeaderName, AUTHORIZATION, COOKIE};
use http::{request, HeaderMap, Response};
use std::borrow::Cow;
use std::collections::HashMap;

pub const SERIALIZABLE_REQUEST_SIZE_LIMIT: usize = 50 * 1024 * 1024;

pub fn path_param<T, D>(
    runtime: &ConjureRuntime,
    parts: &request::Parts,
    param: &str,
    log_as: &str,
) -> Result<T, Error>
where
    D: DecodeParam<T>,
{
    let path_params = parts
        .extensions
        .get::<PathParams>()
        .expect("PathParams missing from request");
    let value = &path_params[param];
    let params = value
        .split('/')
        .map(percent_encoding::percent_decode_str)
        .map(|v| v.decode_utf8_lossy());
    D::decode(runtime, params).map_err(|e| e.with_safe_param("param", log_as))
}

pub fn parse_query_params(parts: &request::Parts) -> HashMap<Cow<'_, str>, Vec<Cow<'_, str>>> {
    let query = match parts.uri.query() {
        Some(query) => query,
        None => return HashMap::new(),
    };

    let mut map = HashMap::new();
    for (key, value) in form_urlencoded::parse(query.as_bytes()) {
        map.entry(key).or_insert_with(Vec::new).push(value);
    }

    map
}

pub fn query_param<T, D>(
    runtime: &ConjureRuntime,
    query_params: &HashMap<Cow<'_, str>, Vec<Cow<'_, str>>>,
    key: &str,
    log_as: &str,
) -> Result<T, Error>
where
    D: DecodeParam<T>,
{
    let values = query_params.get(key).into_iter().flatten();
    D::decode(runtime, values).map_err(|e| e.with_safe_param("param", log_as))
}

pub fn header_param<T, D>(
    runtime: &ConjureRuntime,
    parts: &request::Parts,
    header: &str,
    log_as: &str,
) -> Result<T, Error>
where
    D: DecodeHeader<T>,
{
    D::decode(runtime, parts.headers.get_all(header))
        .map_err(|e| e.with_safe_param("param", log_as))
}

pub fn parse_cookie_auth(parts: &request::Parts, prefix: &str) -> Result<BearerToken, Error> {
    parse_auth_inner(parts, prefix, COOKIE)
}

pub fn parse_header_auth(parts: &request::Parts) -> Result<BearerToken, Error> {
    parse_auth_inner(parts, "Bearer ", AUTHORIZATION)
}

fn parse_auth_inner(
    parts: &request::Parts,
    prefix: &str,
    header: HeaderName,
) -> Result<BearerToken, Error> {
    let header = match parts.headers.get(header) {
        Some(header) => header,
        None => {
            return Err(Error::service_safe(
                "required auth header missing",
                PermissionDenied::new(),
            ));
        }
    };

    let header = header
        .to_str()
        .map_err(|e| Error::service_safe(e, PermissionDenied::new()))?;

    let value = header.strip_prefix(prefix).ok_or_else(|| {
        Error::service_safe("invalid auth header format", PermissionDenied::new())
    })?;

    value
        .parse()
        .map_err(|e| Error::service_safe(e, PermissionDenied::new()))
}

pub fn body_arg<D, T, I>(
    runtime: &ConjureRuntime,
    headers: &HeaderMap,
    body: I,
    log_as: &str,
) -> Result<T, Error>
where
    D: DeserializeRequest<T, I>,
{
    D::deserialize(runtime, headers, body).map_err(|e| e.with_safe_param("param", log_as))
}

pub async fn async_body_arg<D, T, I>(
    runtime: &ConjureRuntime,
    headers: &HeaderMap,
    body: I,
    log_as: &str,
) -> Result<T, Error>
where
    D: AsyncDeserializeRequest<T, I>,
{
    D::deserialize(runtime, headers, body)
        .await
        .map_err(|e| e.with_safe_param("param", log_as))
}

pub async fn local_async_body_arg<D, T, I>(
    runtime: &ConjureRuntime,
    headers: &HeaderMap,
    body: I,
    log_as: &str,
) -> Result<T, Error>
where
    D: LocalAsyncDeserializeRequest<T, I>,
{
    D::deserialize(runtime, headers, body)
        .await
        .map_err(|e| e.with_safe_param("param", log_as))
}

pub fn response<S, T, W>(
    runtime: &ConjureRuntime,
    request_headers: &HeaderMap,
    value: T,
) -> Result<Response<ResponseBody<W>>, Error>
where
    S: SerializeResponse<T, W>,
{
    S::serialize(runtime, request_headers, value)
}

pub fn async_response<S, T, W>(
    runtime: &ConjureRuntime,
    request_headers: &HeaderMap,
    value: T,
) -> Result<Response<AsyncResponseBody<W>>, Error>
where
    S: AsyncSerializeResponse<T, W>,
{
    S::serialize(runtime, request_headers, value)
}

pub fn local_async_response<S, T, W>(
    runtime: &ConjureRuntime,
    request_headers: &HeaderMap,
    value: T,
) -> Result<Response<LocalAsyncResponseBody<W>>, Error>
where
    S: LocalAsyncSerializeResponse<T, W>,
{
    S::serialize(runtime, request_headers, value)
}