FastAPI Vercel deployment not starting app - python

I can't get the API to run on Vercel, running locally works just fine.
Since it's also my first time using Vercel, I can't seem to find logs. The build logs work fine (it's telling me 6 static pages, 0 of the rest), but when I go to the deployment page it serves me a 404 (not coming from my API).
Port 8000 doesn't load anything at all.
Vercel.json
{
"version": 2,
"builds": [
{
"src": "main.py",
"use": "#vercel/python"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "app/api.py"
}
]
}
main.py
import uvicorn
from os import getenv
if __name__ == "__main__":
port = int(getenv("PORT", 8000))
uvicorn.run("app.api:app", host="0.0.0.0", port=port, reload=True)
api.py
from fastapi import FastAPI
app = FastAPI()
#app.get("/", tags=["Root"])
async def read_root():
return {"message": "Welcome to this fantastic app!"}
Project structure
app
|- models/
|- routes/
|- __init__.py
|- api.py
|- database.py
main.py
requirements.txt
Vercel.json
What am I missing here? I tried to deploy using the Vercel CLI with Vercel . and also by committing to my GitHub repo, which works. The API just doesn't seem to be running.

Related

how to debug ajax error with python and vue js?

working on a python flask app with a vue js front end. tested it my local mac book but when i try the same thing on a linux development machine, i get a ajax error. here is the set up ( directory structure below).
backend is flask app that i run with python app.py , then in the front end vue js, i have added a route and calling the backend api endpoint. not sure if there is anything different we have to do in RHEL linux.
myApp
server
app.py
requirements.txt
Client
node_modules
public
src
components
...
package.json
installed vue-cli , npm install -g #vue/cli
Vue create myapp
npm run serve
from flask import Flask
from flask_cors import CORS
# enable CORS
CORS(app, resources={r'/*': {'origins': '*'}})
app = Flask(__name__)
#app.route('/helo')
def index():
return "Hello from flask app"
if __name__ == "__main__":
app.run()
User.vue
<template>
<div>
<div class="hello">
...
</template>
<script>
import axios from "axios";
export default {
name: "Users",
data() {
return {
message: '',
},
};
},
methods: {
getUsers() {
const path = 'http://localhost:5000/hello';
axios.get(path)
.then((res) => {
this.message = msg;
})
.catch((error) => {
// eslint-disable-next-line
console.error(error);
});
}
},
created() {
this.getUsers();
}
}
</script>

Exception "No DB associated to model" when running pytest

I am developing a service with FastAPI and Tortoise-ORM.
When I use the interface generated by Swagger UI or curl, I can add and read the data successfully.
However, when I run pytest, tests fail with the following error message: tortoise.exceptions.ConfigurationError: No DB associated to model
Bearing in mind that the error only occurs when pytest is used, I believe that the problem is some configuration that is wrong or is missing from the test scripts, but I can't find the cause.
Does anyone have any ideas ?
My structure is as follows:
src /
+--api /
| +-__ init__.py
| +-app.py
| +-main.py
| +-models.py
| +-routers.py
| +-schemas.py
+--tests /
+-__ init__.py
+-test_subjects.py
The test_1.py file is as follows:
import pytest
from fastapi.testclient import TestClient
from api.main import app
client = TestClient(app)
def test_create_subject():
response = await client.post(
'/api/subject/',
json={
'name': 'Programming',
},
)
def test_read_subjects():
response = client.get("/api/subjects/")
assert response.status_code == 200
app.py:
from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise
from tortoise import Tortoise
def get_application():
_app = FastAPI(title='MyProject')
_app.add_middleware(
CORSMiddleware,
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*'],
)
return _app
app = get_application()
#app.on_event('startup')
async def startup():
register_tortoise(
app,
db_url='sqlite://db.sqlite3',
modules={'models': ['api.models']},
generate_schemas=True,
add_exception_handlers=True,
)
main.app:
import uvicorn
from .app import app
from .routers import subjects
from .schemas.subjects import SubjectSchema
app.include_router(subjects.router)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
In my case it wasn't the register_tortoise function that needed to be in the on_event('startup') function, rather another part of my code that was trying to use the db before it was initialised. I moved this piece of code (the instantiation of the class that had the query) inside an on_event('startup') block and everything started working. Basically, if you have any db queries that fire before register_tortoise, it will fail. (That's why it works with Swagger)

Flask-SocketIO making sure socket disconnects from client correctly

I added the Flask-SocketIO library to my Flask application to handle live connections and testing it with cookies being sent to the backend after the user completes a specific action. This is in case the user closes their browser or the webpage before issuing another HTTP request to the URL. I found that the browser won't save the cookie being set with document.cookie in javascript until it receives the cookie back from the server in response. Since adding the WebSocket and testing it in the development environment, the socket does emit the cookie correctly. However when I attempt to use ctrl-C in the terminal, it won't fire the signal, and even after I close the terminal and the browser/webpage, localhost is still listening on the port. I know how to manually kill the process with taskkill but my concern is that the socket connection with the client is left open after they had already closed the webpage/browser. I'm assuming this can be bad for performance on the backend and possibly cause some security risks, though I'm not sure. This might be because I'm not handling the socket connection and emitted message on the backend correctly but that's because the example code in the documentation was difficult to follow. Here is the documentation: https://flask-socketio.readthedocs.io/en/latest/.
Can someone please answer this question?
__init__.py:
from flask import Flask, url_for, current_app
from flask_socketio import SocketIO
csp = {
"default-src": [
"'self'",
'https://www.youtube.com'
],
'script-src': [ "'self'",
'https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js',
'https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js'],
'style-src': ["'self'",
'https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css'],
'img-src': ["'self'",
'data:',
'https://i.ytimg.com' ],
'font-src': ['data:']
}
config = {
"CACHE_TYPE": "simple",
"DEBUG": True,
"SQLALCHEMY_DATABASE_URI": "sqlite:///site.db",
"SQLALCHEMY_TRACK_MODIFICATIONS": False,
"SQLALCHEMY_ECHO": False
}
socketio = SocketIO()
def create_app():
app = Flask(__name__)
app.config.from_mapping(config)
socketio.init_app(app)
from flask_app.main.routes import main
app.register_blueprint(main)
with app.app_context():
db.create_all()
socketio.run(current_app)
return app
main/routes.py:
from flask import render_template, session, request, current_app, Blueprint, redirect, url_for, json, make_response
from flask_app import cache
import os
main = Blueprint("main", __name__)
#main.route("/")
def index():
return render_template("index.html", title="Home")
#main.context_processor
def inject_template_scope():
injections = dict()
# Use this method to check if the client has consented to the use of cookies.
def cookies_check():
value = request.cookies.get('consent')
return value != None
injections.update(cookies_check=cookies_check)
return injections
run.py:
from flask_app import create_app
base.html:
<html>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"
integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I="
crossorigin="anonymous"></script>
</body>
</html>
base.js:
$(window).on('load', function() {
function cookieConsent() {
var socket = io();
const now = new Date();
document.cookie = "consent=consented:true,dateTime:" + now + ",lang:" + navigator.language;
socket.on('connect', function() {
socket.emit('consent cookie', {consent_cookie: document.cookie});
});
}
}
Project Hierarchy:
project/
|_ flask_app/
|_ main/
|_ routes.py
|_ templates/
|_ base.html
|_ static/
|_ js/
|_ base.js
|_ __init__.py
|_ run.py
Environment Variables:
FLASK_APP : run.py
FLASK_ENV : development
socketio.run(app) start a development server at the port 5000.
So when you execute flask run flask calls function create_app() and expects an app. Your function however doesn't actually return app because socketio.run(app) is blocking. When you press CTRL+C it stops this line.

Python flask URL mapping issue, returning 404

-->project
--->run.py
--->config.py
--->readme.md
--->app
--->__init__.py
--->controllers
--->__init__.py
--->test_controller.py
--->model
--->__init__.py
--->test_model1.py
--->test_model2.py
run.py
from app import app
app.run(host = '0.0.0.0', port = 8080, debug = True)
config.py - All configuration variable
app/__init__.py
from flask import Flask
app = Flask(__name__)
controllers/__init__.py - Empty
controllers/test_controller.py
#app.route('/test', methods=['POST'])
def test():
return "Hello world"
When I start my server form run.py the server gets started.
But when I try the URL http://locahost:8080/test, it returns 404.
But if the route is configured in app/___init__.py it is working.
Can anyone please guide me what is incorrect here in configuration.
I want to keep the above structure, please let me know of any issues.
Unless you import the file containing the #app.route decorator, it won't be registered. Flask won't import and register all .py files automagically for you.
At the end of your __init__.py file in app/, import projectname.controllers, and import test_controller in the __init__.py file in the controllers module.

Unable to render create-react-app boilerplate views from Flask backend

I'm having a hard time integrating create-react-app single page application to my flask backend. I want to be able to make a fetch/axios call from my front end like so: axios.get('/getResults') and fetch('/getResults'). Some things I have tried but not limited to is specifying the Flask port as 3000 which is the same used by create-react-app. Also, used the proxy configuration feature on the "package.json" file of create-react-app but to no avail. I suspect my folder structure and Flask code implementation may likely be causing this. Below is my folder structure and "app.py" code. Any help I could get will be appreciated. I can provide additional information if necessary. Thanks
Project -build(contains static folder, index.html...Other meta files)-node_modules-public-srcapp.pypackage.jsonrequirements.txt
app.py:
from flask import Flask, Response, request, jsonify, make_response, send_from_directory,render_template
app = Flask(__name__, static_path='/build/static/')
app.debug=True
#app.route('/')
def root():
print('Inside root function')
return app.send_static_file('index.html')
#app.route('/getResults', methods=["GET"])
def results():
print('Inside getResults path')
return app.send_static_file('index.html')
#app.route('/postData', methods=["POST"])
def data_results():
print('Inside postData path')
data = request.get_json
return jsonify(data)
#app.route('/<path:path>')
def send_js(path):
print("inside send_js fxn")
return send_from_directory('./build/static',path)
if __name__ == "__main__":
print("inside main host call")
app.run(host='0.0.0.0', port=3000)
Errors I get when I run "python app.py" are:
On the terminal: Inside root function
127.0.0.1 - - [12/Jun/2017 09:42:24] "GET / HTTP/1.1" 404 -
On the browser:Not Found - The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
I was having the exact same issue and I was able to solve it by appeasing Flask with symlinks.
Keep the templates and static directory paths at their defaults and in the directory with your Flask main file, add these symlinks
ln -s build/ templates
ln -s build/static static
In case you were curious, this was my specific problem, which just involved a few more nested directories but was in essence the same:
Running NPM Build from Flask
You can then use Nurzhan's root configuration:
#app.route('/')
def root():
print('Inside root function')
return render_template('index.html')
But you only require your app declaration to be: app = Flask(__name__)
The only thing that doesn't work for me is the favicon, and I will update this answer once I figure that out.
In development mode, you need to configure your create-react-app package.json to forward "ajax" request to the flask server.
Here is what my package.json looks like:
{
"name": "socialite",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:8080",
"devDependencies": {
"react-scripts": "1.0.10"
},
"dependencies": {
"react": "^15.6.1",
"react-dom": "^15.6.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
See the proxy field? That's where the magic happens, replace its value with the flask server address. That way, you can take advantage of CRA hot reloading feature. This is documented at in create-react-app as "Proxying API Requests in Development"
Then do run your application, you go at localhost:3000 or whatever port yarn opens for you. And when you do an API call in javascript over the rainbow to the server for instance: fetch('/api/model/') or something nodejs' server will forward to the flask app. I think the nodejs server does look at the content-type field of the ajax request to know whether it should forward the request to the backend server or not.
I recommend you prefix all your backend routes with something like /api/v1/ or something so the nginx configuration is neat and easy to write.
I think you have a number of misunderstandings.
The create-react-app runs on its own server on port 3000 and if you try to run your flask app on the same port on the same machine it will complain that port 3000 is already in use. So from this we move to another question - the structure of your application.
Will it be a separate reactjs based client on the frontend and api based on flask in the backend which will be 2 separate applications communicating with each other over HTTP? In this case the frontend and backend will usually run on separate servers.
Or it will one flask application which will use reactjs in its template pages?
You can fix your current problem with not finding URL by changing to this in your code:
#app.route('/')
def root():
print('Inside root function')
return render_template('index.html')
And this:
template_dir = os.path.abspath('build/templates')
app = Flask(__name__, static_path='/build/static/',
template_folder=template_dir)
Since your templates folder is in the build directory.

Categories