Why fastapi trace http method not working? - python

that's my code idk what should i put in view
TypeError: Failed to execute 'fetch' on 'Window': 'TRACE' HTTP method is unsupported.
from fastapi import FastAPI
app = FastAPI()
#app.trace("/")
def test_trace():
...

That's not a problem with your code but the browser. The TRACE HTTP method has little to no support on browsers according to MDN. And since the swagger UI page for FastAPI uses the browser to make these API calls, it may not work.
However your code is working as expected. You can check that by using curl:
(venv) ➜ curl -X TRACE http://127.0.0.1:8000
"test"% (venv) ➜
From the handler method:
#app.trace("/")
def test_trace():
return "test"

Related

Flask 400 error handler not triggered for bad HTTP request syntax

I have a flask app that receives bad requests from another software. I would like to manually handle these requests as I can then still call the relevant functions. A sample bad request looks like this GET GET / HTTP/1.1 with the additional GET in front
Hence, I tried to add a custom error handler as shown in the documentation. However, I am unable to make it work and the default error handler is used instead. This is my code:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello, World!'
#app.errorhandler(400)
def handle_bad_request(e):
print('Custom handler active')
return 'bad request!', 400
if __name__ == '__main__':
app.run()'
I used Packetsender to send similar bad requests, and Flask receives them and uses the default error handler as I can see in my console:
127.0.0.1 - - [18/Jan/2021 17:49:28] code 400, message Bad request syntax ('GET GET / HTTP/1.1')
127.0.0.1 - - [18/Jan/2021 17:49:28] "GET GET / HTTP/1.1" HTTPStatus.BAD_REQUEST
So, why is my custom error handler not used? Is this somehow related to the ridiculously incorrect syntax of the requests? Any feedback would be helpful
Error handlers are for unhandled errors in the application code. Sending a bad HTTP request causes an error at the HTTP server layer (the Werkzeug development server in your case, or an HTTP server like Nginx in production). There is no way for Flask or any other WSGI application to handle the errors you're seeing, as the request is invalid, so it doesn't make it to the application layer.

gunicorn and flask-jwt-extended not getting current user

I've been building an app that uses flask, flask_jwt_extended and the decorator #jwt_required around protected functions that need an access token to access. From these endpoints, I can use flask_jwt_extended's get_current_user function to fetch the currrent user.
This has been working fine while in development, but now I'm planning to serve a production application using gunicorn. However, when I run the gunicorn server, it seems like the get_current_user function is always returning none. For example, the following code works with python3 -m flask run, but not with gunicorn run:app -b localhost:5000. What could be the problem here?
#jwt_required
def get_user_by_id(user_id: str) -> Dict[str, Any]:
# returns user when using flask run, but not with gunicorn
curr_user = get_current_user()
Class-worker
Do you use multiple workers and sync class ?
Maybe try to look at gunicorn worker-class
If you try to use the sync worker type and set the threads setting to more than 1, the gthread worker type will be used instead.
In your python configuration file or you can change worker-class directly in the command line.
worker_class = 'gthread'
Check your JWT_SECRET_KEY
JWT_SECRET_KEY need to have the same value all over each workers

Testing a Flask app with pytest-flask + pytest-selenium (docker)

I am trying to test a Flask web app within a docker container, which is new for me. My stack is the following:
firefox
selenium
pytest-selenium
pytest-flask
Here is my Flask app file:
from flask import Flask
def create_app():
app = Flask(__name__)
return app
app = create_app()
#app.route('/')
def index():
return render_template('index.html')
Now, my test file which verifies the title of my index page:
import pytest
from app import create_app
# from https://github.com/pytest-dev/pytest-selenium/issues/135
#pytest.fixture
def firefox_options(request, firefox_options):
firefox_options.add_argument('--headless')
return firefox_options
# from https://pytest-flask.readthedocs.io/en/latest/tutorial.html#step-2-configure
#pytest.fixture
def app():
app = create_app()
return app
# from https://pytest-flask.readthedocs.io/en/latest/features.html#start-live-server-start-live-server-automatically-default
#pytest.mark.usefixtures('live_server')
class TestLiveServer:
def test_homepage(self, selenium):
selenium.get('http://0.0.0.0:5000')
h1 = selenium.find_element_by_tag_name('h1')
assert h1 == 'title'
When I run my tests with:
pytest --driver Firefox --driver-path /usr/local/bin/firefox test_app.py
I get the following error (which seems due to firefox not in headless mode).
selenium.common.exceptions.WebDriverException: Message: Service /usr/local/bin/firefox unexpectedly exited. Status code was: 1
Error: no DISPLAY environment variable specified
I am able to run firefox --headless but it seems my pytest fixture didn't manage to do the setup. Is there a better way to do this?
Now, if I replace selenium.get() by urlopen just to try the correct initialization of the app and its connection:
def test_homepage(self):
res = urlopen('http://0.0.0.0:5000')
assert b'OK' in res.read()
assert res.code == 200
I get the error:
urllib.error.URLError:
Do I need to boot the live server differently? Or should I change my host + port config somewhere?
Regarding the problem with a direct call with urllib:
Pytest's live server uses random port by default. You can add this parameter to pytest invocation:
--live-server-port 5000
Or without this parameter you can make direct calls to live server like:
import pytest
import requests
from flask import url_for
#pytest.mark.usefixtures('live_server')
def test_something():
r = requests.get(url_for('index', _external=True))
assert r.status_code == 200
I suppose you have view function called index. It would add a correct port number automatically.
But this doesn't have to do anything with docker, how do you run it?
Regarding the problem with Selenium itself - I can imagine docker networks related problem. How do you use it? Do you have eg. docker-compose configuration? Can you share it?
The referenced pytest-selenium issue has:
#pytest.fixture
def firefox_options(firefox_options, pytestconfig):
if pytestconfig.getoption('headless'):
firefox_options.add_argument('-headless')
return firefox_options
Note the - (single dash) preceding headless in add_argument()
(Source)
For late comers, it might be worthwhile taking a look at Xvfb and even more helpful can be this tutorial
Then (in Linux shell) you can enter:
Xvfb :99 &
export DISPLAY=:99
pytest --driver Firefox --driver-path /usr/local/bin/firefox test_app.py
This provides a virtual frame buffer (fake screen) for the application and it outputs all the graphical content there.
Note that I did not encountered this problem, just providing a solution that helped me overcome the mentioned error with an another app.

flask errorhandler does not work in gunicorn after introducing flask_restful

I am developing REST API in flask and plan to run it in Gunicorn.
In my appliction, an user-defined Exception was handled by by flask errorhandler decorator. It works fine in both flask build-in web server and Gunicorn. The respone can be generated from decorated function. After introducting flask_restful, the build-in server works fine, but in Gunicorn, the respone is always {"message": "Internal Server Error"}.
Here is the source code: myapp.py
from flask import Flask, jsonify, make_response
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
class OrderNotExistError(Exception):
def __init__(self, order_id):
self.message = 'Order [{order_id}] does not exist.'.format(order_id=order_id)
#app.errorhandler(OrderNotExistError)
def order_not_exist(error):
return make_response(jsonify({'message': error.message}), 404)
class OrderAPI(Resource):
def get(self, order_id):
raise OrderNotExistError(order_id)
api.add_resource(OrderAPI, '/orders/<int:order_id>', endpoint='order')
#app.route("/o/<int:order_id>")
def get_order(order_id):
raise OrderNotExistError(order_id)
if __name__ == '__main__':
app.debug = True
app.run()
Run it in Gunicorn:
gunicorn -w4 -b0.0.0.0:8000 myapp:app
Access "http://127.0.0.1:8000/o/123"
It response:
{"message": "Order [123] does not exist."}.
The error handler works fine.
Access "http://127.0.0.1:8000/orders/123"
It Response:
{"message": "Internal Server Error"}.
Seems the error handler does not work.
When run it in flask build-in server, the problem does not occur.
Does anybody meet the same problem?
Is this a bug in flask_restful or Gunicorn?
How to deal with this problem?
This is because there are two levels of error handlers one at the app level and one at the api level. You are making a direct call to the api and therefore the app does not see this. (This explains why the exception is caught for the route added through app.route and not for the one added through api.add_resource).
To catch this error, you need to override Werkzeug's exceptions which is what flask-restful uses. The following code should fix it:
errors={
'InternalServerError': {
'status': 500,
'message': 'Internal Server Error'
},
}
api = Api(app, errors=errors)
Had a similar problem (Flask app using Flask-Restplus):
with Flask build-in werkzeug, #app.errorhandler decorator works perfectly
when run with gunicorn, the default error handler is used (500, Internal Server Error). Solved by deriving Flask-Restplus class and overriding handle_error function to raise the error, letting Flask to handle it.

ProtoRPC App Engine Hello World test app not working

I have been trying to get the rather simple Hello World ProtoRPC App Engine example to work, but to no avail. The code from the website just doesn't seem to work unfortunately. I have looked at a number of possible solutions, but couldn't find a complete working set. Any help would be much appreciated! You can see the error (or lack thereof) below:
app.yaml
application: proto-test
version: 1
runtime: python27
api_version: 1
threadsafe: false
handlers:
- url: /hello.*
script: hello.py
hello.py
from protorpc import messages
from protorpc import remote
from protorpc.wsgi import service
package = 'hello'
# Create the request string containing the user's name
class HelloRequest(messages.Message):
my_name = messages.StringField(1, required=True)
# Create the response string
class HelloResponse(messages.Message):
hello = messages.StringField(1, required=True)
# Create the RPC service to exchange messages
class HelloService(remote.Service):
#remote.method(HelloRequest, HelloResponse)
def hello(self, request):
return HelloResponse(hello='Hello there, %s!' % request.my_name)
# Map the RPC service and path (/hello)
app = service.service_mappings([('/hello', HelloService)])
curl command
curl -H 'content-type:application/json' -d '{"my_name":"test1"}' http://proto-test.appspot.com/hello.hello
When I run the above command in the command line, it just returns the prompt without an error. My logs suggest that the curl command sort of worked, but it just didn't provide a response. This is what appears in the logs:
2013-05-08 22:27:07.409 /hello.hello 200 522ms 0kb curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
2620:0:10c8:1007:a800:1ff:fe00:33af - - [08/May/2013:14:27:07 -0700] "POST /hello.hello HTTP/1.1" 200 0 - "curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3" "proto-test.appspot.com" ms=523 cpu_ms=133 loading_request=1 app_engine_release=1.8.0 instance=00c61b117c66197ad84ad9bc61485b292e5129
I 2013-05-08 22:27:07.409
This request caused a new process to be started for your application, and thus caused your application code to be loaded for the first time. This request may thus take longer and use more CPU than a typical request for your application.
An Ajax call through the Chrome JS Console returned the following: SyntaxError: Unexpected token ILLEGAL:
$.ajax({url: ‘/hello.hello’, type: 'POST', contentType: 'application/json', data: ‘{ "my_name": "Bob" }’,dataType: 'json',success: function(response){alert(response.hello);}});
The Java script you posted seems to have syntax errors. Mainly, it looks like you are using the ` character in places instead of the ' character.
The reason why your request is not working is because of how you wrote the app.yaml file. You are using the old Python 2.5 way of calling applications by referring to a script rather than a WSGI application. You can correct it by changing the url handler in app.yaml to:
handlers:
- url: /hello.*
script: hello.app

Categories