Repository: wafflespeanut/paperclip (rust)

Issue:
Actix: type alias makes Option<T> required
Having a schema like this:
```rust
type Email = Option<String>;

#[derive(Apiv2Schema, Serialize)]
struct User {
    id: i32,
    username: String,
    email: Email,
}
```

The `email` field is optional, but in the generated spec it is shown as required (`"required":["email","id","username"]`)

Full code:
```rust
use actix_web::{App, HttpServer};
use paperclip::actix::web::{self, Json};
use paperclip::actix::{api_v2_operation, Apiv2Schema, OpenApiExt};
use serde::Serialize;

type Email = Option<String>;

#[derive(Apiv2Schema, Serialize)]
struct User {
    id: i32,
    username: String,
    email: Email,
}

#[api_v2_operation]
async fn example() -> Json<User> {
    Json(User {
        id: 1,
        username: "john".into(),
        email: None,
    })
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .wrap_api()
            .route("/", web::get().to(example))
            .with_json_spec_at("/api/spec")
            .build()
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}
```

Cargo.toml:
```toml
[dependencies]
actix-web = "3"
paperclip = { git = "https://github.com/wafflespeanut/paperclip", features = ["actix"] }
serde = { version = "1.0", features=["derive"] }
```

Pull request:
Fix optional type aliases
Fix #257

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index be3c97d7..0f121ebe 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Changed
 
 ### Fixed
+- Optional type aliases like `type Email = Option<String>` will not be added to the `required` fields.
 
 ## [0.5.0] - 2020-11-28
 ### Added
diff --git a/core/src/v2/schema.rs b/core/src/v2/schema.rs
index 9388c151..18f18e01 100644
--- a/core/src/v2/schema.rs
+++ b/core/src/v2/schema.rs
@@ -250,6 +250,9 @@ pub trait Apiv2Schema {
     /// Description of this schema. In case the trait is derived, uses the documentation on the type.
     const DESCRIPTION: &'static str = "";
 
+    /// Indicates the requirement of this schema.
+    const REQUIRED: bool = true;
+
     /// Returns the raw schema for this object.
     fn raw_schema() -> DefaultSchemaRaw {
         Default::default()
@@ -304,6 +307,7 @@ impl<T: TypedData> Apiv2Schema for T {
 #[cfg(feature = "nightly")]
 impl<T> Apiv2Schema for Option<T> {
     default const NAME: Option<&'static str> = None;
+    default const REQUIRED: bool = false;
 
     default fn raw_schema() -> DefaultSchemaRaw {
         Default::default()
@@ -316,6 +320,7 @@ impl<T> Apiv2Schema for Option<T> {
 
 impl<T: Apiv2Schema> Apiv2Schema for Option<T> {
     const NAME: Option<&'static str> = T::NAME;
+    const REQUIRED: bool = false;
 
     fn raw_schema() -> DefaultSchemaRaw {
         T::raw_schema()
diff --git a/macros/src/actix.rs b/macros/src/actix.rs
index 46e30993..0cdcfcee 100644
--- a/macros/src/actix.rs
+++ b/macros/src/actix.rs
@@ -769,29 +769,15 @@ fn add_optional_impl(name: &Ident, generics: &Generics) -> proc_macro2::TokenStr
     }
 }
 
-fn get_field_type(field: &Field) -> (Option<proc_macro2::TokenStream>, bool) {
-    let mut is_required = true;
+fn get_field_type(field: &Field) -> Option<proc_macro2::TokenStream> {
     match field.ty {
-        Type::Path(ref p) => {
-            let ty = p
-                .path
-                .segments
-                .last()
-                .expect("expected type for struct field");
-
-            if p.path.segments.len() == 1 && &ty.ident == "Option" {
-                is_required = false;
-            }
-
-            (Some(address_type_for_fn_call(&field.ty)), is_required)
-        }
-        Type::Reference(_) => (Some(address_type_for_fn_call(&field.ty)), is_required),
+        Type::Path(_) | Type::Reference(_) => Some(address_type_for_fn_call(&field.ty)),
         _ => {
             emit_warning!(
                 field.ty.span().unwrap(),
                 "unsupported field type will be ignored."
             );
-            (None, is_required)
+            None
         }
     }
 }
@@ -799,9 +785,8 @@ fn get_field_type(field: &Field) -> (Option<proc_macro2::TokenStream>, bool) {
 /// Generates code for a tuple struct with fields.
 fn handle_unnamed_field_struct(fields: &FieldsUnnamed, props_gen: &mut proc_macro2::TokenStream) {
     let field = fields.unnamed.iter().next().unwrap();
-    let (ty_ref, _) = get_field_type(&field);
 
-    if let Some(ty_ref) = ty_ref {
+    if let Some(ty_ref) = get_field_type(&field) {
         props_gen.extend(quote!({
             schema = #ty_ref::raw_schema();
         }));
@@ -877,7 +862,7 @@ fn handle_field_struct(
             field_name = prop.rename(&field_name);
         }
 
-        let (ty_ref, is_required) = get_field_type(&field);
+        let ty_ref = get_field_type(&field);
 
         let docs = extract_documentation(&field.attrs);
         let docs = docs.trim();
@@ -897,11 +882,11 @@ fn handle_field_struct(
             })
         };
 
-        if is_required {
-            gen.extend(quote! {
+        gen.extend(quote! {
+            if #ty_ref::REQUIRED {
                 schema.required.insert(#field_name.into());
-            });
-        }
+            }
+        });
 
         props_gen.extend(gen);
     }


Test patch:
diff --git a/tests/test_app.rs b/tests/test_app.rs
index 68a09332..1db3f576 100644
--- a/tests/test_app.rs
+++ b/tests/test_app.rs
@@ -24,6 +24,8 @@ use uuid_dev::Uuid;
 static CLIENT: Lazy<reqwest::blocking::Client> = Lazy::new(|| reqwest::blocking::Client::new());
 static PORTS: Lazy<Mutex<HashSet<u16>>> = Lazy::new(|| Mutex::new(HashSet::new()));
 
+type OptionalUuid = Option<uuid_dev::Uuid>;
+
 #[derive(Deserialize, Serialize, Apiv2Schema)]
 #[serde(rename_all = "lowercase")]
 enum PetClass {
@@ -44,7 +46,7 @@ struct Pet {
     birthday: chrono_dev::NaiveDate,
     updated_on: Option<chrono_dev::NaiveDateTime>,
     #[serde(rename = "uuid")]
-    uid: Option<uuid_dev::Uuid>,
+    uid: OptionalUuid,
 }
 
 impl Default for Pet {