paperclip icon indicating copy to clipboard operation
paperclip copied to clipboard

Support serde attributes

Open omid opened this issue 4 years ago • 3 comments

This code:

use actix_web::{App, HttpServer};
use paperclip::actix::{
    OpenApiExt, Apiv2Schema, api_v2_operation,
    web::{self, Json},
};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Apiv2Schema)]
struct Pet {
    #[serde(skip_serializing)]
    ser: String,
    #[serde(skip_deserializing)]
    de: String,
    #[serde(skip)]
    both: String,

    name: String,
    id: Option<i64>,
}

#[api_v2_operation]
async fn echo_pet(body: Json<Pet>) -> Result<Json<Pet>, ()> {
    Ok(body)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| App::new()
        .wrap_api()
        .service(
            web::resource("/pets")
                .route(web::post().to(echo_pet))
        )
        .with_json_spec_at("/api/spec")

        .build()
    ).bind("127.0.0.1:8081")?
        .run().await
}

generates this JSON:

{
	"swagger": "2.0",
	"definitions": {
		"Pet": {
			"type": "object",
			"properties": {
				"both": {
					"type": "string"
				},
				"de": {
					"type": "string"
				},
				"id": {
					"type": "integer",
					"format": "int64"
				},
				"name": {
					"type": "string"
				},
				"ser": {
					"type": "string"
				}
			},
			"required": ["both", "de", "name", "ser"]
		}
	},
	"paths": {
		"/pets": {
			"post": {
				"responses": {
					"200": {
						"description": "OK",
						"schema": {
							"$ref": "#/definitions/Pet"
						}
					}
				},
				"parameters": [{
					"in": "body",
					"name": "body",
					"required": true,
					"schema": {
						"$ref": "#/definitions/Pet"
					}
				}]
			}
		}
	},
	"info": {
		"version": "",
		"title": ""
	}
}

But because of the serde configurations I have, the generated JSON is wrong!

I expect to see something similar to this:

{
	"swagger": "2.0",
	"definitions": {
		"Pet1": {
			"type": "object",
			"properties": {
				"de": {
					"type": "string"
				},
				"id": {
					"type": "integer",
					"format": "int64"
				},
				"name": {
					"type": "string"
				}
			},
			"required": ["de", "name"]
		},
                "Pet2": {
			"type": "object",
			"properties": {
				"id": {
					"type": "integer",
					"format": "int64"
				},
				"name": {
					"type": "string"
				},
				"ser": {
					"type": "string"
				}
			},
			"required": ["name", "ser"]
		}
	},
	"paths": {
		"/pets": {
			"post": {
				"responses": {
					"200": {
						"description": "OK",
						"schema": {
							"$ref": "#/definitions/Pet2"
						}
					}
				},
				"parameters": [{
					"in": "body",
					"name": "body",
					"required": true,
					"schema": {
						"$ref": "#/definitions/Pet1"
					}
				}]
			}
		}
	},
	"info": {
		"version": "",
		"title": ""
	}
}

Maybe there are some better ways of handling this.

omid avatar Oct 14 '20 14:10 omid

We do support parsing some serde attributes, but we have to support the remaining serde attributes. I don't see another way, sadly 😕

wafflespeanut avatar Nov 27 '20 14:11 wafflespeanut

@omid have a look at #309. It handles the skip but I'm not sure how to handle the selective skip_serializing and skip_deserializing properly.

tiagolobocastro avatar Mar 16 '21 00:03 tiagolobocastro

@tiagolobocastro thanks, it's awesome.

Yep, the skip_serializing and skip_deserializing are harder. Since it needs to create two different definitions (for example /definitions/Pet_serialize and /definitions/Pet_deserialize, instead of just /definitions/Pet) automatically, and it seems anti-pattern for a proper API!

omid avatar Mar 16 '21 08:03 omid