Repository: juhaku/utoipa
Pull request #48 (2022-03-27 21:36:25)

Chore schema and path builders
* Add schema related builders
* Add paths related builders
* Fix tests and update docs


Patch:
diff --git a/src/lib.rs b/src/lib.rs
index 9edaf1f..b9ea246 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -249,26 +249,28 @@ pub trait OpenApi {
 /// impl utoipa::Component for Pet {
 ///     fn component() -> utoipa::openapi::schema::Component {
 ///         use utoipa::openapi::ToArray;
-///         utoipa::openapi::Object::new()
-///             .with_property(
+///         utoipa::openapi::ObjectBuilder::new()
+///             .property(
 ///                 "id",
-///                 utoipa::openapi::Property::new(utoipa::openapi::ComponentType::Integer)
-///                     .with_format(utoipa::openapi::ComponentFormat::Int64),
+///                 utoipa::openapi::PropertyBuilder::new()
+///                     .component_type(utoipa::openapi::ComponentType::Integer)
+///                     .format(Some(utoipa::openapi::ComponentFormat::Int64)),
 ///             )
-///             .with_required("id")
-///             .with_property(
+///             .required("id")
+///             .property(
 ///                 "name",
 ///                 utoipa::openapi::Property::new(utoipa::openapi::ComponentType::String),
 ///             )
-///             .with_required("name")
-///             .with_property(
+///             .required("name")
+///             .property(
 ///                 "age",
-///                 utoipa::openapi::Property::new(utoipa::openapi::ComponentType::Integer)
-///                     .with_format(utoipa::openapi::ComponentFormat::Int32),
+///                 utoipa::openapi::PropertyBuilder::new()
+///                     .component_type(utoipa::openapi::ComponentType::Integer)
+///                     .format(Some(utoipa::openapi::ComponentFormat::Int32)),
 ///             )
-///             .with_example(serde_json::json!({
-///               "name":"bob the cat","id":1
-///             }))
+///             .example(Some(serde_json::json!({
+///               "name": "bob the cat", "id": 1
+///             })))
 ///             .into()
 ///     }
 /// }
@@ -316,12 +318,12 @@ pub trait Component {
 ///
 /// Example of what would manual implementation roughly look like of above `#[utoipa::path(...)]` macro.
 /// ```rust
-/// utoipa::openapi::Paths::new().append(
+/// utoipa::openapi::PathsBuilder::new().path(
 ///         "/pets/{id}",
 ///         utoipa::openapi::PathItem::new(
 ///             utoipa::openapi::PathItemType::Get,
-///             utoipa::openapi::path::Operation::new()
-///                 .with_responses(
+///             utoipa::openapi::path::OperationBuilder::new()
+///                 .responses(
 ///                     utoipa::openapi::ResponsesBuilder::new()
 ///                         .response(
 ///                             "200",
@@ -331,26 +333,28 @@ pub trait Component {
 ///                                     utoipa::openapi::Content::new(
 ///                                         utoipa::openapi::Ref::from_component_name("Pet"),
 ///                                     ),
-///                             ).build(),
+///                             ),
 ///                         )
-///                         .response("404", utoipa::openapi::Response::new("Pet was not found")).build(),
+///                         .response("404", utoipa::openapi::Response::new("Pet was not found")),
 ///                 )
-///                 .with_operation_id("get_pet_by_id")
-///                 .with_deprecated(utoipa::openapi::Deprecated::False)
-///                 .with_summary("Get pet by id")
-///                 .with_description("Get pet by id\n\nGet pet from database by pet database id\n")
-///                 .with_parameter(
-///                     utoipa::openapi::path::Parameter::new("id")
-///                         .with_in(utoipa::openapi::path::ParameterIn::Path)
-///                         .with_deprecated(utoipa::openapi::Deprecated::False)
-///                         .with_description("Pet database id to get Pet for")
-///                         .with_schema(
-///                             utoipa::openapi::Property::new(utoipa::openapi::ComponentType::Integer)
-///                                 .with_format(utoipa::openapi::ComponentFormat::Int64),
-///                         )
-///                         .with_required(utoipa::openapi::Required::True),
+///                 .operation_id(Some("get_pet_by_id"))
+///                 .deprecated(Some(utoipa::openapi::Deprecated::False))
+///                 .summary(Some("Get pet by id"))
+///                 .description(Some("Get pet by id\n\nGet pet from database by pet database id\n"))
+///                 .parameter(
+///                     utoipa::openapi::path::ParameterBuilder::new()
+///                         .name("id")
+///                         .parameter_in(utoipa::openapi::path::ParameterIn::Path)
+///                         .required(utoipa::openapi::Required::True)
+///                         .deprecated(Some(utoipa::openapi::Deprecated::False))
+///                         .description(Some("Pet database id to get Pet for"))
+///                         .schema(
+///                             Some(utoipa::openapi::PropertyBuilder::new()
+///                                 .component_type(utoipa::openapi::ComponentType::Integer)
+///                                 .format(Some(utoipa::openapi::ComponentFormat::Int64))),
+///                         ),
 ///                 )
-///                 .with_tag("pet_api"),
+///                 .tag("pet_api"),
 ///         ),
 ///     );
 /// ```
diff --git a/src/openapi.rs b/src/openapi.rs
index d8b17cc..78cd04a 100644
--- a/src/openapi.rs
+++ b/src/openapi.rs
@@ -1,5 +1,3 @@
-use std::collections::BTreeMap;
-
 use serde::{de::Visitor, Deserialize, Serialize, Serializer};
 
 pub use self::{
@@ -7,11 +5,12 @@ pub use self::{
     external_docs::ExternalDocs,
     header::{Header, HeaderBuilder},
     info::{Contact, ContactBuilder, Info, InfoBuilder, License, LicenseBuilder},
-    path::{PathItem, PathItemType, Paths},
+    path::{PathItem, PathItemType, Paths, PathsBuilder},
     response::{Response, ResponseBuilder, Responses, ResponsesBuilder},
     schema::{
-        Array, Component, ComponentFormat, ComponentType, Components, Object, OneOf, Property, Ref,
-        ToArray,
+        Array, ArrayBuilder, Component, ComponentFormat, ComponentType, Components,
+        ComponentsBuilder, Object, ObjectBuilder, OneOf, OneOfBuilder, Property, PropertyBuilder,
+        Ref, ToArray,
     },
     security::SecurityRequirement,
     server::Server,
@@ -79,7 +78,8 @@ builder! {
         /// Available paths and operations for the API.
         ///
         /// See more details at <https://spec.openapis.org/oas/latest.html#paths-object>.
-        pub paths: BTreeMap<String, PathItem>,
+        #[serde(flatten)]
+        pub paths: Paths,
 
         /// Holds various reusable schemas for the OpenAPI document.
         ///
@@ -124,10 +124,10 @@ impl OpenApi {
     /// #
     /// let openapi = OpenApi::new(Info::new("pet api", "0.1.0"), Paths::new());
     /// ```
-    pub fn new(info: Info, paths: Paths) -> Self {
+    pub fn new<P: Into<Paths>>(info: Info, paths: P) -> Self {
         Self {
             info,
-            paths: paths.to_map(),
+            paths: paths.into(),
             ..Default::default()
         }
     }
@@ -152,22 +152,22 @@ impl OpenApi {
 impl OpenApiBuilder {
     /// Add [`Info`] metadata of the API.
     pub fn info(mut self, info: Info) -> Self {
-        add_value!(self info info)
+        set_value!(self info info)
     }
 
     /// Add iterator of [`Server`]s to configure target servers.
     pub fn servers<I: IntoIterator<Item = Server>>(mut self, servers: Option<I>) -> Self {
-        add_value!(self servers servers.map(|servers| servers.into_iter().collect()))
+        set_value!(self servers servers.map(|servers| servers.into_iter().collect()))
     }
 
     /// Add [`Paths`] to configure operations and endpoints of the API.
-    pub fn paths(mut self, paths: Paths) -> Self {
-        add_value!(self paths paths.to_map())
+    pub fn paths<P: Into<Paths>>(mut self, paths: P) -> Self {
+        set_value!(self paths paths.into())
     }
 
     /// Add [`Components`] to configure reusable schemas.
     pub fn components(mut self, components: Option<Components>) -> Self {
-        add_value!(self components components)
+        set_value!(self components components)
     }
 
     /// Add iterator of [`SecurityRequirement`]s that are globally available for all operations.
@@ -175,17 +175,17 @@ impl OpenApiBuilder {
         mut self,
         security: Option<I>,
     ) -> Self {
-        add_value!(self security security.map(|security| security.into_iter().collect()))
+        set_value!(self security security.map(|security| security.into_iter().collect()))
     }
 
     /// Add iterator of [`Tag`]s to add additional documentation for **operations** tags.
     pub fn tags<I: IntoIterator<Item = Tag>>(mut self, tags: Option<I>) -> Self {
-        add_value!(self tags tags.map(|tags| tags.into_iter().collect()))
+        set_value!(self tags tags.map(|tags| tags.into_iter().collect()))
     }
 
     /// Add [`ExternalDocs`] for refering additional documentation.
     pub fn external_docs(mut self, external_docs: Option<ExternalDocs>) -> Self {
-        add_value!(self external_docs external_docs)
+        set_value!(self external_docs external_docs)
     }
 }
 
@@ -318,21 +318,20 @@ macro_rules! build_fn {
                 $(
                     $field: self.$field,
                 )*
-                ..Default::default()
             }
         }
     };
 }
 pub(crate) use build_fn;
 
-macro_rules! add_value {
+macro_rules! set_value {
     ( $self:ident $field:ident $value:expr ) => {{
         $self.$field = $value;
 
         $self
     }};
 }
-pub(crate) use add_value;
+pub(crate) use set_value;
 
 macro_rules! new {
     ( $vis:vis $name:ident ) => {
@@ -406,7 +405,10 @@ pub(crate) use builder;
 #[cfg(test)]
 #[cfg(feature = "serde_json")]
 mod tests {
-    use crate::openapi::info::InfoBuilder;
+    use crate::openapi::{
+        info::InfoBuilder,
+        path::{OperationBuilder, PathsBuilder},
+    };
 
     use super::{path::Operation, response::Response, *};
 
@@ -447,26 +449,26 @@ mod tests {
     fn serialize_openapi_json_with_paths_success() -> Result<(), serde_json::Error> {
         let openapi = OpenApi::new(
             Info::new("My big api", "1.1.0"),
-            Paths::new()
-                .append(
+            PathsBuilder::new()
+                .path(
                     "/api/v1/users",
                     PathItem::new(
                         PathItemType::Get,
-                        Operation::new().with_response("200", Response::new("Get users list")),
+                        OperationBuilder::new().response("200", Response::new("Get users list")),
                     ),
                 )
-                .append(
+                .path(
                     "/api/v1/users",
                     PathItem::new(
                         PathItemType::Post,
-                        Operation::new().with_response("200", Response::new("Post new user")),
+                        OperationBuilder::new().response("200", Response::new("Post new user")),
                     ),
                 )
-                .append(
+                .path(
                     "/api/v1/users/{id}",
                     PathItem::new(
                         PathItemType::Get,
-                        Operation::new().with_response("200", Response::new("Get user by id")),
+                        OperationBuilder::new().response("200", Response::new("Get user by id")),
                     ),
                 ),
         );
diff --git a/src/openapi/content.rs b/src/openapi/content.rs
index 153d92f..f511356 100644
--- a/src/openapi/content.rs
+++ b/src/openapi/content.rs
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
 #[cfg(feature = "serde_json")]
 use serde_json::Value;
 
-use super::{add_value, build_fn, from, new, Component};
+use super::{build_fn, from, new, set_value, Component};
 
 /// Content holds request body content or response content.
 #[derive(Serialize, Deserialize, Default, Clone)]
@@ -53,19 +53,19 @@ impl ContentBuilder {
 
     /// Add schema.
     pub fn schema<I: Into<Component>>(mut self, component: I) -> Self {
-        add_value!(self schema component.into())
+        set_value!(self schema component.into())
     }
 
     /// Add example of schema.
     #[cfg(feature = "serde_json")]
     pub fn example(mut self, example: Option<Value>) -> Self {
-        add_value!(self example example)
+        set_value!(self example example)
     }
 
     /// Add example of schema.
     #[cfg(not(feature = "serde_json"))]
     pub fn example<S: Into<String>>(mut self, example: Option<S>) -> Self {
-        add_value!(self example example.map(|example| example.into()))
+        set_value!(self example example.map(|example| example.into()))
     }
 
     build_fn!(pub Content schema, example);
diff --git a/src/openapi/external_docs.rs b/src/openapi/external_docs.rs
index d10a18c..73d325c 100644
--- a/src/openapi/external_docs.rs
+++ b/src/openapi/external_docs.rs
@@ -3,7 +3,7 @@
 //! [external_docs]: https://spec.openapis.org/oas/latest.html#xml-object
 use serde::{Deserialize, Serialize};
 
-use super::{add_value, build_fn, builder, from, new};
+use super::{build_fn, builder, from, new, set_value};
 
 builder! {
     ExternalDocsBuilder;
@@ -43,11 +43,11 @@ impl ExternalDocs {
 impl ExternalDocsBuilder {
     /// Add target url for external documentation location.
     pub fn url<I: Into<String>>(mut self, url: I) -> Self {
-        add_value!(self url url.into())
+        set_value!(self url url.into())
     }
 
     /// Add additional description of external documentation.
     pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
-        add_value!(self description description.map(|description| description.into()))
+        set_value!(self description description.map(|description| description.into()))
     }
 }
diff --git a/src/openapi/header.rs b/src/openapi/header.rs
index 5c101e0..0100def 100644
--- a/src/openapi/header.rs
+++ b/src/openapi/header.rs
@@ -4,7 +4,7 @@
 
 use serde::{Deserialize, Serialize};
 
-use super::{add_value, build_fn, builder, from, new, Component, ComponentType, Property};
+use super::{build_fn, builder, from, new, set_value, Component, ComponentType, Property};
 
 builder! {
     HeaderBuilder;
@@ -64,11 +64,11 @@ impl Default for Header {
 impl HeaderBuilder {
     /// Add schema of header.
     pub fn schema<I: Into<Component>>(mut self, component: I) -> Self {
-        add_value!(self schema component.into())
+        set_value!(self schema component.into())
     }
 
     /// Add additional description for header.
     pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
-        add_value!(self description description.map(|description| description.into()))
+        set_value!(self description description.map(|description| description.into()))
     }
 }
diff --git a/src/openapi/info.rs b/src/openapi/info.rs
index d61989d..b3d5a5a 100644
--- a/src/openapi/info.rs
+++ b/src/openapi/info.rs
@@ -8,7 +8,7 @@
 //! [derive]: ../../derive.OpenApi.html
 use serde::{Deserialize, Serialize};
 
-use super::{add_value, build_fn, builder, from, new};
+use super::{build_fn, builder, from, new, set_value};
 
 builder! {
     /// # Examples
@@ -93,32 +93,32 @@ impl Info {
 impl InfoBuilder {
     /// Add title of the API.
     pub fn title<I: Into<String>>(mut self, title: I) -> Self {
-        add_value!(self title title.into())
+        set_value!(self title title.into())
     }
 
     /// Add version of the api document typically the API version.
     pub fn version<I: Into<String>>(mut self, version: I) -> Self {
-        add_value!(self version version.into())
+        set_value!(self version version.into())
     }
 
     /// Add description of the API.
     pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
-        add_value!(self description description.map(|description| description.into()))
+        set_value!(self description description.map(|description| description.into()))
     }
 
     /// Add url for terms of the API.
     pub fn terms_of_service<S: Into<String>>(mut self, terms_of_service: Option<S>) -> Self {
-        add_value!(self terms_of_service terms_of_service.map(|terms_of_service| terms_of_service.into()))
+        set_value!(self terms_of_service terms_of_service.map(|terms_of_service| terms_of_service.into()))
     }
 
     /// Add contact information of the API.
     pub fn contact(mut self, contact: Option<Contact>) -> Self {
-        add_value!(self contact contact)
+        set_value!(self contact contact)
     }
 
     /// Add licence of the API.
     pub fn license(mut self, license: Option<License>) -> Self {
-        add_value!(self license license)
+        set_value!(self license license)
     }
 }
 
@@ -161,17 +161,17 @@ impl Contact {
 impl ContactBuilder {
     /// Add name contact person or organization of the API.
     pub fn name<S: Into<String>>(mut self, name: Option<S>) -> Self {
-        add_value!(self name name.map(|name| name.into()))
+        set_value!(self name name.map(|name| name.into()))
     }
 
     /// Add url pointing to the contact information of the API.
     pub fn url<S: Into<String>>(mut self, url: Option<S>) -> Self {
-        add_value!(self url url.map(|url| url.into()))
+        set_value!(self url url.map(|url| url.into()))
     }
 
     /// Add email of the contact person or organization of the API.
     pub fn email<S: Into<String>>(mut self, email: Option<S>) -> Self {
-        add_value!(self email email.map(|email| email.into()))
+        set_value!(self email email.map(|email| email.into()))
     }
 }
 
@@ -210,11 +210,11 @@ impl License {
 impl LicenseBuilder {
     /// Add name of the license used in API.
     pub fn name<S: Into<String>>(mut self, name: S) -> Self {
-        add_value!(self name name.into())
+        set_value!(self name name.into())
     }
 
     /// Add url pointing to the license used in API.
     pub fn url<S: Into<String>>(mut self, url: Option<S>) -> Self {
-        add_value!(self url url.map(|url| url.into()))
+        set_value!(self url url.map(|url| url.into()))
     }
 }
diff --git a/src/openapi/path.rs b/src/openapi/path.rs
index b18774c..b2670e3 100644
--- a/src/openapi/path.rs
+++ b/src/openapi/path.rs
@@ -1,187 +1,293 @@
-use std::collections::BTreeMap;
+//! Implements [OpenAPI Path Object][paths] types.
+//!
+//! [paths]: https://spec.openapis.org/oas/latest.html#paths-object
+use std::{collections::BTreeMap, iter};
 
 use serde::{Deserialize, Serialize};
 
 use super::{
+    build_fn, builder, from, new,
     request_body::RequestBody,
     response::{Response, Responses},
-    Component, Deprecated, ExternalDocs, Required, SecurityRequirement, Server,
+    set_value, Component, Deprecated, ExternalDocs, Required, SecurityRequirement, Server,
 };
 
-#[non_exhaustive]
-#[derive(Default)]
-pub struct Paths {
-    inner: Vec<(String, PathItem)>,
+builder! {
+    PathsBuilder;
+
+    /// Implements [OpenAPI Paths Object][paths].
+    ///
+    /// Holds relative paths to matching endpoints and operations. The path is appended to the url
+    /// from [`Server`] object to construct a full url for endpoint.
+    ///
+    /// [paths]: https://spec.openapis.org/oas/latest.html#paths-object
+    #[non_exhaustive]
+    #[derive(Serialize, Deserialize, Default, Clone)]
+    #[cfg_attr(feature = "debug", derive(Debug))]
+    pub struct Paths {
+        /// Map of relative paths with [`PathItem`]s holding [`Operation`]s matching
+        /// api endpoints.
+        pub paths: BTreeMap<String, PathItem>,
+    }
 }
 
 impl Paths {
+    /// Construct a new [`Paths`] object.
     pub fn new() -> Self {
         Default::default()
     }
 
-    pub fn append<S: AsRef<str>>(mut self, path: S, item: PathItem) -> Self {
-        self.inner.push((path.as_ref().to_string(), item));
-
-        self
+    /// Return [`Option<&PathItem>`] by given relative path if one exists
+    /// in [`Paths::paths`] map. Otherwise will return `None`.
+    pub fn get_path_item<P: AsRef<str>>(&self, path: P) -> Option<&PathItem> {
+        self.paths.get(path.as_ref())
     }
 
-    pub fn to_map(self) -> BTreeMap<String, PathItem> {
-        self.fold(BTreeMap::new(), |mut acc, (path, path_item)| {
-            if let Some(item) = acc.get_mut(&path) {
-                item.merge_operations(path_item);
-            } else {
-                acc.insert(path, path_item);
-            }
-
-            acc
-        })
+    /// Return [`Option<&Operation>`] from map of paths or `None` if not found.
+    ///
+    /// * First will try to find [`PathItem`] by given relative path.
+    /// * Then tries to find [`Operation`] from [`PathItem`]'s operations by given [`PathItemType`].
+    pub fn get_path_operation<P: AsRef<str>>(
+        &self,
+        path: P,
+        item_type: PathItemType,
+    ) -> Option<&Operation> {
+        self.paths
+            .get(path.as_ref())
+            .and_then(|path| path.operations.get(&item_type))
     }
 }
 
-impl Iterator for Paths {
-    type Item = (String, PathItem);
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if self.inner.is_empty() {
-            None
+impl PathsBuilder {
+    /// Append [`PathItem`] with path to map of paths. If path already exists it will merge [`Operation`]s of
+    /// [`PathItem`] with already found path item operations.
+    pub fn path<I: Into<String>>(mut self, path: I, mut item: PathItem) -> Self {
+        let path_string = path.into();
+        if let Some(existing_item) = self.paths.get_mut(&path_string) {
+            existing_item.operations.append(&mut item.operations);
         } else {
-            Some(self.inner.remove(0))
+            self.paths.insert(path_string, item);
         }
+
+        self
     }
 }
 
-#[non_exhaustive]
-#[derive(Serialize, Deserialize, Default, Clone)]
-#[cfg_attr(feature = "debug", derive(Debug))]
-#[serde(rename_all = "camelCase")]
-pub struct PathItem {
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub summary: Option<String>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub description: Option<String>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub servers: Option<Vec<Server>>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub parameters: Option<Vec<Parameter>>,
-
-    #[serde(flatten)]
-    pub operations: BTreeMap<PathItemType, Operation>,
+builder! {
+    PathItemBuilder;
+
+    /// Implements [OpenAPI Path Item Object][path_item] what describes [`Operation`]s availabe on
+    /// a single path.
+    ///
+    /// [path_item]: https://spec.openapis.org/oas/latest.html#path-item-object
+    #[non_exhaustive]
+    #[derive(Serialize, Deserialize, Default, Clone)]
+    #[cfg_attr(feature = "debug", derive(Debug))]
+    #[serde(rename_all = "camelCase")]
+    pub struct PathItem {
+        /// Optional summary intented to apply all operations in this [`PathItem`].
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub summary: Option<String>,
+
+        /// Optional description intented to apply all operations in this [`PathItem`].
+        /// Description supports markdown syntax.
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub description: Option<String>,
+
+        /// Alternative [`Server`] array to serve all [`Operation`]s in this [`PathItem`] overriding
+        /// the global server array.
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub servers: Option<Vec<Server>>,
+
+        /// List of [`Parameter`]s common to all [`Operation`]s in this [`PathItem`]. Parameters cannot
+        /// contain duplicate parameters. They can be overridden in [`Operation`] level but cannot be
+        /// removed there.
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub parameters: Option<Vec<Parameter>>,
+
+        /// Map of operations in this [`PathItem`]. Operations can hold only one operation
+        /// per [`PathItemType`].
+        #[serde(flatten)]
+        pub operations: BTreeMap<PathItemType, Operation>,
+    }
 }
 
 impl PathItem {
-    pub fn new(path_item_type: PathItemType, operation: Operation) -> Self {
-        let mut operations = BTreeMap::new();
-
-        operations.insert(path_item_type, operation);
+    /// Construct a new [`PathItem`] with provided [`Operation`] mapped to given [`PathItemType`].
+    pub fn new<O: Into<Operation>>(path_item_type: PathItemType, operation: O) -> Self {
+        let operations = BTreeMap::from_iter(iter::once((path_item_type, operation.into())));
 
         Self {
             operations,
             ..Default::default()
         }
     }
+}
 
-    pub fn with_summary<S: AsRef<str>>(mut self, summary: S) -> Self {
-        self.summary = Some(summary.as_ref().to_string());
+impl PathItemBuilder {
+    /// Append a new [`Operation`] by [`PathItemType`] to this [`PathItem`]. Operations can
+    /// hold only one operation per [`PathItemType`].
+    pub fn operation<O: Into<Operation>>(
+        mut self,
+        path_item_type: PathItemType,
+        operation: O,
+    ) -> Self {
+        self.operations.insert(path_item_type, operation.into());
 
         self
     }
 
-    pub fn with_description<S: AsRef<str>>(mut self, description: S) -> Self {
-        self.description = Some(description.as_ref().to_string());
-
-        self
+    /// Add or change summary intented to apply all operations in this [`PathItem`].
+    pub fn summary<S: Into<String>>(mut self, summary: Option<S>) -> Self {
+        set_value!(self summary summary.map(|summary| summary.into()))
     }
 
-    pub fn with_servers<I: IntoIterator<Item = Server>>(mut self, servers: I) -> Self {
-        self.servers = Some(servers.into_iter().collect());
-
-        self
+    /// Add or change optional description intented to apply all operations in this [`PathItem`].
+    /// Description supports markdown syntax.
+    pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
+        set_value!(self description description.map(|description| description.into()))
     }
 
-    pub fn with_parameters<I: IntoIterator<Item = Parameter>>(mut self, parameters: I) -> Self {
-        self.parameters = Some(parameters.into_iter().collect());
-
-        self
+    /// Add list of alternative [`Server`]s to serve all [`Operation`]s in this [`PathItem`] overriding
+    /// the global server array.
+    pub fn servers<I: IntoIterator<Item = Server>>(mut self, servers: Option<I>) -> Self {
+        set_value!(self servers servers.map(|servers| servers.into_iter().collect()))
     }
 
-    fn merge_operations(&mut self, mut another: PathItem) {
-        self.operations.append(&mut another.operations);
+    /// Append list of [`Parameter`]s common to all [`Operation`]s to this [`PathItem`].
+    pub fn parameters<I: IntoIterator<Item = Parameter>>(mut self, parameters: Option<I>) -> Self {
+        set_value!(self parameters parameters.map(|parameters| parameters.into_iter().collect()))
     }
 }
 
+/// Path item operation type.
 #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
 #[serde(rename_all = "lowercase")]
 #[cfg_attr(feature = "debug", derive(Debug))]
 pub enum PathItemType {
+    /// Type mapping for HTTP _GET_ request.
     Get,
+    /// Type mapping for HTTP _POST_ request.
     Post,
+    /// Type mapping for HTTP _PUT_ request.
     Put,
+    /// Type mapping for HTTP _DELETE_ request.
     Delete,
+    /// Type mapping for HTTP _OPTIONS_ request.
     Options,
+    /// Type mapping for HTTP _HEAD_ request.
     Head,
+    /// Type mapping for HTTP _PATCH_ request.
     Patch,
+    /// Type mapping for HTTP _TRACE_ request.
     Trace,
+    /// Type mapping for HTTP _CONNECT_ request.
     Connect,
 }
 
-#[non_exhaustive]
-#[derive(Serialize, Deserialize, Default, Clone)]
-#[cfg_attr(feature = "debug", derive(Debug))]
-#[serde(rename_all = "camelCase")]
-pub struct Operation {
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub tags: Option<Vec<String>>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub summary: Option<String>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub description: Option<String>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub operation_id: Option<String>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub external_docs: Option<ExternalDocs>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub parameters: Option<Vec<Parameter>>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub request_body: Option<RequestBody>,
-
-    pub responses: Responses,
-
-    // TODO
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub callbacks: Option<String>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub deprecated: Option<Deprecated>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub security: Option<Vec<SecurityRequirement>>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub servers: Option<Vec<Server>>,
+builder! {
+    OperationBuilder;
+
+    /// Implements [OpenAPI Operation Object][operation] object.
+    ///
+    /// [operation]: https://spec.openapis.org/oas/latest.html#operation-object
+    #[non_exhaustive]
+    #[derive(Serialize, Deserialize, Default, Clone)]
+    #[cfg_attr(feature = "debug", derive(Debug))]
+    #[serde(rename_all = "camelCase")]
+    pub struct Operation {
+        /// List of tags used for groupping operations.
+        ///
+        /// When used with derive [`#[utoipa::path(...)]`][derive_path] attribute macro the default
+        /// value used will be resolved from handler path provided in `#[openapi(handlers(...))]` with
+        /// [`#[derive(OpenApi)]`][derive_openapi] macro. If path resolves to `None` value `crate` will
+        /// be used by default.
+        ///
+        /// [derive_path]: ../../attr.path.html
+        /// [derive_openapi]: ../../derive.OpenApi.html
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub tags: Option<Vec<String>>,
+
+        /// Short summary what [`Operation`] does.
+        ///
+        /// When used with derive [`#[utoipa::path(...)]`][derive_path] attribute macro the value
+        /// is taken from **first line** of doc comment.
+        ///
+        /// [derive_path]: ../../attr.path.html
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub summary: Option<String>,
+
+        /// Long explanation of [`Operation`] behaviour. Markdown syntax is supported.
+        ///
+        /// When used with derive [`#[utoipa::path(...)]`][derive_path] attribute macro the
+        /// doc comment is used as value for description.
+        ///
+        /// [derive_path]: ../../attr.path.html
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub description: Option<String>,
+
+        /// Unique identifier for the API [`Operation`]. Most typically this is mapped to handler function name.
+        ///
+        /// When used with derive [`#[utoipa::path(...)]`][derive_path] attribute macro the handler function
+        /// name will be used by default.
+        ///
+        /// [derive_path]: ../../attr.path.html
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub operation_id: Option<String>,
+
+        /// Additional external documentation for this operation.
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub external_docs: Option<ExternalDocs>,
+
+        /// List of applicable parameters for this [`Operation`].
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub parameters: Option<Vec<Parameter>>,
+
+        /// Optional request body for this [`Operation`].
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub request_body: Option<RequestBody>,
+
+        /// List of possible responses returned by the [`Operation`].
+        pub responses: Responses,
+
+        // TODO
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub callbacks: Option<String>,
+
+        /// Define whether the operation is deprecated or not and thus should be avoided consuming.
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub deprecated: Option<Deprecated>,
+
+        /// Declaration which security mechanishms can be used for for the operation. Only one
+        /// [`SecurityRequirement`] must be met.
+        ///
+        /// Security for the [`Operation`] can be set to optional by adding emty security with
+        /// [`SecurityRequirement::default`].
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub security: Option<Vec<SecurityRequirement>>,
+
+        /// Alternative [`Server`]s for this [`Operation`].
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub servers: Option<Vec<Server>>,
+    }
 }
 
 impl Operation {
+    /// Construct a new API [`Operation`].
     pub fn new() -> Self {
         Default::default()
     }
+}
 
-    pub fn with_tags<I: IntoIterator<Item = String>>(mut self, tags: I) -> Self {
-        self.tags = Some(tags.into_iter().collect());
-
-        self
+impl OperationBuilder {
+    /// Add or change tags of the [`Operation`].
+    pub fn tags<I: IntoIterator<Item = String>>(mut self, tags: Option<I>) -> Self {
+        set_value!(self tags tags.map(|tags| tags.into_iter().collect()))
     }
 
-    pub fn with_tag<S: AsRef<str>>(mut self, tag: S) -> Self {
-        let tag_string = tag.as_ref().to_string();
+    /// Append tag to [`Operation`] tags.
+    pub fn tag<S: Into<String>>(mut self, tag: S) -> Self {
+        let tag_string = tag.into();
         match self.tags {
             Some(ref mut tags) => tags.push(tag_string),
             None => {
@@ -192,133 +298,164 @@ impl Operation {
         self
     }
 
-    pub fn with_summary<S: AsRef<str>>(mut self, summary: S) -> Self {
-        self.summary = Some(summary.as_ref().to_string());
-
-        self
+    /// Add or change short summary of the [`Operation`].
+    pub fn summary<S: Into<String>>(mut self, summary: Option<S>) -> Self {
+        set_value!(self summary summary.map(|summary| summary.into()))
     }
 
-    pub fn with_description<S: AsRef<str>>(mut self, description: S) -> Self {
-        self.description = Some(description.as_ref().to_string());
-
-        self
+    /// Add or change description of the [`Operation`].
+    pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
+        set_value!(self description description.map(|description| description.into()))
     }
 
-    pub fn with_operation_id<S: AsRef<str>>(mut self, operation_id: S) -> Self {
-        self.operation_id = Some(operation_id.as_ref().to_string());
-
-        self
+    /// Add or change operation id of the [`Operation`].
+    pub fn operation_id<S: Into<String>>(mut self, operation_id: Option<S>) -> Self {
+        set_value!(self operation_id operation_id.map(|operation_id| operation_id.into()))
     }
 
-    pub fn with_parameters<I: IntoIterator<Item = Parameter>>(mut self, parameters: I) -> Self {
-        self.parameters = Some(parameters.into_iter().collect());
-
-        self
+    /// Add or change parameters of the [`Operation`].
+    pub fn parameters<I: IntoIterator<Item = Parameter>>(mut self, parameters: Option<I>) -> Self {
+        set_value!(self parameters parameters.map(|parameters| parameters.into_iter().collect()))
     }
 
-    pub fn with_parameter(mut self, parameter: Parameter) -> Self {
+    /// Append parameter to [`Operation`] parameters.
+    pub fn parameter<P: Into<Parameter>>(mut self, parameter: P) -> Self {
         match self.parameters {
-            Some(ref mut parameters) => parameters.push(parameter),
+            Some(ref mut parameters) => parameters.push(parameter.into()),
             None => {
-                self.parameters = Some(vec![parameter]);
+                self.parameters = Some(vec![parameter.into()]);
             }
         }
 
         self
     }
 
-    pub fn with_request_body(mut self, request_body: RequestBody) -> Self {
-        self.request_body = Some(request_body);
-
-        self
+    /// Add or change request body of the [`Operation`].
+    pub fn request_body(mut self, request_body: Option<RequestBody>) -> Self {
+        set_value!(self request_body request_body)
     }
 
-    pub fn with_responses(mut self, responses: Responses) -> Self {
-        self.responses = responses;
-
-        self
+    /// Add or change responses of the [`Operation`].
+    pub fn responses<R: Into<Responses>>(mut self, responses: R) -> Self {
+        set_value!(self responses responses.into())
     }
 
-    pub fn with_response<S: Into<String>>(mut self, code: S, response: Response) -> Self {
+    /// Append status code and a [`Response`] to the [`Operation`] responses map.
+    ///
+    /// * `code` must be valid HTTP status code.
+    /// * `response` is instances of [`Response`].
+    pub fn response<S: Into<String>>(mut self, code: S, response: Response) -> Self {
         self.responses.responses.insert(code.into(), response);
 
         self
     }
 
-    pub fn with_deprecated(mut self, deprecated: Deprecated) -> Self {
-        self.deprecated = Some(deprecated);
-
-        self
+    /// Add or change deprecated status of the [`Operation`].
+    pub fn deprecated(mut self, deprecated: Option<Deprecated>) -> Self {
+        set_value!(self deprecated deprecated)
     }
 
-    /// Add list of [`SecurityRequirement`]s that are globally available for all operations.
-    pub fn with_securities<I: IntoIterator<Item = SecurityRequirement>>(
+    /// Add or change list of [`SecurityRequirement`]s that are available for [`Operation`].
+    pub fn securities<I: IntoIterator<Item = SecurityRequirement>>(
         mut self,
-        securities: I,
+        securities: Option<I>,
     ) -> Self {
-        self.security = Some(securities.into_iter().collect());
-
-        self
+        set_value!(self security securities.map(|securities| securities.into_iter().collect()))
     }
 
-    /// Add [`SecurityRequirement`] that is globally available for all operations.
-    pub fn with_security(mut self, security: SecurityRequirement) -> Self {
-        self.security.as_mut().unwrap().push(security);
+    /// Append [`SecurityRequirement`] to [`Operation`] security requirements.
+    pub fn security(mut self, security: SecurityRequirement) -> Self {
+        if let Some(ref mut securities) = self.security {
+            securities.push(security);
+        } else {
+            self.security = Some(vec![security]);
+        }
 
         self
     }
 
-    pub fn with_servers<I: IntoIterator<Item = Server>>(mut self, servers: I) -> Self {
-        self.servers = Some(servers.into_iter().collect());
-
-        self
+    /// Add or change list of [`Server`]s of the [`Operation`].
+    pub fn servers<I: IntoIterator<Item = Server>>(mut self, servers: Option<I>) -> Self {
+        set_value!(self servers servers.map(|servers| servers.into_iter().collect()))
     }
 
-    pub fn with_server(mut self, server: Server) -> Self {
-        self.servers.as_mut().unwrap().push(server);
+    /// Append a new [`Server`] to the [`Operation`] servers.
+    pub fn server(mut self, server: Server) -> Self {
+        if let Some(ref mut servers) = self.servers {
+            servers.push(server);
+        } else {
+            self.servers = Some(vec![server]);
+        }
 
         self
     }
 }
 
-#[non_exhaustive]
-#[derive(Serialize, Deserialize, Default, Clone)]
-#[cfg_attr(feature = "debug", derive(Debug))]
-#[serde(rename_all = "camelCase")]
-pub struct Parameter {
-    pub name: String,
-
-    #[serde(rename = "in")]
-    pub parameter_in: ParameterIn,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub description: Option<String>,
-
-    pub required: Required,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub deprecated: Option<Deprecated>,
-    // pub allow_empty_value: bool, this is going to be removed from further open api spec releases
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub schema: Option<Component>,
+builder! {
+    ParameterBuilder;
+
+    /// Implements [OpenAPI Parameter Object][parameter] for [`Operation`].
+    ///
+    /// [parameter]: https://spec.openapis.org/oas/latest.html#parameter-object
+    #[non_exhaustive]
+    #[derive(Serialize, Deserialize, Default, Clone)]
+    #[cfg_attr(feature = "debug", derive(Debug))]
+    #[serde(rename_all = "camelCase")]
+    pub struct Parameter {
+        /// Name of the parameter.
+        ///
+        /// * For [`ParameterIn::Path`] this must in accordance to path templating.
+        /// * For [`ParameterIn::Query`] `Content-Type` or `Authorization` value will be ignored.
+        pub name: String,
+
+        /// Parameter location.
+        #[serde(rename = "in")]
+        pub parameter_in: ParameterIn,
+
+        /// Markdown supported description of the parameter.
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub description: Option<String>,
+
+        /// Declares whether the parameter is required or not for api.
+        ///
+        /// * For [`ParameterIn::Path`] this must and will be [`Required::True`].
+        pub required: Required,
+
+        /// Delcares the parameter deprecated status.
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub deprecated: Option<Deprecated>,
+        // pub allow_empty_value: bool, this is going to be removed from further open api spec releases
+
+        /// Schema of the parameter. Typically [`Component::Property`] is used.
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub schema: Option<Component>,
+    }
 }
 
 impl Parameter {
-    pub fn new<S: AsRef<str>>(name: S) -> Self {
+    /// Constructs a new required [`Parameter`] with given name.
+    pub fn new<S: Into<String>>(name: S) -> Self {
         Self {
-            name: name.as_ref().to_string(),
+            name: name.into(),
             required: Required::True,
             ..Default::default()
         }
     }
+}
+impl ParameterBuilder {
+    /// Add name of the [`Parameter`].
+    pub fn name<I: Into<String>>(mut self, name: I) -> Self {
+        set_value!(self name name.into())
+    }
 
-    pub fn with_in(mut self, parameter_in: ParameterIn) -> Self {
-        self.parameter_in = parameter_in;
-
-        self
+    /// Add in of the [`Parameter`].
+    pub fn parameter_in(mut self, parameter_in: ParameterIn) -> Self {
+        set_value!(self parameter_in parameter_in)
     }
 
-    pub fn with_required(mut self, required: Required) -> Self {
+    /// Add required declaration of the [`Parameter`]. If [`ParameterIn::Path`] is
+    /// defined this is always [`Required::True`].
+    pub fn required(mut self, required: Required) -> Self {
         self.required = required;
         // required must be true, if parameter_in is Path
         if self.parameter_in == ParameterIn::Path {
@@ -328,32 +465,34 @@ impl Parameter {
         self
     }
 
-    pub fn with_description<S: AsRef<str>>(mut self, description: S) -> Self {
-        self.description = Some(description.as_ref().to_string());
-
-        self
+    /// Add or change description of the [`Parameter`].
+    pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
+        set_value!(self description description.map(|description| description.into()))
     }
 
-    pub fn with_deprecated(mut self, deprecated: Deprecated) -> Self {
-        self.deprecated = Some(deprecated);
-
-        self
+    /// Add or change [`Parameter`] deprecated declaration.
+    pub fn deprecated(mut self, deprecated: Option<Deprecated>) -> Self {
+        set_value!(self deprecated deprecated)
     }
 
-    pub fn with_schema<I: Into<Component>>(mut self, component: I) -> Self {
-        self.schema = Some(component.into());
-
-        self
+    /// Add or change [`Parameter`]s schema.
+    pub fn schema<I: Into<Component>>(mut self, component: Option<I>) -> Self {
+        set_value!(self schema component.map(|component| component.into()))
     }
 }
 
+/// In definition of [`Parameter`].
 #[derive(Serialize, Deserialize, PartialEq, Clone)]
 #[serde(rename_all = "lowercase")]
 #[cfg_attr(feature = "debug", derive(Debug))]
 pub enum ParameterIn {
+    /// Delcares that parameter is used as query parameter.
     Query,
+    /// Delcares that parameter is used as path parameter.
     Path,
+    /// Delcares that parameter is used as header value.
     Header,
+    /// Delcares that parameter is used as cookie value.
     Cookie,
 }
 
diff --git a/src/openapi/request_body.rs b/src/openapi/request_body.rs
index 0bb4896..ad5af2f 100644
--- a/src/openapi/request_body.rs
+++ b/src/openapi/request_body.rs
@@ -5,7 +5,7 @@ use std::collections::HashMap;
 
 use serde::{Deserialize, Serialize};
 
-use super::{add_value, build_fn, builder, from, new, Content, Required};
+use super::{build_fn, builder, from, new, set_value, Content, Required};
 
 builder! {
     RequestBodyBuilder;
@@ -41,12 +41,12 @@ impl RequestBody {
 impl RequestBodyBuilder {
     /// Add description for [`RequestBody`].
     pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
-        add_value!(self description description.map(|description| description.into()))
+        set_value!(self description description.map(|description| description.into()))
     }
 
     /// Define [`RequestBody`] required.
     pub fn required(mut self, required: Option<Required>) -> Self {
-        add_value!(self required required)
+        set_value!(self required required)
     }
 
     /// Add [`Content`] by content type e.g `application/json` to [`RequestBody`].
diff --git a/src/openapi/response.rs b/src/openapi/response.rs
index 08ca517..f7ab6a7 100644
--- a/src/openapi/response.rs
+++ b/src/openapi/response.rs
@@ -5,7 +5,7 @@ use std::collections::{BTreeMap, HashMap};
 
 use serde::{Deserialize, Serialize};
 
-use super::{add_value, build_fn, builder, from, header::Header, new, Content};
+use super::{build_fn, builder, from, header::Header, new, set_value, Content};
 
 builder! {
     ResponsesBuilder;
@@ -34,8 +34,8 @@ impl Responses {
 
 impl ResponsesBuilder {
     /// Add response to responses.
-    pub fn response<S: Into<String>>(mut self, code: S, response: Response) -> Self {
-        self.responses.insert(code.into(), response);
+    pub fn response<S: Into<String>, R: Into<Response>>(mut self, code: S, response: R) -> Self {
+        self.responses.insert(code.into(), response.into());
 
         self
     }
@@ -96,7 +96,7 @@ impl Response {
 impl ResponseBuilder {
     /// Add description. Description supports markdown syntax.
     pub fn description<I: Into<String>>(mut self, description: I) -> Self {
-        add_value!(self description description.into())
+        set_value!(self description description.into())
     }
 
     /// Add [`Content`] of the [`Response`] with content type e.g `application/json`.
diff --git a/src/openapi/schema.rs b/src/openapi/schema.rs
index b9ac26b..f507f22 100644
--- a/src/openapi/schema.rs
+++ b/src/openapi/schema.rs
@@ -1,60 +1,70 @@
+//! Implements [OpenAPI Schema Object][schema] types which can be
+//! used to define field properties, enum values, array or object types.
+//! 
+//! [schema]: https://spec.openapis.org/oas/latest.html#schema-object
 use std::collections::HashMap;
 
 use serde::{Deserialize, Serialize};
 #[cfg(feature = "serde_json")]
 use serde_json::Value;
 
-use super::{security::SecuritySchema, xml::Xml, Deprecated};
+use super::{
+    set_value, build_fn, builder, from, new, security::SecuritySchema, xml::Xml, Deprecated,
+};
 
-#[non_exhaustive]
-#[derive(Serialize, Deserialize, Default, Clone)]
-#[cfg_attr(feature = "debug", derive(Debug))]
-#[serde(rename_all = "camelCase")]
-pub struct Components {
-    #[serde(skip_serializing_if = "HashMap::is_empty")]
-    schemas: HashMap<String, Component>,
+macro_rules! component_from_builder {
+    ( $name:ident ) => {
+        impl From<$name> for Component {
+            fn from(builder: $name) -> Self {
+                builder.build().into()
+            }
+        }
+    };
+}
 
-    #[serde(skip_serializing_if = "HashMap::is_empty")]
-    security_schemas: HashMap<String, SecuritySchema>,
+macro_rules! to_array_builder {
+    () => {
+        /// Construct a new [`ArrayBuilder`] with this component set to [`ArrayBuilder::items`].
+        pub fn to_array_builder(self) -> ArrayBuilder {
+            ArrayBuilder::from(Array::new(self))
+        }
+    };
+}
+
+builder! {
+    ComponentsBuilder;
+
+    /// Implements [OpenAPI Components Object][components] which holds supported
+    /// reusable objects.
+    ///
+    /// [components]: https://spec.openapis.org/oas/latest.html#components-object
+    #[non_exhaustive]
+    #[derive(Serialize, Deserialize, Default, Clone)]
+    #[cfg_attr(feature = "debug", derive(Debug))]
+    #[serde(rename_all = "camelCase")]
+    pub struct Components {
+        /// Map of reusable [OpenAPI Schema Object][schema]s.
+        ///
+        /// [schema]: https://spec.openapis.org/oas/latest.html#schema-object
+        #[serde(skip_serializing_if = "HashMap::is_empty")]
+        pub schemas: HashMap<String, Component>,
+
+        /// Map of reusable [OpenAPI Security Schema Object][security_schema]s.
+        ///
+        /// [security_schema]: https://spec.openapis.org/oas/latest.html#security-scheme-object
+        #[serde(skip_serializing_if = "HashMap::is_empty")]
+        pub security_schemas: HashMap<String, SecuritySchema>,
+    }
 }
 
 impl Components {
+    /// Construct a new [`Components`].
     pub fn new() -> Self {
         Self {
             ..Default::default()
         }
     }
-
-    pub fn with_component<S: AsRef<str>, I: Into<Component>>(
-        mut self,
-        name: S,
-        component: I,
-    ) -> Self {
-        self.schemas
-            .insert(name.as_ref().to_string(), component.into());
-
-        self
-    }
-
-    /// Add [`SecuritySchema`] to [`Components`] while consuming self.
-    ///
-    /// Accepts two arguments where first is the name of the [`SecuritySchema`]. This is later when
-    /// referenced by [`SecurityRequirement`][requirement]s. Second parameter is the [`SecuritySchema`].
-    ///
-    /// [requirement]: ../security/struct.SecurityRequirement.html
-    pub fn with_security_schemas<N: Into<String>, S: Into<SecuritySchema>>(
-        mut self,
-        name: N,
-        security_schema: S,
-    ) -> Self {
-        self.security_schemas
-            .insert(name.into(), security_schema.into());
-
-        self
-    }
-
-    /// Add [`SecuritySchema`] to [`Components`] **without** consuming self. Use this when you want to
-    /// update existing [`Components`] object.
+    /// Add [`SecuritySchema`] to [`Components`]
     ///
     /// Accepts two arguments where first is the name of the [`SecuritySchema`]. This is later when
     /// referenced by [`SecurityRequirement`][requirement]s. Second parameter is the [`SecuritySchema`].
@@ -69,8 +79,7 @@ impl Components {
             .insert(name.into(), security_schema.into());
     }
 
-    /// Add iterator of [`SecuritySchema`]s to [`Components`] **without** consuming self. Use this
-    /// when you want to update existing [`Components`] object.
+    /// Add iterator of [`SecuritySchema`]s to [`Components`].
     ///
     /// Accepts two arguments where first is the name of the [`SecuritySchema`]. This is later when
     /// referenced by [`SecurityRequirement`][requirement]s. Second parameter is the [`SecuritySchema`].
@@ -92,15 +101,63 @@ impl Components {
     }
 }
 
+impl ComponentsBuilder {
+    /// Add [`Component`] to [`Components`].
+    ///
+    /// Accpets two arguments where first is name of the component and second is the component itself.
+    pub fn component<S: Into<String>, I: Into<Component>>(mut self, name: S, component: I) -> Self {
+        self.schemas.insert(name.into(), component.into());
+
+        self
+    }
+
+    /// Add [`SecuritySchema`] to [`Components`].
+    ///
+    /// Accepts two arguments where first is the name of the [`SecuritySchema`]. This is later when
+    /// referenced by [`SecurityRequirement`][requirement]s. Second parameter is the [`SecuritySchema`].
+    ///
+    /// [requirement]: ../security/struct.SecurityRequirement.html
+    pub fn security_schema<N: Into<String>, S: Into<SecuritySchema>>(
+        mut self,
+        name: N,
+        security_schema: S,
+    ) -> Self {
+        self.security_schemas
+            .insert(name.into(), security_schema.into());
+
+        self
+    }
+}
+
+/// Is super type for [OpenAPI Schema Object][components] components. Component
+/// is reusable resource what can be referenced from path operations and other
+/// components using [`Ref`] component.
+///
+/// [components]: https://spec.openapis.org/oas/latest.html#components-object
 #[non_exhaustive]
 #[derive(Serialize, Deserialize, Clone)]
 #[cfg_attr(feature = "debug", derive(Debug))]
 #[serde(untagged, rename_all = "camelCase")]
 pub enum Component {
+    /// Defines property component typically used together with
+    /// [`Component::Object`] or [`Component::Array`]. It is used to map
+    /// field types to OpenAPI documentation.
     Property(Property),
+    /// Creates a reference component _`$ref=#/components/schemas/ComponentName`_. Which
+    /// can be used to reference a other reusable component in [`Components`].
     Ref(Ref),
+    /// Defines object component. This is formed from structs holding [`Property`] components
+    /// created from it's fields.
     Object(Object),
+    /// Defines array component from another component. Typically used with
+    /// [`Component::Property`] or [`Component::Object`] component. Slice and Vec
+    /// types are translated to [`Component::Array`] types.
     Array(Array),
+    /// Creates a _OneOf_ type [Discriminator Object][discriminator] component. This component
+    /// is used to map multiple components together where API endpoint could return any of them.
+    /// [`Component::OneOf`] is created form complex enum where enum holds other than unit types.
+    ///
+    /// [discriminator]: https://spec.openapis.org/oas/latest.html#components-object
     OneOf(OneOf),
 }
 
@@ -110,82 +167,132 @@ impl Default for Component {
     }
 }
 
-#[derive(Serialize, Deserialize, Clone, Default)]
-#[cfg_attr(feature = "debug", derive(Debug))]
-pub struct OneOf {
-    #[serde(rename = "oneOf")]
-    items: Vec<Component>,
+builder! {
+    OneOfBuilder;
+
+    /// OneOf [Discriminator Object][discriminator] component holds
+    /// multiple components together where API endpoint could return any of them.
+    ///
+    /// See [`Component::OneOf`] for more details.
+    ///
+    /// [discriminator]: https://spec.openapis.org/oas/latest.html#components-object
+    #[derive(Serialize, Deserialize, Clone, Default)]
+    #[cfg_attr(feature = "debug", derive(Debug))]
+    pub struct OneOf {
+        /// Components of _OneOf_ component.
+        #[serde(rename = "oneOf")]
+        pub items: Vec<Component>,
+    }
 }
 
 impl OneOf {
+    /// Construct a new [`OneOf`] component.
     pub fn new() -> Self {
         Self {
             ..Default::default()
         }
     }
 
+    /// Construct a new [`OneOf`] component with given capacity.
+    ///
+    /// OneOf component is then able to contain number of components without
+    /// reallocating.
+    ///
+    /// # Examples
+    ///
+    /// Create [`OneOf`] component with initial capacity of 5.
+    /// ```rust
+    /// # use utoipa::openapi::schema::OneOf;
+    /// let one_of = OneOf::with_capacity(5);
+    /// ```
     pub fn with_capacity(capacity: usize) -> Self {
         Self {
             items: Vec::with_capacity(capacity),
         }
     }
+}
 
-    pub fn append<I: Into<Component>>(mut self, component: I) -> Self {
+impl OneOfBuilder {
+    /// Adds a given [`Component`] to [`OneOf`] [Discriminator Object][discriminator]
+    ///
+    /// [discriminator]: https://spec.openapis.org/oas/latest.html#components-object
+    pub fn item<I: Into<Component>>(mut self, component: I) -> Self {
         self.items.push(component.into());
 
         self
     }
+
+    to_array_builder!();
 }
 
+
 impl From<OneOf> for Component {
     fn from(one_of: OneOf) -> Self {
         Self::OneOf(one_of)
     }
 }
 
+component_from_builder!(OneOfBuilder);
+
+/// Implements special subset of [OpenAPI Schema Object][schema] which can be
+/// used to define field property or enum values or type for array items.
+/// 
+/// [schema]: https://spec.openapis.org/oas/latest.html#schema-object
 #[derive(Default, Serialize, Deserialize, Clone)]
 #[cfg_attr(feature = "debug", derive(Debug))]
 #[serde(rename_all = "camelCase")]
 pub struct Property {
+    /// Type of the property e.g [`ComponentType::String`].
     #[serde(rename = "type")]
-    component_type: ComponentType,
+    pub component_type: ComponentType,
 
+    /// Additional format for detailing the component type.
     #[serde(skip_serializing_if = "Option::is_none")]
-    format: Option<ComponentFormat>,
+    pub format: Option<ComponentFormat>,
 
+    /// Description of the property. Markdown syntax is supported.
     #[serde(skip_serializing_if = "Option::is_none")]
-    description: Option<String>,
+    pub description: Option<String>,
 
+    /// Default value for the property which is provided when user has not provided the input.
     #[serde(skip_serializing_if = "Option::is_none")]
     #[cfg(feature = "serde_json")]
-    default: Option<Value>,
+    pub default: Option<Value>,
 
+    /// Default value for the property which is provided when user has not provided the input.
     #[serde(skip_serializing_if = "Option::is_none")]
     #[cfg(not(feature = "serde_json"))]
-    default: Option<String>,
+    pub default: Option<String>,
 
+    /// Enum type property possible variants.
     #[serde(rename = "enum", skip_serializing_if = "Option::is_none")]
-    enum_values: Option<Vec<String>>,
+    pub enum_values: Option<Vec<String>>,
 
+    /// Example shown in UI of the value for richier documentation.
     #[serde(skip_serializing_if = "Option::is_none")]
     #[cfg(not(feature = "serde_json"))]
-    example: Option<String>,
-
+    pub example: Option<String>,
+    
+    /// Example shown in UI of the value for richier documentation.
     #[serde(skip_serializing_if = "Option::is_none")]
     #[cfg(feature = "serde_json")]
-    example: Option<Value>,
+    pub example: Option<Value>,
 
+    /// Changes the [`Property`] deprecated status.
     #[serde(skip_serializing_if = "Option::is_none")]
-    deprecated: Option<Deprecated>,
+    pub deprecated: Option<Deprecated>,
 
+    /// Write only property will be only sent in _write_ requests like _POST, PUT_.
     #[serde(skip_serializing_if = "Option::is_none")]
-    write_only: Option<bool>,
+    pub write_only: Option<bool>,
 
+    /// Read only property will be only sent in _read_ requests like _GET_.
     #[serde(skip_serializing_if = "Option::is_none")]
-    read_only: Option<bool>,
+    pub read_only: Option<bool>,
 
+    /// Additional [`Xml`] formatting of the [`Property`].
     #[serde(skip_serializing_if = "Option::is_none")]
-    xml: Option<Xml>,
+    pub xml: Option<Xml>,
 }
 
 impl Property {
@@ -195,121 +302,172 @@ impl Property {
             ..Default::default()
         }
     }
+}
 
-    pub fn with_format(mut self, format: ComponentFormat) -> Self {
-        self.format = Some(format);
-
-        self
+impl From<Property> for Component {
+    fn from(property: Property) -> Self {
+        Self::Property(property)
     }
+}
+
+impl ToArray for Property {}
 
-    pub fn with_description<S: AsRef<str>>(mut self, description: S) -> Self {
-        self.description = Some(description.as_ref().to_string());
+/// Builder for [`Property`] with chainable configuration methods to create a new [`Property`].
+#[derive(Default)]
+pub struct PropertyBuilder {
+    component_type: ComponentType,
 
-        self
-    }
+    format: Option<ComponentFormat>,
+
+    description: Option<String>,
 
     #[cfg(feature = "serde_json")]
-    pub fn with_default(mut self, default: Value) -> Self {
-        self.default = Some(default);
+    default: Option<Value>,
 
-        self
-    }
+    #[cfg(not(feature = "serde_json"))]
+    default: Option<String>,
+
+    enum_values: Option<Vec<String>>,
 
     #[cfg(not(feature = "serde_json"))]
-    pub fn with_default<I: Into<String>>(mut self, default: I) -> Self {
-        self.default = Some(default.into());
+    example: Option<String>,
 
-        self
-    }
+    #[cfg(feature = "serde_json")]
+    example: Option<Value>,
 
-    pub fn with_enum_values<S: AsRef<str>>(mut self, enum_values: &[S]) -> Self {
-        self.enum_values = Some(
-            enum_values
-                .iter()
-                .map(|str| str.as_ref().to_string())
-                .collect(),
-        );
+    deprecated: Option<Deprecated>,
 
-        self
-    }
+    write_only: Option<bool>,
 
-    #[cfg(not(feature = "serde_json"))]
-    pub fn with_example<I: Into<String>>(mut self, example: I) -> Self {
-        self.example = Some(example.into());
+    read_only: Option<bool>,
 
-        self
+    xml: Option<Xml>,
+}
+
+from!(Property PropertyBuilder 
+    component_type, format, description, default, enum_values, example, deprecated, write_only, read_only, xml);
+
+impl PropertyBuilder {
+    new!(pub PropertyBuilder);
+
+    /// Add or change type of the property e.g [`ComponentType::String`].
+    pub fn component_type(mut self, component_type: ComponentType) -> Self {
+        set_value!(self component_type component_type)
     }
 
-    #[cfg(feature = "serde_json")]
-    pub fn with_example(mut self, example: Value) -> Self {
-        self.example = Some(example);
+    /// Add or change additional format for detailing the component type.
+    pub fn format(mut self, format: Option<ComponentFormat>) -> Self {
+        set_value!(self format format)
+    }
 
-        self
+    /// Add or change description of the property. Markdown syntax is supported.
+    pub fn description<I: Into<String>>(mut self, description: Option<I>) -> Self {
+        set_value!(self description description.map(|description| description.into()))
     }
 
-    pub fn with_deprecated(mut self, deprecated: Deprecated) -> Self {
-        self.deprecated = Some(deprecated);
+    /// Add or change default value for the property which is provided when user has not provided the input.
+    #[cfg(feature = "serde_json")]
+    pub fn default(mut self, default: Option<Value>) -> Self {
+        set_value!(self default default)
+    }
 
-        self
+    /// Add or change default value for the property which is provided when user has not provided the input.
+    #[cfg(not(feature = "serde_json"))]
+    pub fn default<I: Into<String>>(mut self, default: Option<I>) -> Self {
+        set_value!(self default default.map(|default| default.into()))
     }
 
-    pub fn with_write_only(mut self, write_only: bool) -> Self {
-        self.write_only = Some(write_only);
+    /// Add or change enum property variants.
+    pub fn enum_values<I: IntoIterator<Item = E>, E: Into<String>>(
+        mut self,
+        enum_values: Option<I>,
+    ) -> Self {
+        set_value!(self enum_values 
+            enum_values.map(|values| values.into_iter().map(|enum_value| enum_value.into()).collect()))
+    }
 
-        self
+    /// Add or change example shown in UI of the value for richier documentation.
+    #[cfg(not(feature = "serde_json"))]
+    pub fn example<I: Into<String>>(mut self, example: Option<I>) -> Self {
+        set_value!(self example example.map(|example| example.into()))
     }
 
-    pub fn with_read_only(mut self, read_only: bool) -> Self {
-        self.read_only = Some(read_only);
+    /// Add or change example shown in UI of the value for richier documentation.
+    #[cfg(feature = "serde_json")]
+    pub fn example(mut self, example: Option<Value>) -> Self {
+        set_value!(self example example)
+    }
 
-        self
+    /// Add or change deprecated status for [`Property`].
+    pub fn deprecated(mut self, deprecated: Option<Deprecated>) -> Self {
+        set_value!(self deprecated deprecated)
     }
 
-    pub fn with_xml(mut self, xml: Xml) -> Self {
-        self.xml = Some(xml);
+    /// Add or change write only flag for [`Property`].
+    pub fn write_only(mut self, write_only: Option<bool>) -> Self {
+        set_value!(self write_only write_only)
+    }
 
-        self
+    /// Add or change read only flag for [`Property`].
+    pub fn read_only(mut self, read_only: Option<bool>) -> Self {
+        set_value!(self read_only read_only)
     }
-}
 
-impl From<Property> for Component {
-    fn from(property: Property) -> Self {
-        Self::Property(property)
+    /// Add or change additional [`Xml`] formatting of the [`Property`].
+    pub fn xml(mut self, xml: Option<Xml>) -> Self {
+        set_value!(self xml xml)
     }
+
+    to_array_builder!();
+
+    build_fn!(pub Property 
+        component_type, format, description, default, enum_values, example, deprecated, write_only, read_only, xml);
 }
 
-impl ToArray for Property {}
+component_from_builder!(PropertyBuilder);
 
+/// Implements subset of [OpenAPI Schema Object][schema] which allows 
+/// adding other [`Component`]s as **properties** to this [`Component`].
+/// 
+/// [schema]: https://spec.openapis.org/oas/latest.html#schema-object
 #[non_exhaustive]
 #[derive(Serialize, Deserialize, Default, Clone)]
 #[cfg_attr(feature = "debug", derive(Debug))]
 #[serde(rename_all = "camelCase")]
 pub struct Object {
+    /// Data type of [`Object`]. Will always be [`ComponentType::Object`]
     #[serde(rename = "type")]
     component_type: ComponentType,
 
+    /// Vector of required field names.
     #[serde(skip_serializing_if = "Vec::is_empty")]
-    required: Vec<String>,
+    pub required: Vec<String>,
 
+    /// Map of fields with their [`Component`] types.
     #[serde(skip_serializing_if = "HashMap::is_empty")]
-    properties: HashMap<String, Component>,
+    pub properties: HashMap<String, Component>,
 
+    /// Description of the [`Object`]. Markdown syntax is supported.
     #[serde(skip_serializing_if = "Option::is_none")]
-    description: Option<String>,
+    pub description: Option<String>,
 
+    /// Changes the [`Object`] deprecated status.
     #[serde(skip_serializing_if = "Option::is_none")]
-    deprecated: Option<Deprecated>,
+    pub deprecated: Option<Deprecated>,
 
+    /// Example shown in UI of the value for richier documentation.
     #[serde(skip_serializing_if = "Option::is_none")]
     #[cfg(feature = "serde_json")]
-    example: Option<Value>,
+    pub example: Option<Value>,
 
+    /// Example shown in UI of the value for richier documentation.
     #[serde(skip_serializing_if = "Option::is_none")]
     #[cfg(not(feature = "serde_json"))]
-    example: Option<String>,
+    pub example: Option<String>,
 
+    /// Additional [`Xml`] formatting of the [`Object`].
     #[serde(skip_serializing_if = "Option::is_none")]
-    xml: Option<Xml>,
+    pub xml: Option<Xml>,
 }
 
 impl Object {
@@ -318,83 +476,126 @@ impl Object {
             ..Default::default()
         }
     }
+}
+
+impl From<Object> for Component {
+    fn from(s: Object) -> Self {
+        Self::Object(s)
+    }
+}
+
+impl ToArray for Object {}
+
+/// Builder for [`Object`] with chainable configuration methods to create a new [`Object`].
+#[derive(Default)]
+pub struct ObjectBuilder {
+    component_type: ComponentType,
+
+    required: Vec<String>,
+
+    properties: HashMap<String, Component>,
 
-    pub fn with_property<S: AsRef<str>, I: Into<Component>>(
+    description: Option<String>,
+
+    deprecated: Option<Deprecated>,
+
+    #[cfg(feature = "serde_json")]
+    example: Option<Value>,
+
+    #[cfg(not(feature = "serde_json"))]
+    example: Option<String>,
+
+    xml: Option<Xml>,
+}
+
+impl ObjectBuilder {
+    new!(pub ObjectBuilder);
+    
+    /// Add new property to the [`Object`]. 
+    /// 
+    /// Method accepts property name and property component as an arguments.
+    pub fn property<S: Into<String>, I: Into<Component>>(
         mut self,
         property_name: S,
         component: I,
     ) -> Self {
         self.properties
-            .insert(property_name.as_ref().to_string(), component.into());
+            .insert(property_name.into(), component.into());
 
         self
     }
 
-    pub fn with_required<S: AsRef<str>>(mut self, required_field: S) -> Self {
-        self.required.push(required_field.as_ref().to_string());
+    /// Add field to the required fields of [`Object`].
+    pub fn required<I: Into<String>>(mut self, required_field: I) -> Self {
+        self.required.push(required_field.into());
 
         self
     }
 
-    pub fn with_description<S: AsRef<str>>(mut self, description: S) -> Self {
-        self.description = Some(description.as_ref().to_string());
-
-        self
+    /// Add or change description of the property. Markdown syntax is supported.
+    pub fn description<I: Into<String>>(mut self, description: Option<I>) -> Self {
+        set_value!(self description description.map(|description| description.into()))
     }
 
-    pub fn with_deprecated(mut self, deprecated: Deprecated) -> Self {
-        self.deprecated = Some(deprecated);
-
-        self
+    /// Add or change deprecated status for [`Object`].
+    pub fn deprecated(mut self, deprecated: Option<Deprecated>) -> Self {
+        set_value!(self deprecated deprecated)
     }
 
+    /// Add or change example shown in UI of the value for richier documentation.
     #[cfg(feature = "serde_json")]
-    pub fn with_example(mut self, example: Value) -> Self {
-        self.example = Some(example);
-
-        self
+    pub fn example(mut self, example: Option<Value>) -> Self {
+        set_value!(self example example)
     }
 
+    /// Add or change example shown in UI of the value for richier documentation.
     #[cfg(not(feature = "serde_json"))]
-    pub fn with_example<I: Into<String>>(mut self, example: I) -> Self {
-        self.example = Some(example.into());
-
-        self
+    pub fn example<I: Into<String>>(mut self, example: Option<I>) -> Self {
+        set_value!(self example example.map(|example| example.into()))
     }
 
-    pub fn with_xml(mut self, xml: Xml) -> Self {
-        self.xml = Some(xml);
-
-        self
+    /// Add or change additional [`Xml`] formatting of the [`Object`].
+    pub fn xml(mut self, xml: Option<Xml>) -> Self {
+        set_value!(self xml xml)
     }
-}
+    
+    to_array_builder!();
 
-impl From<Object> for Component {
-    fn from(s: Object) -> Self {
-        Self::Object(s)
-    }
+    build_fn!(pub Object component_type, required, properties, description, deprecated, example, xml);
 }
 
-impl ToArray for Object {}
+from!(Object ObjectBuilder component_type, required, properties, description, deprecated, example, xml);
+component_from_builder!(ObjectBuilder);
 
+/// Implements [OpenAPI Reference Object][reference] that can be used to reference 
+/// reusable components.
+/// 
+/// [reference]: https://spec.openapis.org/oas/latest.html#reference-object
 #[non_exhaustive]
 #[derive(Serialize, Deserialize, Default, Clone)]
 #[cfg_attr(feature = "debug", derive(Debug))]
 pub struct Ref {
+    /// Reference location of the actual component.
     #[serde(rename = "$ref")]
-    ref_location: String,
+    pub ref_location: String,
 }
 
 impl Ref {
-    pub fn new<S: AsRef<str>>(ref_location: S) -> Self {
+    /// Construct a new [`Ref`] with custom ref location. In most cases this is not necessary 
+    /// and [`Ref::from_component_name`] could be used instead.
+    pub fn new<I: Into<String>>(ref_location: I) -> Self {
         Self {
-            ref_location: ref_location.as_ref().to_string(),
+            ref_location: ref_location.into(),
         }
     }
 
-    pub fn from_component_name<S: AsRef<str>>(component_name: S) -> Self {
-        Self::new(&format!("#/components/schemas/{}", component_name.as_ref()))
+    /// Construct a new [`Ref`] from provided component name. This will create a [`Ref`] that 
+    /// references the the reusable schemas.
+    pub fn from_component_name<I: Into<String>>(component_name: I) -> Self {
+        Self::new(&format!("#/components/schemas/{}", component_name.into()))
     }
+
+    to_array_builder!();
 }
 
 impl From<Ref> for Component {
@@ -405,27 +606,48 @@ impl From<Ref> for Component {
 
 impl ToArray for Ref {}
 
-#[non_exhaustive]
-#[derive(Serialize, Deserialize, Default, Clone)]
-#[cfg_attr(feature = "debug", derive(Debug))]
-#[serde(rename_all = "camelCase")]
-pub struct Array {
-    #[serde(rename = "type")]
-    component_type: ComponentType,
-
-    items: Box<Component>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    max_items: Option<usize>,
+builder! {
+    ArrayBuilder;
 
-    #[serde(skip_serializing_if = "Option::is_none")]
-    min_items: Option<usize>,
-
-    #[serde(skip_serializing_if = "Option::is_none")]
-    xml: Option<Xml>,
+    /// Component represents [`Vec`] or [`slice`] type  of items.
+    ///
+    /// See [`Component::Array`] for more details.
+    #[non_exhaustive]
+    #[derive(Serialize, Deserialize, Default, Clone)]
+    #[cfg_attr(feature = "debug", derive(Debug))]
+    #[serde(rename_all = "camelCase")]
+    pub struct Array {
+        /// Type will always be [`ComponentType::Array`]
+        #[serde(rename = "type")]
+        component_type: ComponentType,
+
+        /// Component representing the array items type.
+        pub items: Box<Component>,
+
+        /// Max length of the array.
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub max_items: Option<usize>,
+
+        /// Min lenght of the array.
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub min_items: Option<usize>,
+
+        /// Xml format of the array.
+        #[serde(skip_serializing_if = "Option::is_none")]
+        pub xml: Option<Xml>,
+    }
 }
 
 impl Array {
+    /// Construct a new [`Array`] component from given [`Component`].
+    ///
+    /// # Examples
+    ///
+    /// Create a `String` array component.
+    /// ```rust
+    /// # use utoipa::openapi::schema::{Component, Array, ComponentType, Property};
+    /// let string_array = Array::new(Property::new(ComponentType::String));
+    /// ```
     pub fn new<I: Into<Component>>(component: I) -> Self {
         Self {
             component_type: ComponentType::Array,
@@ -434,25 +656,38 @@ impl Array {
         }
     }
 
-    pub fn with_max_items(mut self, max_items: usize) -> Self {
-        self.max_items = Some(max_items);
-
-        self
+    /// Convert this [`Array`] to [`ArrayBuilder`].
+    pub fn to_builder(self) -> ArrayBuilder {
+        self.into()
     }
+}
 
-    pub fn with_min_items(mut self, min_items: usize) -> Self {
-        self.min_items = Some(min_items);
+impl ArrayBuilder {
+    /// Set [`Component`] type for the [`Array`].
+    pub fn items<I: Into<Component>>(mut self, component: I) -> Self {
+        set_value!(self items Box::new(component.into()))
+    }
 
-        self
+    /// Set maximun allowed lenght for [`Array`].
+    pub fn max_items(mut self, max_items: Option<usize>) -> Self {
+        set_value!(self max_items max_items)
     }
 
-    pub fn with_xml(mut self, xml: Xml) -> Self {
-        self.xml = Some(xml);
+    /// Set minimum allowed lenght for [`Array`].
+    pub fn min_items(mut self, min_items: Option<usize>) -> Self {
+        set_value!(self min_items min_items)
+    }
 
-        self
+    /// Set [`Xml`] formatting for [`Array`].
+    pub fn xml(mut self, xml: Option<Xml>) -> Self {
+        set_value!(self xml xml)
     }
+
+    to_array_builder!();
 }
 
+component_from_builder!(ArrayBuilder);
+
 impl From<Array> for Component {
     fn from(array: Array) -> Self {
         Self::Array(array)
@@ -471,15 +706,24 @@ where
     }
 }
 
+/// Represents data type of [`Component`].
 #[derive(Serialize, Deserialize, Clone)]
 #[cfg_attr(feature = "debug", derive(Debug))]
 #[serde(rename_all = "lowercase")]
 pub enum ComponentType {
+    /// Used with [`Object`] and [`ObjectBuilder`]. Objects always have 
+    /// _component_type_ [`ComponentType::Object`].
     Object,
+    /// Indicates string type of content. Typically used with [`Property`] and [`PropertyBuilder`].
     String,
+    /// Indicates integer type of content. Typically used with [`Property`] and [`PropertyBuilder`].
     Integer,
+    /// Indicates floating point number type of content. Typically used with 
+    /// [`Property`] and [`PropertyBuilder`].
     Number,
+    /// Indicates boolean type of content. Typically used with [`Property`] and [`PropertyBuilder`].
     Boolean,
+    /// Used with [`Array`] and [`ArrayBuilder`]. Indicates array type of content.
     Array,
 }
 
@@ -489,19 +733,30 @@ impl Default for ComponentType {
     }
 }
 
+/// Additional format for [`ComponentType`] to fine tune the data type used. If the **format** is not 
+/// supported by the UI it may default back to [`ComponentType`] alone.
 #[derive(Serialize, Deserialize, Clone)]
 #[cfg_attr(feature = "debug", derive(Debug))]
 #[serde(rename_all = "lowercase")]
 pub enum ComponentFormat {
+    /// 32 bit integer.
     Int32,
+    /// 64 bit integer.
     Int64,
+    /// floating point number.
     Float,
+    /// double (floating point) number.
     Double,
+    /// base64 encoded chars.
     Byte,
+    /// binary data (octec).
     Binary,
+    /// ISO-8601 full date [FRC3339](https://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14).
     Date,
+    /// ISO-8601 full date time [FRC3339](https://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14).
     #[serde(rename = "date-time")]
     DateTime,
+    /// Hint to UI to obsucre input.
     Password,
 }
 
@@ -519,41 +774,45 @@ mod tests {
             .info(Info::new("My api", "1.0.0"))
             .paths(Paths::new())
             .components(Some(
-                Components::new()
-                    .with_component("Person", Ref::new("#/components/PersonModel"))
-                    .with_component(
+                ComponentsBuilder::new()
+                    .component("Person", Ref::new("#/components/PersonModel"))
+                    .component(
                         "Credential",
-                        Object::new()
-                            .with_property(
+                        ObjectBuilder::new()
+                            .property(
                                 "id",
-                                Property::new(ComponentType::Integer)
-                                    .with_format(ComponentFormat::Int32)
-                                    .with_description("Id of credential")
-                                    .with_default(json!(1)),
+                                PropertyBuilder::new()
+                                    .component_type(ComponentType::Integer)
+                                    .format(Some(ComponentFormat::Int32))
+                                    .description(Some("Id of credential"))
+                                    .default(Some(json!(1i32))),
                             )
-                            .with_property(
+                            .property(
                                 "name",
-                                Property::new(ComponentType::String)
-                                    .with_description("Name of credential"),
+                                PropertyBuilder::new()
+                                    .component_type(ComponentType::String)
+                                    .description(Some("Name of credential")),
                             )
-                            .with_property(
+                            .property(
                                 "status",
-                                Property::new(ComponentType::String)
-                                    .with_default(json!("Active"))
-                                    .with_description("Credential status")
-                                    .with_enum_values(&[
+                                PropertyBuilder::new()
+                                    .component_type(ComponentType::String)
+                                    .default(Some(json!("Active")))
+                                    .description(Some("Credential status"))
+                                    .enum_values(Some([
                                         "Active",
                                         "NotActive",
                                         "Locked",
                                         "Expired",
-                                    ]),
+                                    ])),
                             )
-                            .with_property(
+                            .property(
                                 "history",
                                 Array::new(Ref::from_component_name("UpdateHistory")),
                             )
-                            .with_property("tags", Property::new(ComponentType::String).to_array()),
-                    ),
+                            .property("tags", Property::new(ComponentType::String).to_array()),
+                    )
+                    .build(),
             ))
             .build();
 
@@ -624,7 +883,7 @@ mod tests {
     #[test]
     fn derive_object_with_example() {
         let expected = r#"{"type":"object","example":{"age":20,"name":"bob the cat"}}"#;
-        let json_value = Object::new().with_example(json!({"age": 20, "name": "bob the cat"}));
+        let json_value = ObjectBuilder::new().example(Some(json!({"age": 20, "name": "bob the cat"}))).build();
 
         let value_string = serde_json::to_string(&json_value).unwrap();
         assert_eq!(
diff --git a/src/openapi/tag.rs b/src/openapi/tag.rs
index 9cbed0a..0737782 100644
--- a/src/openapi/tag.rs
+++ b/src/openapi/tag.rs
@@ -3,7 +3,7 @@
 //! [tag]: https://spec.openapis.org/oas/latest.html#tag-object
 use serde::{Deserialize, Serialize};
 
-use super::{add_value, build_fn, builder, external_docs::ExternalDocs, from, new};
+use super::{build_fn, builder, external_docs::ExternalDocs, from, new, set_value};
 
 builder! {
     TagBuilder;
@@ -44,16 +44,16 @@ impl Tag {
 impl TagBuilder {
     /// Add name fo the tag.
     pub fn name<I: Into<String>>(mut self, name: I) -> Self {
-        add_value!(self name name.into())
+        set_value!(self name name.into())
     }
 
     /// Add additional description for the tag.
     pub fn description<S: Into<String>>(mut self, description: Option<S>) -> Self {
-        add_value!(self description description.map(|description| description.into()))
+        set_value!(self description description.map(|description| description.into()))
     }
 
     /// Add additional external documentation for the tag.
     pub fn external_docs(mut self, external_docs: Option<ExternalDocs>) -> Self {
-        add_value!(self external_docs external_docs)
+        set_value!(self external_docs external_docs)
     }
 }
diff --git a/src/openapi/xml.rs b/src/openapi/xml.rs
index 245bc28..66f91e9 100644
--- a/src/openapi/xml.rs
+++ b/src/openapi/xml.rs
@@ -5,7 +5,7 @@ use std::borrow::Cow;
 
 use serde::{Deserialize, Serialize};
 
-use super::{add_value, build_fn, builder, from, new};
+use super::{build_fn, builder, from, new, set_value};
 
 builder! {
     /// # Examples
@@ -70,34 +70,34 @@ impl XmlBuilder {
     ///
     /// Builder style chainable consuming add name method.
     pub fn name<S: Into<Cow<'static, str>>>(mut self, name: Option<S>) -> Self {
-        add_value!(self name name.map(|name| name.into()))
+        set_value!(self name name.map(|name| name.into()))
     }
 
     /// Add [`Xml::namespace`] to xml object.
     ///
     /// Builder style chainable consuming add namespace method.
     pub fn namespace<S: Into<Cow<'static, str>>>(mut self, namespace: Option<S>) -> Self {
-        add_value!(self namespace namespace.map(|namespace| namespace.into()))
+        set_value!(self namespace namespace.map(|namespace| namespace.into()))
     }
 
     /// Add [`Xml::prefix`] to xml object.
     ///
     /// Builder style chainable consuming add prefix method.
     pub fn prefix<S: Into<Cow<'static, str>>>(mut self, prefix: Option<S>) -> Self {
-        add_value!(self prefix prefix.map(|prefix| prefix.into()))
+        set_value!(self prefix prefix.map(|prefix| prefix.into()))
     }
 
     /// Mark [`Xml`] object as attribute. See [`Xml::attribute`]
     ///
     /// Builder style chainable consuming add attribute method.
     pub fn attribute(mut self, attribute: Option<bool>) -> Self {
-        add_value!(self attribute attribute)
+        set_value!(self attribute attribute)
     }
 
     /// Mark [`Xml`] object wrapped. See [`Xml::wrapped`]
     ///
     /// Builder style chainable consuming add wrapped method.
     pub fn wrapped(mut self, wrapped: Option<bool>) -> Self {
-        add_value!(self wrapped wrapped)
+        set_value!(self wrapped wrapped)
     }
 }
diff --git a/utoipa-gen/src/component.rs b/utoipa-gen/src/component.rs
index 9e76c17..b58241d 100644
--- a/utoipa-gen/src/component.rs
+++ b/utoipa-gen/src/component.rs
@@ -53,7 +53,6 @@ impl ToTokens for Component<'_> {
         tokens.extend(quote! {
             impl #impl_generics utoipa::Component for #ident #ty_generics #where_clause {
                 fn component() -> utoipa::openapi::schema::Component {
-                    use utoipa::openapi::ToArray;
                     #variant.into()
                 }
             }
@@ -124,7 +123,7 @@ struct NamedStructComponent<'a> {
 
 impl ToTokens for NamedStructComponent<'_> {
     fn to_tokens(&self, tokens: &mut TokenStream2) {
-        tokens.extend(quote! { utoipa::openapi::Object::new() });
+        tokens.extend(quote! { utoipa::openapi::ObjectBuilder::new() });
         self.fields.iter().for_each(|field| {
             let field_name = &*field.ident.as_ref().unwrap().to_string();
 
@@ -148,18 +147,18 @@ impl ToTokens for NamedStructComponent<'_> {
             );
 
             tokens.extend(quote! {
-                .with_property(#field_name, #component)
+                .property(#field_name, #component)
             });
 
             if !component.is_option() {
                 tokens.extend(quote! {
-                    .with_required(#field_name)
+                    .required(#field_name)
                 })
             }
         });
 
         if let Some(deprecated) = get_deprecated(self.attributes) {
-            tokens.extend(quote! { .with_deprecated(#deprecated) });
+            tokens.extend(quote! { .deprecated(Some(#deprecated)) });
         }
 
         let attrs = ComponentAttr::<attr::Struct>::from_attributes_validated(self.attributes);
@@ -172,7 +171,7 @@ impl ToTokens for NamedStructComponent<'_> {
             .first()
         {
             tokens.extend(quote! {
-                .with_description(#comment)
+                .description(Some(#comment))
             })
         }
     }
@@ -211,11 +210,11 @@ impl ToTokens for UnnamedStructComponent<'_> {
             // Typically OpenAPI does not support multi type arrays thus we simply consider the case
             // as generic object array
             tokens.extend(quote! {
-                utoipa::openapi::Object::new()
+                utoipa::openapi::ObjectBuilder::new()
             });
 
             if let Some(deprecated) = deprecated {
-                tokens.extend(quote! { .with_deprecated(#deprecated) });
+                tokens.extend(quote! { .deprecated(Some(#deprecated)) });
             }
 
             if let Some(attrs) = attrs {
@@ -228,13 +227,13 @@ impl ToTokens for UnnamedStructComponent<'_> {
             .first()
         {
             tokens.extend(quote! {
-                .with_description(#comment)
+                .description(Some(#comment))
             })
         }
 
         if fields_len > 1 {
             tokens.extend(
-                quote! { .to_array().with_max_items(#fields_len).with_min_items(#fields_len) },
+                quote! { .to_array_builder().max_items(Some(#fields_len)).min_items(Some(#fields_len)) },
             )
         }
     }
@@ -285,12 +284,12 @@ impl ToTokens for SimpleEnum<'_> {
             .iter()
             .filter(|variant| matches!(variant.fields, Fields::Unit))
             .map(|variant| variant.ident.to_string())
-            .collect::<Array<String>>()
-            .into_referenced_array();
+            .collect::<Array<String>>();
 
         tokens.extend(quote! {
-            utoipa::openapi::Property::new(utoipa::openapi::ComponentType::String)
-            .with_enum_values(#enum_values)
+            utoipa::openapi::PropertyBuilder::new()
+            .component_type(utoipa::openapi::ComponentType::String)
+            .enum_values(Some(#enum_values))
         });
 
         let attrs = attr::parse_component_attr::<ComponentAttr<Enum>>(self.attributes);
@@ -299,7 +298,7 @@ impl ToTokens for SimpleEnum<'_> {
         }
 
         if let Some(deprecated) = get_deprecated(self.attributes) {
-            tokens.extend(quote! { .with_deprecated(#deprecated) });
+            tokens.extend(quote! { .deprecated(Some(#deprecated)) });
         }
 
         if let Some(comment) = CommentAttributes::from_attributes(self.attributes)
@@ -307,7 +306,7 @@ impl ToTokens for SimpleEnum<'_> {
             .first()
         {
             tokens.extend(quote! {
-                .with_description(#comment)
+                .description(Some(#comment))
             })
         }
     }
@@ -335,7 +334,7 @@ impl ToTokens for ComplexEnum<'_> {
 
         let capasity = self.variants.len();
         tokens.extend(quote! {
-            utoipa::openapi::OneOf::with_capacity(#capasity)
+            Into::<utoipa::openapi::schema::OneOfBuilder>::into(utoipa::openapi::OneOf::with_capacity(#capasity))
         });
 
         // serde, externally tagged format supported by now
@@ -350,8 +349,8 @@ impl ToTokens for ComplexEnum<'_> {
                     let name = &*variant.ident.to_string();
 
                     quote! {
-                        utoipa::openapi::schema::Object::new()
-                            .with_property(#name, #named_enum)
+                        utoipa::openapi::schema::ObjectBuilder::new()
+                            .property(#name, #named_enum)
                     }
                 }
                 Fields::Unnamed(unnamed_fields) => {
@@ -362,8 +361,8 @@ impl ToTokens for ComplexEnum<'_> {
                     let name = &*variant.ident.to_string();
 
                     quote! {
-                        utoipa::openapi::schema::Object::new()
-                            .with_property(#name, #unnamed_enum)
+                        utoipa::openapi::schema::ObjectBuilder::new()
+                            .property(#name, #unnamed_enum)
                     }
                 }
                 Fields::Unit => {
@@ -379,9 +378,9 @@ impl ToTokens for ComplexEnum<'_> {
             })
             .for_each(|inline_variant| {
                 tokens.extend(quote! {
-                    .append(#inline_variant)
+                    .item(#inline_variant)
                 })
-            })
+            });
     }
 }
 
@@ -567,13 +566,13 @@ where
             Some(GenericType::Map) => {
                 // Maps are treated just as generic objects without types. There is no Map type in OpenAPI spec.
                 tokens.extend(quote! {
-                    utoipa::openapi::Object::new()
+                    utoipa::openapi::ObjectBuilder::new()
                 });
 
                 if let Some(description) = self.comments.and_then(|attributes| attributes.0.first())
                 {
                     tokens.extend(quote! {
-                        .with_description(#description)
+                        .description(Some(#description))
                     })
                 }
             }
@@ -587,13 +586,13 @@ where
                 );
 
                 tokens.extend(quote! {
-                    #component_property.to_array()
+                    #component_property.to_array_builder()
                 });
 
                 if let Some(xml_value) = self.xml {
                     match xml_value {
                         Xml::Slice { vec, value: _ } => tokens.extend(quote! {
-                            .with_xml(#vec)
+                            .xml(Some(#vec))
                         }),
                         Xml::NonSlice(_) => (),
                     }
@@ -618,13 +617,13 @@ where
                     let component_type = ComponentType(self.component_part.ident);
 
                     tokens.extend(quote! {
-                        utoipa::openapi::Property::new(#component_type)
+                        utoipa::openapi::PropertyBuilder::new().component_type(#component_type)
                     });
 
                     let format = ComponentFormat(self.component_part.ident);
                     if format.is_known_format() {
                         tokens.extend(quote! {
-                            .with_format(#format)
+                            .format(Some(#format))
                         })
                     }
 
@@ -632,12 +631,12 @@ where
                         self.comments.and_then(|attributes| attributes.0.first())
                     {
                         tokens.extend(quote! {
-                            .with_description(#description)
+                            .description(Some(#description))
                         })
                     }
 
                     if let Some(deprecated) = self.deprecated {
-                        tokens.extend(quote! { .with_deprecated(#deprecated) });
+                        tokens.extend(quote! { .deprecated(Some(#deprecated)) });
                     }
 
                     if let Some(attributes) = self.attrs {
@@ -647,10 +646,10 @@ where
                     if let Some(xml_value) = self.xml {
                         match xml_value {
                             Xml::Slice { vec: _, value } => tokens.extend(quote! {
-                                .with_xml(#value)
+                                .xml(Some(#value))
                             }),
                             Xml::NonSlice(xml) => tokens.extend(quote! {
-                                .with_xml(#xml)
+                                .xml(Some(#xml))
                             }),
                         }
                     }
diff --git a/utoipa-gen/src/component/attr.rs b/utoipa-gen/src/component/attr.rs
index ebca947..ecdf323 100644
--- a/utoipa-gen/src/component/attr.rs
+++ b/utoipa-gen/src/component/attr.rs
@@ -362,13 +362,13 @@ impl ToTokens for Enum {
     fn to_tokens(&self, tokens: &mut TokenStream) {
         if let Some(ref default) = self.default {
             tokens.extend(quote! {
-                .with_default(#default)
+                .default(Some(#default))
             })
         }
 
         if let Some(ref example) = self.example {
             tokens.extend(quote! {
-                .with_example(#example)
+                .example(Some(#example))
             })
         }
     }
@@ -378,12 +378,12 @@ impl ToTokens for Struct {
     fn to_tokens(&self, tokens: &mut TokenStream) {
         if let Some(ref example) = self.example {
             tokens.extend(quote! {
-                .with_example(#example)
+                .example(Some(#example))
             })
         }
         if let Some(ref xml) = self.xml_attr {
             tokens.extend(quote!(
-                 .with_xml(#xml)
+                 .xml(Some(#xml))
             ))
         }
     }
@@ -393,13 +393,13 @@ impl ToTokens for UnnamedFieldStruct {
     fn to_tokens(&self, tokens: &mut TokenStream) {
         if let Some(ref default) = self.default {
             tokens.extend(quote! {
-                .with_default(#default)
+                .default(Some(#default))
             })
         }
 
         if let Some(ref example) = self.example {
             tokens.extend(quote! {
-                .with_example(#example)
+                .example(Some(#example))
             })
         }
     }
@@ -409,31 +409,31 @@ impl ToTokens for NamedField {
     fn to_tokens(&self, tokens: &mut TokenStream) {
         if let Some(ref default) = self.default {
             tokens.extend(quote! {
-                .with_default(#default)
+                .default(Some(#default))
             })
         }
 
         if let Some(ref format) = self.format {
             tokens.extend(quote! {
-                .with_format(#format)
+                .format(Some(#format))
             })
         }
 
         if let Some(ref example) = self.example {
             tokens.extend(quote! {
-                .with_example(#example)
+                .example(Some(#example))
             })
         }
 
         if let Some(ref write_only) = self.write_only {
             tokens.extend(quote! {
-                .with_write_only(#write_only)
+                .write_only(Some(#write_only))
             })
         }
 
         if let Some(ref read_only) = self.read_only {
             tokens.extend(quote! {
-                .with_read_only(#read_only)
+                .read_only(Some(#read_only))
             })
         }
     }
diff --git a/utoipa-gen/src/openapi.rs b/utoipa-gen/src/openapi.rs
index 8ac2695..a5b2982 100644
--- a/utoipa-gen/src/openapi.rs
+++ b/utoipa-gen/src/openapi.rs
@@ -269,8 +269,8 @@ fn impl_components(
     tokens: &mut TokenStream,
 ) -> Option<TokenStream> {
     if !components.is_empty() {
-        Some(components.iter().fold(
-            quote! { utoipa::openapi::Components::new() },
+        let mut components_tokens = components.iter().fold(
+            quote! { utoipa::openapi::ComponentsBuilder::new() },
             |mut schema, component| {
                 let ident = &component.ty;
                 let span = ident.span();
@@ -293,12 +293,14 @@ fn impl_components(
                     Some(ty_generics)
                 };
                 schema.extend(quote! {
-                    .with_component(#component_name, <#ident #ty_generics>::component())
+                    .component(#component_name, <#ident #ty_generics>::component())
                 });
 
                 schema
             },
-        ))
+        );
+        components_tokens.extend(quote! { .build() });
+        Some(components_tokens)
     } else {
         None
     }
@@ -306,7 +308,7 @@ fn impl_components(
 
 fn impl_paths(handler_paths: &Punctuated<ExprPath, Comma>) -> TokenStream {
     handler_paths.iter().fold(
-        quote! { utoipa::openapi::path::Paths::new() },
+        quote! { utoipa::openapi::path::PathsBuilder::new() },
         |mut paths, handler| {
             let segments = handler.path.segments.iter().collect::<Vec<_>>();
             let handler_fn_name = &*segments.last().unwrap().ident.to_string();
@@ -334,7 +336,7 @@ fn impl_paths(handler_paths: &Punctuated<ExprPath, Comma>) -> TokenStream {
             .unwrap();
 
             paths.extend(quote! {
-                .append(#usage::path(), #usage::path_item(Some(#tag)))
+                .path(#usage::path(), #usage::path_item(Some(#tag)))
             });
 
             paths
diff --git a/utoipa-gen/src/path.rs b/utoipa-gen/src/path.rs
index e79713a..a9aba04 100644
--- a/utoipa-gen/src/path.rs
+++ b/utoipa-gen/src/path.rs
@@ -395,7 +395,7 @@ impl ToTokens for Path {
                     use utoipa::openapi::ToArray;
                     utoipa::openapi::PathItem::new(
                         #path_operation,
-                        #operation.with_tag(*[Some(#tag), default_tag, Some("crate")].iter()
+                        #operation.tag(*[Some(#tag), default_tag, Some("crate")].iter()
                             .flatten()
                             .find(|t| !t.is_empty()).unwrap()
                         )
@@ -419,28 +419,26 @@ struct Operation<'a> {
 
 impl ToTokens for Operation<'_> {
     fn to_tokens(&self, tokens: &mut TokenStream2) {
-        tokens.extend(quote! { utoipa::openapi::path::Operation::new() });
+        tokens.extend(quote! { utoipa::openapi::path::OperationBuilder::new() });
 
         if let Some(request_body) = self.request_body {
             tokens.extend(quote! {
-                .with_request_body(#request_body)
+                .request_body(Some(#request_body))
             })
         }
 
         let responses = Responses(self.responses);
         tokens.extend(quote! {
-            .with_responses(#responses)
+            .responses(#responses)
         });
         if let Some(security_requirements) = self.security {
             tokens.extend(quote! {
-                .with_securities(#security_requirements)
+                .securities(Some(#security_requirements))
             })
         }
         let operation_id = self.operation_id;
         tokens.extend(quote! {
-            .with_operation_id(
-                #operation_id
-            )
+            .operation_id(Some(#operation_id))
         });
 
         let deprecated = self
@@ -449,12 +447,12 @@ impl ToTokens for Operation<'_> {
             .or(Some(Deprecated::False))
             .unwrap();
         tokens.extend(quote! {
-           .with_deprecated(#deprecated)
+           .deprecated(Some(#deprecated))
         });
 
         if let Some(summary) = self.summary {
             tokens.extend(quote! {
-                .with_summary(#summary)
+                .summary(Some(#summary))
             })
         }
 
@@ -466,14 +464,14 @@ impl ToTokens for Operation<'_> {
                 .join("");
 
             tokens.extend(quote! {
-                .with_description(#description)
+                .description(Some(#description))
             })
         }
 
         if let Some(parameters) = self.parameters {
             parameters
                 .iter()
-                .for_each(|parameter| tokens.extend(quote! { .with_parameter(#parameter) }));
+                .for_each(|parameter| tokens.extend(quote! { .parameter(#parameter) }));
         }
     }
 }
diff --git a/utoipa-gen/src/path/parameter.rs b/utoipa-gen/src/path/parameter.rs
index 58c49d0..63e46ee 100644
--- a/utoipa-gen/src/path/parameter.rs
+++ b/utoipa-gen/src/path/parameter.rs
@@ -108,22 +108,24 @@ impl Parse for Parameter {
 impl ToTokens for Parameter {
     fn to_tokens(&self, tokens: &mut TokenStream) {
         let name = &*self.name;
-        tokens.extend(quote! { utoipa::openapi::path::Parameter::new(#name) });
+        tokens.extend(quote! { 
+            utoipa::openapi::path::ParameterBuilder::from(utoipa::openapi::path::Parameter::new(#name)) 
+        });
         let parameter_in = &self.parameter_in;
-        tokens.extend(quote! { .with_in(#parameter_in) });
+        tokens.extend(quote! { .parameter_in(#parameter_in) });
 
         let deprecated: Deprecated = self.deprecated.into();
-        tokens.extend(quote! { .with_deprecated(#deprecated) });
+        tokens.extend(quote! { .deprecated(Some(#deprecated)) });
 
         if let Some(ref description) = self.description {
-            tokens.extend(quote! { .with_description(#description) });
+            tokens.extend(quote! { .description(Some(#description)) });
         }
 
         if let Some(ref parameter_type) = self.parameter_type {
             let property = Property::new(parameter_type.is_array, &parameter_type.ty);
             let required: Required = (!parameter_type.is_option).into();
 
-            tokens.extend(quote! { .with_schema(#property).with_required(#required) });
+            tokens.extend(quote! { .schema(Some(#property)).required(#required) });
         }
     }
 }
diff --git a/utoipa-gen/src/path/property.rs b/utoipa-gen/src/path/property.rs
index ae66256..fafd0f6 100644
--- a/utoipa-gen/src/path/property.rs
+++ b/utoipa-gen/src/path/property.rs
@@ -24,15 +24,13 @@ impl ToTokens for Property<'_> {
         if self.component_type.is_primitive() {
             let component_type = &self.component_type;
             let mut component = quote! {
-                utoipa::openapi::Property::new(
-                    #component_type
-                )
+                utoipa::openapi::PropertyBuilder::new().component_type(#component_type)
             };
 
             let format = ComponentFormat(self.component_type.0);
             if format.is_known_format() {
                 component.extend(quote! {
-                    .with_format(#format)
+                    .format(Some(#format))
                 })
             }
 
@@ -47,7 +45,7 @@ impl ToTokens for Property<'_> {
 
         if self.is_array {
             tokens.extend(quote! {
-                .to_array()
+                .to_array_builder()
             });
         }
     }


Test patch:
diff --git a/tests/component_derive_test.rs b/tests/component_derive_test.rs
index 8aa1fd6..91e7421 100644
--- a/tests/component_derive_test.rs
+++ b/tests/component_derive_test.rs
@@ -515,7 +515,6 @@ fn derive_complex_enum_with_named_and_unnamed_fields() {
             UnnamedFields(Foo),
         }
     };
-    dbg!(&complex_enum);
 
     common::assert_json_array_len(complex_enum.get("oneOf").unwrap(), 3);
     assert_value! {complex_enum=>
diff --git a/tests/modify_test.rs b/tests/modify_test.rs
index 2873255..922a946 100644
--- a/tests/modify_test.rs
+++ b/tests/modify_test.rs
@@ -20,12 +20,16 @@ fn modify_openapi_add_security_schema() {
 
     impl Modify for SecurityAddon {
         fn modify(&self, openapi: &mut openapi::OpenApi) {
-            openapi.components = Some(utoipa::openapi::Components::new().with_security_schemas(
-                "api_jwt_token",
-                SecuritySchema::Http(
-                    Http::new(HttpAuthenticationType::Bearer).with_bearer_format("JWT"),
-                ),
-            ))
+            openapi.components = Some(
+                utoipa::openapi::ComponentsBuilder::new()
+                    .security_schema(
+                        "api_jwt_token",
+                        SecuritySchema::Http(
+                            Http::new(HttpAuthenticationType::Bearer).with_bearer_format("JWT"),
+                        ),
+                    )
+                    .build(),
+            )
         }
     }