Flask and Swagger UI does not work? - python

I am trying to create a RESTful app using Flask and swagger. But when I run the endpoint I do not see the methods documented in the browser like described here for example http://michal.karzynski.pl/blog/2016/06/19/building-beautiful-restful-apis-using-flask-swagger-ui-flask-restplus/
Instead just the 404 not found error. Here is my code:
def init_deserializer_restful_api():
# Get port number for the web app.
PORT = 8000
# Initiate the Flask app
app = Flask(__name__)
Swagger(app)
CORS(app)
# Handler for deserializer
#app.route("/deserialize", methods=['POST','GET'])
def handle_deserialization_request():
# Method description
# Method content
App is run like this:
app.run(port=PORT, host="0.0.0.0")
I run http://localhost:8000/deserializer I get The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
Questions:
1. How do I feed flask the request.json it requires?
2. How do I get swagger to work?

try localhost:8000/apidocs/index.html
Explanation
This is the default endpoint of Swagger. What you were trying to do is accessing one endpoint of your API and expecting it to render the Swagger UI. Swagger UI is an ADDITIONAL endpoint to your API which lists and lets you try all other endpoints. Hope that helps!

Related

How to change the Redirect URI from HTTP to HTTPS within a FastAPI web app using fastapi_msal?

I am trying to setup Azure AD authentication for a web application using FastAPI. I am using the fastapi_msal python package to do this. The problem I am having is that when I go to the web app, I am able to login, but once i am authenticated, it says the redirect URI that the application is using begins with HTTP. However, Azure requires the redirect uri begin with HTTPS unless running the app locally. Does anyone know how I can change the redirect uri to begin with https instead?
The code for my project pretty much exactly resembles the code from this example project here. However, I have found a similar project using Flask instead of FastAPI. And there is a specific portion of the code that addresses this redirect uri problem:
# This section is needed for url_for("foo", _external=True) to automatically
# generate http scheme when this sample is running on localhost,
# and to generate https scheme when it is deployed behind reversed proxy.
# See also https://flask.palletsprojects.com/en/1.0.x/deploying/wsgi-standalone/#proxy-setups
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)
Does anyone know how I can do something like this for a web app using FastAPI instead?
The full source code for the Flask app can be found here

Can't serve swagger on remotely hosted server with different url

I'm trying to serve some simple service using flask and flask_restx (a forked project of flask-restplus, that would be eventually served on AWS.
When it is served, I want to generate swagger page for others to test it easily.
from flask import Flask
from flask_restx import Api
from my_service import service_namespace
app = Flask(__name__)
api = Api(app, version='1.0')
api.add_namespace(service_namespace)
if __name__ == '__main__':
app.run(debug=True)
When I test it locally (e.g. localhost:5000), it works just fine. Problem is, when it is hosted on AWS, because it has a specific domain (gets redirected?) (e.g. my-company.com/chris-service to a container), the document page is unable to find its required files like css and so:
What I've looked and tried
Python (Flask + Swagger) Flasgger throwing 404 error
flask python creating swagger document error
404 error in Flask
Also tried adding Blueprint (albeit without knowing exactly what it does):
app = Flask(__name__)
blueprint = Blueprint("api", __name__,
root_path="/chris-service",
# url_prefix="/chris-service", # doesn't work
)
api = Api(blueprint)
app.register_blueprint(blueprint)
...
And still no luck.
Update
So here's more information as per the comments (pseudo, but technically identical)
Access point for the swagger is my-company.com/chris (with or without http:// or https:// doesn't make difference)
When connecting to the above address, the request URL for the assets are my-company.com/swaggerui/swagger-ui.css
You can access the asset in my-company.com/chris/swaggerui/swagger-ui.css
So I my resolution (which didn't work) was to somehow change the root_path (not even sure if it's the correct wording), as shown in What I've looked and tried.
I've spent about a week to solve this but can't find a way.
Any help will be greatful :) Thanks
Swagger parameters defined at apidoc.py file. Default apidoc object also created in this file. So if you want to customize it you have change it before app and api initialization.
In your case url_prefix should be changed (I recommend to use environment variables to be able set url_prefix flexibly):
$ export URL_PREFIX='/chris'
from os import environ
from flask import Flask
from flask_restx import Api, apidoc
if (url_prefix := environ.get('URL_PREFIX', None)) is not None:
apidoc.apidoc.url_prefix = url_prefix
app = Flask(__name__)
api = Api(app)
...
if __name__ == '__main__':
app.run()
Always very frustrating when stuff is working locally but not when deployed to AWS. Reading this github issue, these 404 errors on swagger assets are probably caused by:
Missing javascript swagger packages
Probably not the case, since flask-restx does this for you. And running it locally should also not work in this case.
Missing gunicorn settings
Make sure that you are also setting gunicorn up correctly as well with
--forwarded-allow-ips if deploying with it (you should be). If you are in a kubernetes cluster you can set this to *
https://docs.gunicorn.org/en/stable/settings.html#forwarded-allow-ips
According to this post, you also have to explicitly set
settings.FLASK_SERVER_NAME to something like http://ec2-10-221-200-56.us-west-2.compute.amazonaws.com:5000
If that does not work, try to deploy a flask-restx example, that should definetely work. This rules out any errors on your end.

How to obtain the caller's IP address in Flask/Connexion?

I'm using an OpenAPI 3.0 specification (swagger.yml) and use Swagger Codegen to create the corresponding Python Flask application stubs. This is how I run the application to expose my Swagger API:
app = connexion.App(__name__, specification_dir='./swagger/')
app.app.json_encoder = encoder.JSONEncoder
app.add_api('swagger.yaml', arguments={'title': 'My Test API'})
# add CORS support to send Access-Control-Allow-Origin header
CORS(app.app)
So far so good. The application logic is handled within the generated Python stubs which are linked by the x-openapi-router-controller: swagger_server.controllers.user_controller.
I now however need to access HTTP Request specific information within the application itself to for example react differently based on the HTTP_CLIENT_IP address
How can I obtain that information within my controller endpoint?
Use Flask's request context.
For example, to get the HTTP_CLIENT_IP, use:
from flask import request
http_client_ip = request.remote_addr
You can read more about request here.
Attached two related links addressing the same issue on request header parameters and how connexion does not forward them to custom controllers. I ended up manually accessing them via
access_token = connexion.request.headers['access_token']

How to pass URLs as parameters in a GET request within python flask (restplus)?

I am creating a REST API using python flask. The API is ready and works on port number 8000 of my localhost. Now I intend to give this REST API a user friendly interface for which I decided to go with python - restplus. I thought of calling this service (running on 8000) internally from swagger application running on 5000
I was able to create the basic structure of the API (Swagger). The code for which looks like this:
import flask
from flask import Flask, request
from flask_restplus import Resource, Api
app = Flask(__name__)
api = Api(app)
#api.route('/HybridComparator/<string:url2>/<string:url1>')
class HybridComparator(Resource):
def get(self, url1, url2):
print(url1)
print(url2)
return url1 + ' ' + url2
if __name__ == '__main__':
app.run(debug=True)
The application as a whole runs seamlessly (with random strings as parameters) on port 5000. But when the URLs I pass are actual links, the application returns a response of 404 - Not found. Further to my investigation I realized the culprit being '/' embedded within the links I try to provide. Is there a way to handle URLs in particular?
Should I encode them before sending a request. (This will make my parameters look ugly). Is there something I am missing?
This is an entirely old question and I am sure you solved your problem by now.
But for new searchers, this may come in handy;
replace <string:url2>/<string:url1> with <path:url2>/<path:url1>
it seems that :
#api.route('/HybridComparator/<path:url2>/<path:url1>')
should fix it ,it fixes the 404 but i am getting only "http:/" part of the param

Routes With Custom Domains Using Flask

My web app assigns a subdomain to users and optionally allows them to use a custom domain. This works except when the user visits their custom domain for a route without including a trailing slash.
GET requests to this url works as expected: http://user.example.com:5000/book/12345/
GET requests to this url works as expected: http://custom.com:5000/book/12345/
GET requests to this url attempt to redirect, but fail: http://custom.com:5000/book/12345
Flask ends up redirecting the browser to this url which, of course, doesn't work: http://<invalid>.example.com:5000/book/12345/
Is there a different way that I should handle custom domains? Here's a complete minimal example to reproduce this. I have set custom.com, example.com. and user.example.com to point to 127.0.0.1 in my /etc/hosts file in my development environment so that Flask receives the request.
from flask import Flask
app = Flask(__name__)
server = app.config['SERVER_NAME'] = 'example.com:5000'
#app.route('/', subdomain="<subdomain>")
#app.route('/')
def index(subdomain=None):
return ("index")
#app.route('/book/<book_id>/', subdomain="<subdomain>")
#app.route('/book/<book_id>/')
def posts(post_id, subdomain=None):
return (book_id)
if __name__ == '__main__':
app.run(host='example.com', debug=True)
I'm not sure that's possible. host matching and subdomain matching are mutually exclusive (look at host matching parameter).
I'd love to be wrong though.
One way around this issue that I can think of is to use something in front of Flask (say nginx) that points custom.com to custom.com._custom.example.com or something like that. In your code you could create a custom url_for function that would recognize this as a custom domain. I would ask on the Flask mailing list as they would be able to give you a solid answer.

Categories