miguelgrinberg / APIFairy

A minimalistic API framework built on top of Flask, Marshmallow and friends.
MIT License
323 stars 30 forks source link

How to return an error? #49

Closed LeoVrana closed 2 years ago

LeoVrana commented 2 years ago

I don't think I could love this package any more, thank you so so much!

I'm just stuck on trying to return a failure response. I've got the authentication, request body, and success responses working fine. I just can't find in the docs exactly how I'm supposed to respond an error response (like 400, 401, etc). I was trying to follow this walkthrough to see how I can return a non-success response by making a post request to create a duplicate Thing, but I am getting the following error:

RuntimeError: The @response decorator cannot handle Response objects.

Here is my route:

@things.route('/create', methods=['POST'])
@authenticate(auth)
@body(NewThingSchema(unknown=ma.EXCLUDE))
@response(ThingSchema, status_code=201, description='Created a thing.')
@other_responses({400: "thing name already exists"})
def create_thing(args):
    db = Session()
    thing_name = args.get('thing_name')
    existing = db.query(Thing).filter_by(thing_name=thing_name).first()
    if existing:
        resp = {"err": "thing by that name already exists."}
        db.close()
        abort(400)
        ...

I could return a ThingSchema instead of abort so it would align with the regular @response, but I want to return error code with it since it's not a successful creation. I just can't figure out how to send back a response that is in the @other_responses.

How can I return a different response from the success one? Ideally one with a message.

miguelgrinberg commented 2 years ago

Yeah, the way I expected this to work is that you would either use abort(400) or raise a custom exception that is specific to the error you want to return. Then you can write an error handler that formats the response as appropriate. Have a look at errors.py in my Microblog-API project to get some inspiration.

Muhammad-Nasr commented 2 years ago

I used the same code in errors.py but I still have an issue with the response

@items.route("/items/") @response(item_schema, description="retrieve an Item by Id") @other_responses({404: 'Item not found'}) def get(id): """Retrieve an Item by id""" item = Item.query.filter_by(id=id).first_or_404() return item

when the user enter an id not exist ,

404 Not Found { "code": 404, "description": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.", "message": "Not Found" }

miguelgrinberg commented 2 years ago

@Muhammad-Nasr What issue do you have with the error response? Looks okay to me.

Muhammad-Nasr commented 2 years ago

Can I send this error to user @other_responses({404: 'Item not found'})

miguelgrinberg commented 2 years ago

@Muhammad-Nasr the other_responses decorator is only used for the OpenAPI docs. From the documentation:

This decorator does not perform any validation or formatting of error responses, it just adds the information provided to the documentation.

The error response that you are getting must be defined in a custom error handler for your Flask application. Edit that handler to use the format that you like your errors to have.

Muhammad-Nasr commented 2 years ago

Thank you @miguelgrinberg I am happy to talk to you. you are a great tutor. I learned flask from flask-Mircoblog and your book Flask Web Development. I followed React-Mega tutorial and it is a great reference for learning React. You helped me a lot

Muhammad-Nasr commented 2 years ago

I need you help If I can. I am working on a project for api. I am using apifairy for your reference. It is very good and simple. The company wants me to display a data in a format return Response({ 'result': plants_schema.dump(plants.items), 'pagination':{ 'count':plants.total, 'pages':plants.pages, 'page':plants.page,

'per_page':plants.per_page,

            # 'has_next':plants.has_next,
            # 'has_prev':plants.has_prev,
        },
        'message':"Plants retrieved successfully!"

    }), status=200)

I now can't to add pagination to my schema

{ "arrival_date": "2022-09-17 20:36Z", "id": 1, "location": "cairo", "name": "honda", "package": "yes", "price": 50.0, "quantity": 12, "status": "active",

    "total_quantity": 40,
    "type": "seeds"
},

I tried to follow your pagination decorator in microblog api but I am in a trouble. It is a high level and I can't understand well. and I am using sqlalchemy model If I could ask, If there a simple way for me I could use to solve this problem. sorry for some unclarifications.