I am building an api with flask_restplus. How the user gets/gives the data, is different of how is defined in my Models. This was easily solved with response marshalling https://flask-restplus.readthedocs.io/en/stable/marshalling.html#renaming-attributes
As I see it, the decorator @marshal_with()
marshals the output response, but not the input (at least if the input and output models are different).
I was able to "rename" the input given by the user in a get
calls by using the parser = reqparse.RequestParser()
and parser.add_argument()
, because the parser.parse_args()
also does the "renaming". The problem comes to the post
calls:
For the post
calls, I cannot use the reqparse
because the swagger documentation does not look well (How to document the post body using flask-ReSTplus?).
Therefore I use a @expect()
with the model I expect, but the expect
does not rename the input json (simply validates). So what I have to end up doing is creating an additional Model and use marshal_with(api.payload)
before managing the data. I however find it quite dirty because I need 3 models for one post call:
ModelResponse
ModelExpected
ModelRename
Example
Let me put it in an example: in the internal system I call the fields as user_name
and user_age
but the client gets/gives the fields as name
and age
, then I have to:
# define the response model (includes the user id)
UserResponse = api.model("userResponse",
{
"name": fields.String(description="name of the user", attribute="user_name", required=True),
"age": fields.String(description="age of the user", attribute="user_age"),
"user_id": fields.String(description="User ID", required=True, attribute="user_id")
}
# define the expected model (to validate the input)
UserExpectPost = api.model("userExpectPost",
{
"name": fields.String(description="name of the user", attribute="user_name", required=True),
"age": fields.String(description="age of the user", required=True, attribute="user_age")
}
# define the model again, reverse from UserExpectPost (to rename the input attributes)
UserPostRename = api.model("userPostRename",
{
"user_name": fields.String(description="name of the user", attribute="name", required=True),
"user_age": fields.String(description="age of the user", required=True, attribute="age")
}
class Users(Resource):
@api.marshal_with(UserResponse)
@api.expect(UserExpectPost)
def post(self):
data = marshal(api.payload, UserPostRename)
# do stuff
return # return whatever will be marshalled with UserResponse
Question
So, the question is, is there a way that I can do it with just 2 models? (just responseModel and inputModel). I would need something like the expect()
but that also renames the attributes from the payload.