Search code examples
pythonflaskflask-restful

Flask: The browser (or proxy) sent a request that this server could not understand


I created a small Flask service. However each time I tried to use the say-hi endpoint, I get the following message:

{
    "message": "The browser (or proxy) sent a request that this server could not understand."
}

My Flask service looks like this:

from flask import Flask, request
from flask_restful import Resource, Api, abort, reqparse

app = Flask(__name__)
api = Api(app)

class HelloResource(Resource):
    def get(self):
        return { 'message': 'Hello' }

class SayHiResource(Resource):
    def get(self):
        parser = reqparse.RequestParser()
        parser.add_argument('name', required=True, help='Name cannot be blank')
        args = parser.parse_args()

        return { 'message': 'Hello ' + args['name'] }

api.add_resource(HelloResource, '/hello')
api.add_resource(SayHiResource, '/say-hi')

if __name__ == '__main__':
    app.run(debug=True, load_dotenv=True)

However, there is not much information about why is failing.

The way I'm running is by using gunicorn and the serviceEntrypoint.py file, which only has this content:

from src.api.service import app

if __name__ == '__main__':
    app.run()

Here is my folder structure

.
├── requirements.txt
├── serviceEntrypoint.py
└── src
    ├── __init__.py
    └── api
        ├── __init__.py
        └── service.py

Why the /hello ending works, but the say-hi doesn't when I call to http://localhost:8000/say-hi?name=John?


Solution

  • if you run the flask debug server and issue your HTTP request http://localhost:8000/say-hi?name=John, you will see that the actual error is:

    message "Did not attempt to load JSON data because the request Content-Type was not 'application/json'."
    

    There is documentation and examples here, but it boils down to choosing if the request should be a GET or a POST. The way you structured your request - you are passing 1 field only, the username - it looks like a GET, in this case you should have:

    api.add_resource(SayHiResource, '/say-hi/<username>')
    

    and class:

    class SayHiResource(Resource):
        def get(self, username):
            return { 'message': 'Hello ' + username }
    

    if you want to implement a POST request, please trace in the documentation the example that is triggered by the call: curl http://localhost:5000/todos -d "task=something new" -X POST -v

    Update:

    for using query parameters, you can use the request.args:

    api.add_resource(SayHiResource, '/say-hi')
    

    class:

    class SayHiResource(Resource):
        def get(self):
            username = request.args.get("username")
            status = request.args.get("status")
            # print(query_args)
            return { 'message': 'Hello {}, your status is: {}'.format(username, status) }
    

    example:

    [http_offline@greenhat-35 /tmp/] > curl 'http://localhost:8000/say-hi?username=lala&status=enabled'
    {
        "message": "Hello lala, your status is: enabled"
    }
    [http_offline@greenhat-35 /tmp/] >