christophergs / ultimate-fastapi-tutorial Goto Github PK
View Code? Open in Web Editor NEWThe Ultimate FastAPI Tutorial
The Ultimate FastAPI Tutorial
Thanks for what seems to be a great resource!
I'm currently struggling though it but I am encountering a strange error on first step:
https://christophergs.com/tutorials/ultimate-fastapi-tutorial-pt-1-hello-world/
Probably some stupid python thing, but I lack the background that would help me get through it, so if you have an idea...
I cloned the repo, installed poetry, seems everything is fine, but running the following line within the part-01-hello-world
folder fails:
$ poetry run ./run.sh
/usr/lib/python3/dist-packages/requests/__init__.py:89: RequestsDependencyWarning: urllib3 (1.26.16) or chardet (3.0.4) doesn't match a supported version!
warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
Creating virtualenv app-OgzSzvj8-py3.8 in /home/sk/.cache/pypoetry/virtualenvs
module 'virtualenv.create.via_global_ref.builtin.cpython.mac_os' has no attribute 'CPython2macOsFramework'
I think the warning is not critical (or is it?) but the missing attribute seems to prevent running the app.
FWIW:
$ python3 --version
Python 3.8.10
$ poetry --version
/usr/lib/python3/dist-packages/requests/__init__.py:89: RequestsDependencyWarning: urllib3 (1.26.16) or chardet (3.0.4) doesn't match a supported version!
warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
Poetry (version 1.5.1)
$ pip3 freeze | grep fastapi
fastapi==0.96.0
Any idea what I can check next?
Hi, when trying to push part 13 to Heroku, I kept getting the below error messages, which looks like an issue parsing BACKEND_CORS_ORIGINS as a json list.
I've managed to solve the issue by adding in a few json.dumps() when declaring/validating the variable - as seen below.
I'm not sure why the app was crashing on Heroku, because it was working fine locally, and I'm not yet sure if this will have any knock on effects anywhere else, but just wanted to share, to hopefully save someone else some time in the future!
Thanks for the tutorial @ChristopherGS!!
New code in config.py file:
BACKEND_CORS_ORIGINS = json.dumps([
"http://localhost:3000",
"http://localhost:8001"
])
....
@validator("BACKEND_CORS_ORIGINS", pre=True) # 3
def assemble_cors_origins(cls, v: Union[str, List[str]]) -> Union[List[str], str]:
if isinstance(v, str) and not v.startswith("["):
return json.dumps([i.strip() for i in v.split(",")])
elif isinstance(v, (list, str)):
return json.dumps(v)
raise ValueError(v)
error message I was getting:
2022-05-25T21:39:26.798355+00:00 heroku[web.1]: State changed from starting to up
2022-05-25T21:39:27.015783+00:00 app[web.1]: [2022-05-25 21:39:27 +0000] [8] [ERROR] Exception in worker process
2022-05-25T21:39:27.015790+00:00 app[web.1]: Traceback (most recent call last):
2022-05-25T21:39:27.015790+00:00 app[web.1]: File "pydantic/env_settings.py", line 172, in pydantic.env_settings.EnvSettingsSource.__call__
2022-05-25T21:39:27.015791+00:00 app[web.1]: File "/usr/local/lib/python3.9/json/__init__.py", line 346, in loads
2022-05-25T21:39:27.015791+00:00 app[web.1]: return _default_decoder.decode(s)
2022-05-25T21:39:27.015791+00:00 app[web.1]: File "/usr/local/lib/python3.9/json/decoder.py", line 337, in decode
2022-05-25T21:39:27.015792+00:00 app[web.1]: obj, end = self.raw_decode(s, idx=_w(s, 0).end())
2022-05-25T21:39:27.015792+00:00 app[web.1]: File "/usr/local/lib/python3.9/json/decoder.py", line 355, in raw_decode
2022-05-25T21:39:27.015792+00:00 app[web.1]: raise JSONDecodeError("Expecting value", s, err.value) from None
2022-05-25T21:39:27.015793+00:00 app[web.1]: json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
2022-05-25T21:39:27.015793+00:00 app[web.1]:
2022-05-25T21:39:27.015794+00:00 app[web.1]: The above exception was the direct cause of the following exception:
2022-05-25T21:39:27.015794+00:00 app[web.1]:
2022-05-25T21:39:27.015794+00:00 app[web.1]: Traceback (most recent call last):
2022-05-25T21:39:27.015795+00:00 app[web.1]: File "/usr/local/lib/python3.9/site-packages/gunicorn/arbiter.py", line 589, in spawn_worker
2022-05-25T21:39:27.015795+00:00 app[web.1]: worker.init_process()
2022-05-25T21:39:27.015795+00:00 app[web.1]: File "/usr/local/lib/python3.9/site-packages/uvicorn/workers.py", line 61, in init_process
2022-05-25T21:39:27.015795+00:00 app[web.1]: super(UvicornWorker, self).init_process()
2022-05-25T21:39:27.015795+00:00 app[web.1]: File "/usr/local/lib/python3.9/site-packages/gunicorn/workers/base.py", line 134, in init_process
2022-05-25T21:39:27.015796+00:00 app[web.1]: self.load_wsgi()
2022-05-25T21:39:27.015796+00:00 app[web.1]: File "/usr/local/lib/python3.9/site-packages/gunicorn/workers/base.py", line 146, in load_wsgi
2022-05-25T21:39:27.015796+00:00 app[web.1]: self.wsgi = self.app.wsgi()
2022-05-25T21:39:27.015796+00:00 app[web.1]: File "/usr/local/lib/python3.9/site-packages/gunicorn/app/base.py", line 67, in wsgi
2022-05-25T21:39:27.015797+00:00 app[web.1]: self.callable = self.load()
2022-05-25T21:39:27.015797+00:00 app[web.1]: File "/usr/local/lib/python3.9/site-packages/gunicorn/app/wsgiapp.py", line 58, in load
2022-05-25T21:39:27.015797+00:00 app[web.1]: return self.load_wsgiapp()
2022-05-25T21:39:27.015797+00:00 app[web.1]: File "/usr/local/lib/python3.9/site-packages/gunicorn/app/wsgiapp.py", line 48, in load_wsgiapp
2022-05-25T21:39:27.015797+00:00 app[web.1]: return util.import_app(self.app_uri)
2022-05-25T21:39:27.015798+00:00 app[web.1]: File "/usr/local/lib/python3.9/site-packages/gunicorn/util.py", line 359, in import_app
2022-05-25T21:39:27.015798+00:00 app[web.1]: mod = importlib.import_module(module)
2022-05-25T21:39:27.015798+00:00 app[web.1]: File "/usr/local/lib/python3.9/importlib/__init__.py", line 127, in import_module
2022-05-25T21:39:27.015798+00:00 app[web.1]: return _bootstrap._gcd_import(name[level:], package, level)
2022-05-25T21:39:27.015798+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
2022-05-25T21:39:27.015799+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
2022-05-25T21:39:27.015799+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
2022-05-25T21:39:27.015799+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
2022-05-25T21:39:27.015799+00:00 app[web.1]: File "<frozen importlib._bootstrap_external>", line 850, in exec_module
2022-05-25T21:39:27.015799+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
2022-05-25T21:39:27.015799+00:00 app[web.1]: File "/app/app/main.py", line 10, in <module>
2022-05-25T21:39:27.015799+00:00 app[web.1]: from app.api import deps
2022-05-25T21:39:27.015800+00:00 app[web.1]: File "/app/app/api/deps.py", line 8, in <module>
2022-05-25T21:39:27.015800+00:00 app[web.1]: from app.core.auth import oauth2_scheme
2022-05-25T21:39:27.015800+00:00 app[web.1]: File "/app/app/core/auth.py", line 9, in <module>
2022-05-25T21:39:27.015800+00:00 app[web.1]: from app.core.config import settings
2022-05-25T21:39:27.015800+00:00 app[web.1]: File "/app/app/core/config.py", line 52, in <module>
2022-05-25T21:39:27.015801+00:00 app[web.1]: settings = Settings()
2022-05-25T21:39:27.015801+00:00 app[web.1]: File "pydantic/env_settings.py", line 37, in pydantic.env_settings.BaseSettings.__init__
2022-05-25T21:39:27.015801+00:00 app[web.1]: File "pydantic/env_settings.py", line 63, in pydantic.env_settings.BaseSettings._build_values
2022-05-25T21:39:27.015801+00:00 app[web.1]: File "pydantic/env_settings.py", line 174, in pydantic.env_settings.EnvSettingsSource.__call__
2022-05-25T21:39:27.015801+00:00 app[web.1]: pydantic.env_settings.SettingsError: error parsing JSON for "BACKEND_CORS_ORIGINS"
2022-05-25T21:39:27.015961+00:00 app[web.1]: [2022-05-25 21:39:27 +0000] [8] [INFO] Worker exiting (pid: 8)
2022-05-25T21:39:27.110253+00:00 app[web.1]: [2022-05-25 21:39:27 +0000] [4] [INFO] Shutting down: Master
2022-05-25T21:39:27.110284+00:00 app[web.1]: [2022-05-25 21:39:27 +0000] [4] [INFO] Reason: Worker failed to boot.
2022-05-25T21:39:27.284599+00:00 heroku[web.1]: Process exited with status 3
2022-05-25T21:39:27.563745+00:00 heroku[web.1]: State changed from up to crashed
I get the following error below. How should I update the docker file to get this working?
Thanks.
RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | POETRY_HOME=/opt/poetry python && cd /usr/local/bin && ln -s /opt/poetry/bin/poetry && poetry config virtualenvs.create false:
#7 1.430 Retrieving Poetry metadata
#7 1.549
#7 1.555 This installer is deprecated, and scheduled for removal from the Poetry repository on or after January 1, 2023.
#7 1.555 See python-poetry/poetry#6377 for details.
#7 1.555
#7 1.555 You should migrate to https://install.python-poetry.org instead, which supports all versions of Poetry, and allows for self update
of versions 1.1.7 or newer.
#7 1.555 Instructions are available at https://python-poetry.org/docs/#installation.
#7 1.555
#7 1.555 Without an explicit version, this installer will attempt to install the latest version of Poetry.
#7 1.555 This installer cannot install Poetry 1.2.0a1 or newer (and installs will be unable to self update
to 1.2.0a1 or newer).
#7 1.555
#7 1.555 To continue to use this deprecated installer, you must specify an explicit version with --version or POETRY_VERSION=.
#7 1.555 Alternatively, if you wish to force this deprecated installer to use the latest installable release, set GET_POETRY_IGNORE_DEPRECATION=1.
#7 1.556
#7 1.556 Version 1.2.2 is not supported by this installer! Please specify a version prior to 1.2.0a1 to continue!
Hi,
I've tried to follow the instructions in README.md and I got stuck at step 3. When I type poetry run ./run.sh
in the terminal I get the following error:
OSError
[WinError 193] %1 is not a valid Win32 application
at ~\anaconda3\lib\subprocess.py:1420 in _execute_child
1416│ sys.audit("subprocess.Popen", executable, args, cwd, env)
1417│
1418│ # Start the process
1419│ try:
→ 1420│ hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
1421│ # no special security
1422│ None, None,
1423│ int(not close_fds),
1424│ creationflags,
I'm new to a poetry and I wonder whether it caused by me using windows or anacoda prompt ?
Cheers
Edit:
I've managed to run it with poetry run python ./app/main.py
command although I'm not sure if everything is setup correctly that way.
Related to issue #18 (mixing password/hashed_password ) ?
app/db/init_db.py", line 52, in init_db
user_in = schemas.UserCreate(
File "pydantic/main.py", line 406, in pydantic.main.BaseModel.init
pydantic.error_wrappers.ValidationError: 1 validation error for UserCreate
password
field required (type=value_error.missing)
Field 'id' is also not mapped/queried or is this an autoinc field somehow?
Not sure what im doing wrong, but after installing, and running ./prestart.sh
, i am getting the following error:
Traceback (most recent call last):
File "/Users/personal/ultimate-fastapi-tutorial/part-07-database/./app/backend_pre_start.py", line 3, in <module>
from tenacity import after_log, before_log, retry, stop_after_attempt, wait_fixed
ModuleNotFoundError: No module named 'tenacity'
./prestart.sh: line 7: alembic: command not found
Traceback (most recent call last):
File "/Users/personal/ultimate-fastapi-tutorial/part-07-database/./app/initial_data.py", line 3, in <module>
from app.db.base import Base
ModuleNotFoundError: No module named 'app'
All i did was cloning the repo, going into one of the parts, and running poetry install.
/personal/ultimate-fastapi-tutorial/part-07-database main stock-lc ❯ poetry install 17:31:09
Installing dependencies from lock file
Package operations: 1 install, 20 updates, 0 removals
• Updating dnspython (2.2.1 -> 2.1.0)
• Updating greenlet (2.0.1 -> 1.1.2)
• Updating idna (3.4 -> 3.2)
• Updating markupsafe (2.1.1 -> 2.0.1)
• Updating typing-extensions (4.4.0 -> 3.10.0.0)
• Updating click (8.1.3 -> 7.1.2)
• Updating email-validator (1.3.0 -> 1.1.3)
• Updating h11 (0.14.0 -> 0.9.0)
• Updating httptools (0.5.0 -> 0.1.2)
• Updating mako (1.2.4 -> 1.1.4)
• Updating pydantic (1.10.2 -> 1.8.2)
• Installing python-editor (1.0.4)
• Updating sqlalchemy (1.4.44 -> 1.4.22)
• Updating starlette (0.22.0 -> 0.14.2)
• Updating uvloop (0.17.0 -> 0.15.3)
• Updating websockets (10.4 -> 8.1)
• Updating alembic (1.8.1 -> 1.6.5)
• Updating fastapi (0.88.0 -> 0.68.0)
• Updating jinja2 (3.1.2 -> 3.0.1)
• Updating tenacity (8.1.0 -> 8.0.1)
• Updating uvicorn (0.20.0 -> 0.11.8)
Installing the current project: app (0.0.1)
And yes, even after manually installing tenacity
, it still throws that error
Amazing blog series. Really helped a lot clear some basics about FastAPI.
I shifted my project from Flask to FastAPI and noticed some latency issues with database calls
(earlier using Flask-SQLAlchemy) with MySQL.
Although FastAPI is faster than Flask in serving the requests, but when it comes to making the database calls, which eventually every production app would run into, using FastAPI with SQLAlchemy as a dependency injection or even as a middleware, especially with a Synchronous SQLAlchemy flavor does cause some troubles in production.
Thought you might wanna look into this before Dependency post comes out.
A common approach followed to use the new SQLAlchemy 1.4 by many is :
engine_async = create_async_engine(SQLALCHEMY_DATABASE_URL)
async_session = sessionmaker(
engine_async,
expire_on_commit=False,
autocommit=False,
autoflush=False,
class_=AsyncSession,
)
@app.get("/users/insert-data-to-test")
async def insert_data_to_test():
async with async_session() as session:
async with session.begin():
user = User()
user.email = "[email protected]"
session.add(user)
session.commit()
I know SQLAlchemy Async i.e. 1.4 is still in Alpha, but looks promising in terms of avoiding some production related issues with synchronous session.
Would love to hear your comments or analysis in upcoming episodes of the blog series.
When building the example DB with Alembic the User table has a field 'password', but the code which fills the database assumes the field to be called 'hashed_password'. (part 10)
When not using Alembic by uncommenting a line in db/init_db.py I get an error about not recognizing Base which is not(?) imported although mentioned in init.py
SO, great tutorial, but I believe there is a mistake in the JWT part in
https://christophergs.com/tutorials/ultimate-fastapi-tutorial-pt-10-auth-jwt/
When you create an JWT you put in the user id underneath SUB
And when I go to the endpoint /me
you use the same sub (with user id) to put it in username and try to search for a username that is actually a user id.
Or is there something I do not see?
I am trying to use this code on Debian Stable. I created a virtualenv whoch uses Python 3.9.2. The importing mechanism is no longer compatible with the code. Adding paths helps. So at various locations I added:
import sys,os
sys.path.append("..") # fix py2/py relative path issue
p = os.path.abspath(".")
sys.path.insert(1, p)
It's a great project setup & learning strategy you shared. But it would be nice if you could also add a testing procedure for this project.
First of all thanks for putting this tutorial together. Very helpful.
I came across an issue with the CRUDBase class when trying to create my own models.
If you have a date column, the jsonable_encode converts a datetime.date object to a str. This dosen't work when you pass the kwargs to the sqlalchemy model class.
def create(self, db: Session, *, obj_in: CreateSchemaType) -> ModelType:
obj_in_data = jsonable_encoder(obj_in)
db_obj = self.model(**obj_in_data) # type: ignore
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
TypeError: SQLite Date type only accepts Python date objects as input.
I fixed it by simply calling the .dict() method on the pydantic model.
def create(self, db: Session, *, obj_in: CreateSchemaType) -> ModelType:
db_obj = self.model(**obj_in.dict()) # type: ignore
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
I took a look at the documentation for FastAPI about jsonable_encoders and it mentioned that it's not really to be used with a date formats.
I'm just curious, what is the utility of jsonable_encoders, and why would you use it.
Hi Chris,
Thank you so much creating this course. As I'm going through the material, I realize the dependencies installation now will have issues with the super old version of SQLAlchemy. I have personally updated the dependencies to make it work on my m2 mac, it would be good to update those dependencies in the repo for people to have the latest version of codebase. I could also help you do it if necessary.
Thanks,
Bowen
Running "poetry run ./prestart.sh" when on tutorial step 7 (https://christophergs.com/tutorials/ultimate-fastapi-tutorial-pt-7-sqlalchemy-database-setup/) fails with the following error message infinitely repeating:
INFO:__main__:Initializing service INFO:__main__:Starting call to '__main__.init', this is the 1st time calling it. ERROR:__main__:(sqlite3.OperationalError) unable to open database file (Background on this error at: https://sqlalche.me/e/14/e3q8) WARNING:__main__:Finished call to '__main__.init' after 0.000(s), this was the 1st time calling it. INFO:__main__:Starting call to '__main__.init', this is the 2nd time calling it. ERROR:__main__:(sqlite3.OperationalError) unable to open database file (Background on this error at: https://sqlalche.me/e/14/e3q8) WARNING:__main__:Finished call to '__main__.init' after 1.002(s), this was the 2nd time calling it. INFO:__main__:Starting call to '__main__.init', this is the 3rd time calling it.
Following the advice in the "Unable to run the server on Windows #28" issue, I tried running "python3 ./app/backend_pre_start.py" by itself and received the same errors as shown above.
Note that at the time I tried running this first, I did not have SQLite installed on my WSL2 Ubuntu. So I installed SQLite, to see if that makes a difference. It did not.
One additional thing I noticed: after the initial cloning of the git repo, all the source files are read only, and the directories are too. Could that be the issue here?
Just a small issue to tell you to update the link on your webpage ( https://christophergs.com/tutorials/ultimate-fastapi-tutorial-pt-6-jinja-templates/).. It gives not found... Nothing much just telling you :) @ChristopherGS
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.