Skip to main content

topcoat_openapi/
parameter.rs

1use std::borrow::Cow;
2
3use schemars::{JsonSchema, SchemaGenerator};
4use serde::Serialize;
5
6use crate::content::SchemaFn;
7
8/// A single request parameter: a path segment, a query key, a header, or a
9/// cookie.
10///
11/// Pass it to [`Operation::parameter`](crate::Operation::parameter). The
12/// value is documented as a string unless [`schema`](Self::schema) names
13/// another type:
14///
15/// ```
16/// use topcoat::openapi::{Operation, Parameter};
17///
18/// let operation = Operation::new().parameter(
19///     Parameter::path("post_id")
20///         .schema::<u64>()
21///         .description("The post to load."),
22/// );
23/// ```
24///
25/// Path parameters are documented even without an entry, because they are
26/// part of the route's path. Add one to describe the parameter or to give
27/// it a type.
28#[derive(Debug, Clone)]
29pub struct Parameter {
30    pub(crate) location: ParameterLocation,
31    pub(crate) name: Cow<'static, str>,
32    pub(crate) description: Option<Cow<'static, str>>,
33    pub(crate) required: bool,
34    pub(crate) schema: Option<SchemaFn>,
35}
36
37impl Parameter {
38    /// Creates a parameter at `location` that is not required.
39    fn new(location: ParameterLocation, name: impl Into<Cow<'static, str>>) -> Self {
40        Self {
41            location,
42            name: name.into(),
43            description: None,
44            required: false,
45            schema: None,
46        }
47    }
48
49    /// Describes the path parameter `name`, written `{name}` in the route's
50    /// path. A path parameter is always required.
51    #[must_use]
52    pub fn path(name: impl Into<Cow<'static, str>>) -> Self {
53        Self::new(ParameterLocation::Path, name)
54    }
55
56    /// Describes the query string key `name`.
57    #[must_use]
58    pub fn query(name: impl Into<Cow<'static, str>>) -> Self {
59        Self::new(ParameterLocation::Query, name)
60    }
61
62    /// Describes the request header `name`.
63    #[must_use]
64    pub fn header(name: impl Into<Cow<'static, str>>) -> Self {
65        Self::new(ParameterLocation::Header, name)
66    }
67
68    /// Describes the cookie `name`.
69    #[must_use]
70    pub fn cookie(name: impl Into<Cow<'static, str>>) -> Self {
71        Self::new(ParameterLocation::Cookie, name)
72    }
73
74    /// Explains what the parameter is for.
75    #[must_use]
76    pub fn description(mut self, description: impl Into<Cow<'static, str>>) -> Self {
77        self.description = Some(description.into());
78        self
79    }
80
81    /// Chooses whether a request has to send the parameter. Parameters are
82    /// optional by default, except path parameters, which are always
83    /// required.
84    #[must_use]
85    pub fn required(mut self, required: bool) -> Self {
86        self.required = required;
87        self
88    }
89
90    /// Documents the parameter's value with the schema of `T`, for example
91    /// `.schema::<u64>()` for a numeric ID.
92    #[must_use]
93    pub fn schema<T: JsonSchema>(mut self) -> Self {
94        let schema: SchemaFn = SchemaGenerator::subschema_for::<T>;
95        self.schema = Some(schema);
96        self
97    }
98
99    /// Returns whether `other` describes the same parameter of a request.
100    pub(crate) fn same_as(&self, other: &Parameter) -> bool {
101        self.location == other.location && self.name == other.name
102    }
103}
104
105/// The part of a request that carries a parameter.
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
107#[serde(rename_all = "lowercase")]
108pub(crate) enum ParameterLocation {
109    Path,
110    Query,
111    Header,
112    Cookie,
113}