Intro Présentation de FastAPI + TypeScript + OpenAPI en tant que pile technologique pour créer rapidement des applications Web avec l'apprentissage automatique et le traitement d'images comme back-end implémenté en Python.
--Je souhaite configurer rapidement un serveur Web (serveur API) avec Python ――Utilisez comme si vous utilisiez Flask jusqu'à présent
width
or w
--La plage de valeurs est «[0, w]» ou «[0, 1]»?FastAPI? https://fastapi.tiangolo.com/
--Base Starlette
Demo
Des motivations ci-dessus
―― Configurez rapidement une API
Démo de ça
Cliquez ici pour un exemple de référentiel: https://github.com/tuttieee/fastapi-typescript-openapi-example
En gros, procédez selon le tutoriel Fast API, mais il a été légèrement modifié pour ↑.
--Inclure le frontend (TypeScript) dans l'exemple pour couvrir le processus de création d'une WebApp --Développer et déployer avec Docker
Selon https://fastapi.tiangolo.com/deployment/.
/ backend
pour en faire un monorepo avec frontend.
――Afin d'ajouter la migration, etc. plus tard, creusez une autre couche et créez-la / backend / app / app
. / backend / app
est monté sur le conteneur docker
--Gérer avec docker-composeAprès docker-compose build
, docker-compose up
, essayez curl localhost: 8000
$ curl localhost:8000
{"Hello":"World"}
Exemple: https://github.com/tuttieee/fastapi-typescript-openapi-example/commit/703af24fff8d39e261e1f1ce5ba859f28e806fb2
docker-compose.devel.yml
--Monter le répertoire hôte/ start-reload.sh
comme commande de docker run pour activer le rechargement automatique ([Image Docker officielle](https://hub.docker.com/r/tiangolo/uvicorn-" option gunicorn-fastapi /))Exemple: https://github.com/tuttieee/fastapi-typescript-openapi-example/commit/33f6e91bc48c9c6396a9ceaf1e720b88c78a6822
En gros, procédez selon ↓. La partie qui utilise MySQL est ajoutée indépendamment.
https://fastapi.tiangolo.com/tutorial/sql-databases/
Pour le moment, utilisez directement le Dockerfile pour RUN pip install sqlalchemy
Exemple: https://github.com/tuttieee/fastapi-typescript-openapi-example/commit/75b7d2d7ccb8bc5a142b86bd3800b5e190732628
--Créer ʻapp / app / __ init __. Py, ʻapp / app / database.py
, ʻapp / app / models.py`
python -i
-Essayez de frapper ↓from app import models
from app.database import SessionLocal, engine
models.Base.metadata.create_all(bind=engine)
user = models.User(email='[email protected]', hashed_password='')
db = SessionLocal()
db.add(user)
db.commit()
db.close()
db = SessionLocal()
db.query(models.User).all()
Exemple: https://github.com/tuttieee/fastapi-typescript-openapi-example/commit/8f0d85445c33bfddd05466060b11501c2f3748b3
MySQL
RUN apt-get update && apt-get install -y \
default-mysql-client \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN pip install sqlalchemy PyMySQL
échantillon:
-Utiliser Image officielle. En gros, écrivez les paramètres dans docker-compose.yml
selon README
--Ajoutez des informations d'identification à .env
et passez-le en tant que variable d'environnement avec docker-compose.yml
Exemple: https://github.com/tuttieee/fastapi-typescript-openapi-example/commit/22d760d963394f340622ea402fdcf72f02cd240f
Alembic
pip install alembic
à Dockerfile
(sera-t-il converti en requirements.txt?) -> Docker-compose build
--Mettre à jour database.py
--Mise à jour de l'URL de la base de données pour MySQL
--Mettre à jour create_engine
pour MySQL (supprimer les arguments inutiles)Astuces: Vous pouvez utiliser la classe starlette telle quelle
Entrez ensuite dans le shell et procédez comme suit:
alembic init migrations
Ref: https://alembic.sqlalchemy.org/en/latest/tutorial.htmlExemple: https://github.com/tuttieee/fastapi-typescript-openapi-example/commit/979f4b3982b3ce3e7631661af3171000d6ea0381
Ref: https://alembic.sqlalchemy.org/en/latest/autogenerate.html
--Modifier ʻalembic.ini --Supprimer
sqlalchemy.url (car il provient de
database.py) --Modifier
migrations / env.py`
-Ajouté ↓
from app.models import Base
from app.database import SQLALCHEMY_DATABASE_URL
config.set_main_option("sqlalchemy.url", SQLALCHEMY_DATABASE_URL)
target_metadata = Base.metadata
--Définissez models.py
pour MySQL (spécifiez la longueur dans String
)
alembic revision --autogenerate -m "Add users and items tables"
Exemple: https://github.com/tuttieee/fastapi-typescript-openapi-example/commit/4ceae799f6f6b83ffc71cfec5ce13a669e137757
alembic upgrade head
python -i
from app import models
from app.database import SessionLocal
user = models.User(email='[email protected]', hashed_password='')
db = SessionLocal()
db.add(user)
db.commit()
db.close()
db = SessionLocal()
db.query(models.User).all()
See https://fastapi.tiangolo.com/tutorial/sql-databases/#create-initial-pydantic-models-schemas ʻApp / schemas.py` créé
See https://fastapi.tiangolo.com/tutorial/sql-databases/#crud-utils ʻApp / crud.py` créé
See https://fastapi.tiangolo.com/tutorial/sql-databases/#main-fastapi-app Mise à jour ʻApp / main.py`
Exemple: https://github.com/tuttieee/fastapi-typescript-openapi-example/commit/1e7d140c1d7929c15f7815648deb14f831807ddd
Exemple de cURL:
curl localhost:8000/users/
curl -X POST -d '{"email": "[email protected]", "password": "test"}' localhost:8000/users/
Depuis Open API http://localhost:8000/docs
MISC
prestart.sh
backend / app / app / main.py
from fastapi.routing import APIRoute
...
def use_route_names_as_operation_ids(app: FastAPI) -> None:
"""
Simplify operation IDs so that generated API clients have simpler function
names.
Should be called only after all routes have been added.
"""
for route in app.routes:
if isinstance(route, APIRoute):
route.operation_id = route.name
use_route_names_as_operation_ids(app)
Frontend Create React App
$ yarn create react-app frontend --template typescript
$ cd frontend
$ yarn start
Exemple: https://github.com/tuttieee/fastapi-typescript-openapi-example/commit/21b1f0f926132fdbf9c1dbef967ef4286fa27279
backend / app / app / main.py
# TODO: This is for development. Remove it for production.
origins = [
"<http://localhost:3000",>
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
yarn add axios
frontend / src / App.tsx
import React, { useState, useEffect } from 'react';
import './App.css';
import { DefaultApi, Configuration, User } from './api-client';
const config = new Configuration({ basePath: 'http://localhost:8000' }); // TODO: This is for dev
export const apiClient = new DefaultApi(config);
const App: React.FC = () => {
const [users, setUsers] = useState<User[]>([]);
useEffect(() => {
apiClient.readUsers().then((response) => {
setUsers(response.data);
})
})
return (
<div className="App">
<ul>
{users.map(user =>
<li key={user.id}>{user.email}</li>
)}
</ul>
</div>
);
}
export default App;
Exemple: https://github.com/tuttieee/fastapi-typescript-openapi-example/commit/79fc0bb26c6ffa7e6e43473f0ef497dd1c2f53ff
--Doit être tapé manuellement
Intro OpenAPI: ancien Swagger FastAPI générera une définition JSON pour OpenAPI: <http: // localhost: 8000 / openapi.json> Open API Generator qui mange ce JSON et génère des clients dans différentes langues
See https://openapi-generator.tech/docs/installation.html#docker
docker-compose.openapi-generator.yml
version: "3.7"
services:
openapi-generator:
image: openapitools/openapi-generator-cli
volumes:
- ./frontend:/frontend
working_dir: /frontend
command:
- generate
- -g
- typescript-axios
- -i
- <http://backend/openapi.json>
- -o
- /frontend/src/api-client
- --additional-properties=supportsES6=true,modelPropertyNaming=original
# modelPropertyNaming=original is necessary though camelCase is preferred
# See <https://github.com/OpenAPITools/openapi-generator/issues/2976>
--Ajouter une commande à Makefile
oapi/gen:
docker-compose -f docker-compose.yml -f docker-compose.openapi-generator.yml up openapi-generator \
&& docker-compose -f docker-compose.yml -f docker-compose.openapi-generator.yml rm -f openapi-generator
frontend/src/App.tsx
import React, { useState, useEffect } from 'react';
import './App.css';
import { DefaultApi, Configuration, User } from './api-client';
const config = new Configuration({ basePath: '<http://localhost:8000'> }); // TODO: This is for dev
export const apiClient = new DefaultApi(config);
const App: React.FC = () => {
const [users, setUsers] = useState<User[]>([]);
useEffect(() => {
apiClient.readUsers().then((response) => {
setUsers(response.data);
})
})
return (
<div className="App">
<ul>
{users.map(user =>
<li>{user.email}</li>
)}
</ul>
</div>
);
}
export default App;
Exemple: https://github.com/tuttieee/fastapi-typescript-openapi-example/commit/1d38242a63c9a5477fa1cde506f36f68a19060a7
Dans le projet proprement dit, Unittest, CI, Linter, etc. sont adoptés le cas échéant.
Recommended Posts