Anda mungkin pernah mendengar tentang keluaran terbaru Flama 1.7, yang membawa beberapa ciri baharu yang menarik untuk membantu anda dengan pembangunan dan pengeluaran API ML anda. Siaran ini dikhaskan dengan tepat kepada salah satu sorotan utama keluaran itu: Sokongan untuk Reka Bentuk Dipacu Domain. Tetapi, sebelum kami menyelami butiran dengan contoh langsung, kami mengesyorkan anda untuk mengingati sumber berikut (dan, biasakan diri dengannya jika anda belum melakukannya):
Sekarang, mari kita mulakan dengan ciri baharu dan lihat cara anda boleh memanfaatkannya untuk membina API ML yang mantap dan boleh diselenggara.
Siaran ini berstruktur seperti berikut:
Dalam pembangunan perisian moden, menyelaraskan logik perniagaan dengan reka bentuk teknikal aplikasi adalah penting. Di sinilah Reka Bentuk Dipacu Domain (DDD) bersinar. DDD menekankan membina perisian yang mencerminkan domain teras perniagaan, memecahkan masalah kompleks dengan mengatur kod di sekitar konsep perniagaan. Dengan berbuat demikian, DDD membantu pembangun untuk mencipta aplikasi yang boleh diselenggara, berskala dan teguh. Dalam perkara berikut, kami memperkenalkan perkara yang kami anggap sebagai konsep DDD yang paling penting yang perlu anda ketahui. Sebelum kita menyelaminya, mari kita nyatakan bahawa siaran ini tidak bertujuan untuk menjadi panduan komprehensif kepada DDD, mahupun pengganti rujukan utama mengenai topik tersebut. Sesungguhnya, kami mengesyorkan sumber berikut untuk mendapatkan pemahaman yang lebih mendalam tentang DDD:
Sebelum menyelam lebih mendalam kepada mana-mana konsep utama DDD, kami mengesyorkan anda melihat angka yang agak berguna oleh Cosmic Python di mana ini ditunjukkan dalam konteks apl, sekali gus menunjukkan cara ia saling berkaitan: angka .
Konsep model domain boleh dijelaskan dengan takrifan ringkas istilahnya:
Oleh itu, model domain ialah cara yang mewah (tetapi standard dan berguna) untuk merujuk kepada set konsep dan peraturan yang ada dalam fikiran pemilik perniagaan tentang cara perniagaan itu berfungsi. Inilah yang juga kami, dan lazimnya, rujuk sebagai logik perniagaan aplikasi, termasuk peraturan, kekangan dan perhubungan yang mengawal tingkah laku sistem.
Kami akan merujuk kepada model domain sebagai model mulai sekarang.
Corak repositori ialah corak reka bentuk yang membolehkan penyahgandingan model daripada akses data. Idea utama di sebalik corak repositori adalah untuk mencipta lapisan abstraksi antara logik akses data dan logik perniagaan aplikasi. Lapisan abstraksi ini membolehkan pengasingan kebimbangan, menjadikan kod lebih boleh diselenggara dan boleh diuji.
Apabila melaksanakan corak repositori, kami biasanya mentakrifkan antara muka yang menentukan kaedah standard yang mesti dilaksanakan oleh mana-mana repositori lain (AbstractRepository). Dan, kemudian, repositori tertentu ditakrifkan dengan pelaksanaan konkrit kaedah ini di mana logik capaian data dilaksanakan (cth., SQLAlchemyRepository). Corak reka bentuk ini bertujuan untuk mengasingkan kaedah manipulasi data supaya ia boleh digunakan dengan lancar di tempat lain dalam aplikasi, mis. dalam model domain kami.
Unit corak kerja ialah bahagian yang hilang untuk akhirnya memisahkan model daripada akses data. Unit kerja merangkum logik akses data dan menyediakan cara untuk mengumpulkan semua operasi yang mesti dilakukan pada sumber data dalam satu transaksi. Corak ini memastikan semua operasi dilakukan secara atom.
Apabila melaksanakan unit corak kerja, kami biasanya mentakrifkan antara muka yang menentukan kaedah standard yang mesti dilaksanakan oleh mana-mana unit kerja lain (AbstractUnitOfWork). Dan, kemudian, unit kerja tertentu ditakrifkan dengan pelaksanaan konkrit kaedah ini di mana logik akses data dilaksanakan (cth., SQLAlchemyUnitOfWork). Reka bentuk ini membolehkan pengendalian sistematik sambungan kepada sumber data, tanpa perlu mengubah pelaksanaan logik perniagaan aplikasi.
Selepas pengenalan pantas kepada konsep utama DDD, kami bersedia untuk menyelami pelaksanaan DDD dengan Flama. Dalam bahagian ini, kami akan membimbing anda melalui proses menyediakan persekitaran pembangunan, membina aplikasi asas dan melaksanakan konsep DDD dengan Flama.
Sebelum meneruskan dengan contoh, sila lihat konvensyen penamaan Flama berkenaan konsep DDD utama yang baru kami semak:
Seperti yang anda lihat dalam rajah di atas, konvensyen penamaan agak intuitif: Repositori merujuk kepada corak repositori; dan, Pekerja merujuk kepada unit kerja. Kini, kita kini boleh beralih kepada pelaksanaan API Flama yang menggunakan DDD. Tetapi, sebelum kita mula, jika anda perlu menyemak asas tentang cara mencipta API mudah dengan flama, atau cara menjalankan API setelah kod anda sudah sedia, maka anda mungkin mahu menyemak keluar panduan permulaan pantas. Di sana, anda akan menemui konsep asas dan langkah yang diperlukan untuk mengikuti siaran ini. Sekarang, tanpa berlengah lagi, mari kita mulakan dengan pelaksanaannya.
Langkah pertama kami ialah mencipta persekitaran pembangunan kami dan memasang semua kebergantungan yang diperlukan untuk projek ini. Perkara yang baik ialah untuk contoh ini kita hanya perlu memasang flama untuk mempunyai semua alatan yang diperlukan untuk melaksanakan pengesahan JWT. Kami akan menggunakan puisi untuk mengurus kebergantungan kami, tetapi anda juga boleh menggunakan pip jika anda lebih suka:
poetry add "flama[full]" "aiosqlite"
Pakej aiosqlite diperlukan untuk menggunakan SQLite dengan SQLAlchemy, iaitu pangkalan data yang akan kami gunakan dalam contoh ini.
Jika anda ingin tahu cara kami biasanya mengatur projek kami, lihat siaran kami sebelum ini di sini, di mana kami menerangkan secara terperinci cara menyediakan projek ular sawa dengan puisi, dan struktur folder projek yang biasanya kami ikuti.
Mari kita mulakan dengan aplikasi mudah yang mempunyai satu titik akhir awam. Titik akhir ini akan mengembalikan penerangan ringkas tentang API.
# src/app.py from flama import Flama app = Flama( title="Domain-driven API", version="1.0.0", description="Domain-driven design with Flama ?", docs="/docs/", ) @app.get("/", name="info") def info(): """ tags: - Info summary: Ping description: Returns a brief description of the API responses: 200: description: Successful ping. """ return {"title": app.schema.title, "description": app.schema.description, "public": True}
Jika anda ingin menjalankan aplikasi ini, anda boleh menyimpan kod di atas dalam fail bernama app.py di bawah folder src, dan kemudian jalankan arahan berikut (ingat untuk mengaktifkan persekitaran puisi, jika tidak, anda perlu awalan perintah dengan larian puisi):
flama run --server-reload src.app:app INFO: Started server process [3267] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
di mana bendera --server-reload adalah pilihan dan digunakan untuk memuat semula pelayan secara automatik apabila kod berubah. Ini sangat berguna semasa pembangunan, tetapi anda boleh mengeluarkannya jika anda tidak memerlukannya. Untuk senarai penuh pilihan yang tersedia, anda boleh menjalankan flama run --help, atau semak dokumentasi.
Sebagai alternatif, anda juga boleh menjalankan aplikasi dengan menjalankan skrip berikut, yang boleh anda simpan sebagai __main__.py di bawah folder src:
# src/__main__.py import flama def main(): flama.run( flama_app="src.app:app", server_host="0.0.0.0", server_port=8000, server_reload=True ) if __name__ == "__main__": main()
Dan kemudian, anda boleh menjalankan aplikasi dengan melaksanakan arahan berikut:
poetry add "flama[full]" "aiosqlite"
Sekarang, setelah menyediakan rangka minimum untuk aplikasi kami, kami boleh mula melaksanakan konsep DDD yang baru kami semak dalam
konteks contoh mudah yang cuba meniru senario dunia sebenar. Katakan kami diminta untuk membangunkan API untuk mengurus pengguna, dan kami dibekalkan dengan keperluan berikut:
Set keperluan ini membentuk perkara yang sebelum ini kami rujuk sebagai model domain aplikasi kami, yang pada asasnya tidak lain hanyalah pewujudan aliran kerja pengguna berikut:
Sekarang, mari kita laksanakan model domain menggunakan repositori dan corak pekerja. Kami akan mulakan dengan mentakrifkan model data, dan kemudian kami akan melaksanakan repositori dan corak pekerja.
Data pengguna kami akan disimpan dalam pangkalan data SQLite (anda boleh menggunakan mana-mana pangkalan data lain yang disokong oleh SQLAlchemy). Kami akan menggunakan model data berikut untuk mewakili pengguna (anda boleh menyimpan kod ini dalam fail yang dipanggil models.py di bawah folder src):
# src/app.py from flama import Flama app = Flama( title="Domain-driven API", version="1.0.0", description="Domain-driven design with Flama ?", docs="/docs/", ) @app.get("/", name="info") def info(): """ tags: - Info summary: Ping description: Returns a brief description of the API responses: 200: description: Successful ping. """ return {"title": app.schema.title, "description": app.schema.description, "public": True}
Selain model data, kami memerlukan skrip migrasi untuk mencipta pangkalan data dan jadual. Untuk ini, kami boleh menyimpan kod berikut dalam fail yang dipanggil migrations.py pada akar projek:
poetry add "flama[full]" "aiosqlite"
Dan kemudian, kita boleh menjalankan skrip migrasi dengan melaksanakan arahan berikut:
# src/app.py from flama import Flama app = Flama( title="Domain-driven API", version="1.0.0", description="Domain-driven design with Flama ?", docs="/docs/", ) @app.get("/", name="info") def info(): """ tags: - Info summary: Ping description: Returns a brief description of the API responses: 200: description: Successful ping. """ return {"title": app.schema.title, "description": app.schema.description, "public": True}
Dalam contoh ini kita hanya memerlukan satu repositori, iaitu repositori yang akan mengendalikan operasi atom pada jadual pengguna, yang namanya akan menjadi UserRepository. Syukurlah, flama menyediakan kelas asas untuk repositori yang berkaitan dengan jadual SQLAlchemy, dipanggil SQLAlchemyTableRepository.
Kelas SQLAlchemyTableRepository menyediakan satu set kaedah untuk melaksanakan operasi CRUD pada jadual, khususnya:
Untuk tujuan contoh kami, kami tidak memerlukan sebarang tindakan lanjut pada jadual, jadi kaedah yang disediakan oleh SQLAlchemyTableRepository adalah mencukupi. Kami boleh menyimpan kod berikut dalam fail yang dipanggil repositories.py di bawah folder src:
flama run --server-reload src.app:app INFO: Started server process [3267] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Seperti yang anda boleh lihat, kelas UserRepository ialah subkelas SQLAlchemyTableRepository, dan ia hanya memerlukan jadual untuk ditetapkan dalam atribut _table. Ini adalah satu-satunya perkara yang perlu kita lakukan untuk mempunyai repositori berfungsi sepenuhnya untuk jadual pengguna.
Jika kami ingin menambah kaedah tersuai di luar operasi CRUD standard, kami boleh melakukannya dengan mentakrifkannya dalam kelas UserRepository. Contohnya, jika kami ingin menambah kaedah untuk mengira bilangan pengguna aktif, kami boleh berbuat demikian seperti berikut:
# src/__main__.py import flama def main(): flama.run( flama_app="src.app:app", server_host="0.0.0.0", server_port=8000, server_reload=True ) if __name__ == "__main__": main()
Walaupun kami tidak akan menggunakan kaedah ini dalam contoh kami, adalah baik untuk mengetahui bahawa kami boleh menambah kaedah tersuai pada repositori jika perlu, dan cara ia dilaksanakan
dalam konteks corak repositori. Ini adalah corak reka bentuk yang berkuasa seperti yang kita sudah lihat, kerana kita boleh melaksanakan di sini semua logik akses data tanpa perlu menukar logik perniagaan aplikasi (yang dilaksanakan dalam kaedah sumber yang sepadan).
Corak unit kerja digunakan untuk merangkum logik akses data dan menyediakan cara untuk mengumpulkan semua operasi yang mesti dilakukan pada sumber data dalam satu transaksi. Dalam flama corak UoW dilaksanakan dengan nama Pekerja. Dengan cara yang sama seperti corak repositori, flama menyediakan kelas asas untuk pekerja yang berkaitan dengan jadual SQLAlchemy, dipanggil SQLAlchemyWorker. Pada dasarnya, SQLAlchemyWorker menyediakan sambungan dan transaksi kepada pangkalan data, dan membuat instantiate semua repositorinya dengan sambungan pekerja. Dalam contoh ini, pekerja kami hanya akan menggunakan satu repositori (iaitu, UserRepository) tetapi kami boleh menambah lebih banyak repositori jika perlu.
Pekerja kami akan dipanggil RegisterWorker, dan kami boleh menyimpan kod berikut dalam fail bernama workers.py di bawah folder src:
poetry add "flama[full]" "aiosqlite"
Oleh itu, jika kami mempunyai lebih banyak repositori untuk digunakan, contohnya ProductRepository dan OrderRepository, kami boleh menambahkannya kepada pekerja seperti berikut:
# src/app.py from flama import Flama app = Flama( title="Domain-driven API", version="1.0.0", description="Domain-driven design with Flama ?", docs="/docs/", ) @app.get("/", name="info") def info(): """ tags: - Info summary: Ping description: Returns a brief description of the API responses: 200: description: Successful ping. """ return {"title": app.schema.title, "description": app.schema.description, "public": True}
Semudah itu, kami telah melaksanakan repositori dan corak pekerja dalam aplikasi kami. Kini, kita boleh meneruskan untuk melaksanakan kaedah sumber yang akan menyediakan titik akhir API yang diperlukan untuk berinteraksi dengan data pengguna.
Sumber ialah salah satu blok binaan utama aplikasi flama. Ia digunakan untuk mewakili sumber aplikasi (dalam erti kata sumber RESTful) dan untuk menentukan titik akhir API yang berinteraksi dengannya.
Dalam contoh kami, kami akan menentukan sumber untuk pengguna, dipanggil UserResource, yang akan mengandungi kaedah untuk mencipta, mengaktifkan, log masuk dan menyahaktifkan pengguna. Sumber perlu diperoleh, sekurang-kurangnya, daripada flama kelas Sumber terbina dalam, walaupun flama menyediakan kelas yang lebih canggih untuk digunakan seperti RESTResourcedan CRUDResource.
Kami boleh menyimpan kod berikut dalam fail yang dipanggil resources.py di bawah folder src:
flama run --server-reload src.app:app INFO: Started server process [3267] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Sekarang kami telah melaksanakan model data, repositori dan corak pekerja serta kaedah sumber, kami perlu mengubah suai aplikasi asas yang kami perkenalkan sebelum ini, supaya semuanya berfungsi seperti yang diharapkan. Kita perlu:
Ini akan meninggalkan fail app.py seperti berikut:
poetry add "flama[full]" "aiosqlite"
Sepatutnya anda sudah jelas bagaimana corak DDD telah membolehkan kami memisahkan logik perniagaan aplikasi (yang mudah dibaca dalam kaedah sumber) daripada logik akses data (yang dilaksanakan dalam repositori dan corak pekerja). Perlu juga diperhatikan bagaimana pemisahan kebimbangan ini telah menjadikan kod lebih boleh diselenggara dan boleh diuji serta cara kod itu kini lebih sejajar dengan keperluan perniagaan yang kami berikan pada permulaan contoh ini.
Sebelum menjalankan sebarang arahan, sila semak sama ada persekitaran pembangunan anda disediakan dengan betul dan struktur folder adalah seperti berikut:
# src/app.py from flama import Flama app = Flama( title="Domain-driven API", version="1.0.0", description="Domain-driven design with Flama ?", docs="/docs/", ) @app.get("/", name="info") def info(): """ tags: - Info summary: Ping description: Returns a brief description of the API responses: 200: description: Successful ping. """ return {"title": app.schema.title, "description": app.schema.description, "public": True}
Jika semuanya disediakan dengan betul, anda boleh menjalankan aplikasi dengan melaksanakan arahan berikut (ingat untuk menjalankan skrip pemindahan sebelum menjalankan aplikasi):
flama run --server-reload src.app:app INFO: Started server process [3267] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Kini kita boleh mencuba logik perniagaan yang baru kita laksanakan. Ingat, anda boleh mencuba ini sama ada dengan menggunakan alat seperti curl atau Postman, atau dengan menggunakan UI dokumen yang dijana secara automatik yang disediakan oleh flama dengan menavigasi ke http://localhost:8000/docs/ dalam penyemak imbas anda dan mencuba titik akhir dari sana.
Untuk mencipta pengguna, anda boleh menghantar permintaan POST kepada /user/ dengan muatan berikut:
# src/__main__.py import flama def main(): flama.run( flama_app="src.app:app", server_host="0.0.0.0", server_port=8000, server_reload=True ) if __name__ == "__main__": main()
Jadi, kita boleh menggunakan curl untuk menghantar permintaan seperti berikut:
poetry run python src/__main__.py INFO: Started server process [3267] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Jika permintaan itu berjaya, anda akan menerima 200 respons dengan badan kosong, dan pengguna akan dibuat dalam pangkalan data.
Untuk log masuk, anda boleh menghantar permintaan POST kepada /user/login/ dengan muatan berikut:
# src/models.py import uuid import sqlalchemy from flama.sqlalchemy import metadata from sqlalchemy.dialects.postgresql import UUID __all__ = ["user_table", "metadata"] user_table = sqlalchemy.Table( "user", metadata, sqlalchemy.Column("id", UUID(as_uuid=True), primary_key=True, nullable=False, default=uuid.uuid4), sqlalchemy.Column("name", sqlalchemy.String, nullable=False), sqlalchemy.Column("surname", sqlalchemy.String, nullable=False), sqlalchemy.Column("email", sqlalchemy.String, nullable=False, unique=True), sqlalchemy.Column("password", sqlalchemy.String, nullable=False), sqlalchemy.Column("active", sqlalchemy.Boolean, nullable=False), )
Jadi, kita boleh menggunakan curl untuk menghantar permintaan seperti berikut:
# migrations.py from sqlalchemy import create_engine from src.models import metadata if __name__ == "__main__": # Set up the SQLite database engine = create_engine("sqlite:///models.db", echo=False) # Create the database tables metadata.create_all(engine) # Print a success message print("Database and User table created successfully.")
Memandangkan pengguna tidak aktif, anda akan menerima sesuatu seperti respons berikut:
> poetry run python migrations.py Database and User table created successfully.
Kami juga boleh menguji perkara yang akan berlaku jika seseorang cuba log masuk dengan kata laluan yang salah:
# src/repositories.py from flama.ddd import SQLAlchemyTableRepository from src import models __all__ = ["UserRepository"] class UserRepository(SQLAlchemyTableRepository): _table = models.user_table
Dalam kes ini, anda sepatutnya menerima respons 401 dengan badan berikut:
# src/repositories.py from flama.ddd import SQLAlchemyTableRepository from src import models __all__ = ["UserRepository"] class UserRepository(SQLAlchemyTableRepository): _table = models.user_table async def count_active_users(self): return len((await self._connection.execute(self._table.select().where(self._table.c.active == True))).all())
Akhir sekali, kita juga harus cuba log masuk dengan pengguna yang tidak wujud:
# src/workers.py from flama.ddd import SQLAlchemyWorker from src import repositories __all__ = ["RegisterWorker"] class RegisterWorker(SQLAlchemyWorker): user: repositories.UserRepository
Dalam kes ini, anda sepatutnya menerima respons 404 dengan badan berikut:
# src/workers.py from flama.ddd import SQLAlchemyWorker from src import repositories __all__ = ["RegisterWorker"] class RegisterWorker(SQLAlchemyWorker): user: repositories.UserRepository product: repositories.ProductRepository order: repositories.OrderRepository
Setelah meneroka proses log masuk, kami kini boleh mengaktifkan pengguna dengan menghantar permintaan POST ke /pengguna/aktifkan/ dengan bukti kelayakan pengguna:
# src/resources.py import hashlib import http import uuid from flama import types from flama.ddd.exceptions import NotFoundError from flama.exceptions import HTTPException from flama.http import APIResponse from flama.resources import Resource, resource_method from src import models, schemas, worker __all__ = ["AdminResource", "UserResource"] ENCRYPTION_SALT = uuid.uuid4().hex ENCRYPTION_PEPER = uuid.uuid4().hex class Password: def __init__(self, password: str): self._password = password def encrypt(self): return hashlib.sha512( (hashlib.sha512((self._password + ENCRYPTION_SALT).encode()).hexdigest() + ENCRYPTION_PEPER).encode() ).hexdigest() class UserResource(Resource): name = "user" verbose_name = "User" @resource_method("/", methods=["POST"], name="create") async def create(self, worker: worker.RegisterWorker, data: types.Schema[schemas.UserDetails]): """ tags: - User summary: User create description: Create a user responses: 200: description: User created in successfully. """ async with worker: try: await worker.user.retrieve(email=data["email"]) except NotFoundError: await worker.user.create({**data, "password": Password(data["password"]).encrypt(), "active": False}) return APIResponse(status_code=http.HTTPStatus.OK) @resource_method("/signin/", methods=["POST"], name="signin") async def signin(self, worker: worker.RegisterWorker, data: types.Schema[schemas.UserCredentials]): """ tags: - User summary: User sign in description: Create a user responses: 200: description: User signed in successfully. 401: description: User not active. 404: description: User not found. """ async with worker: password = Password(data["password"]) try: user = await worker.user.retrieve(email=data["email"]) except NotFoundError: raise HTTPException(status_code=http.HTTPStatus.NOT_FOUND) if user["password"] != password.encrypt(): raise HTTPException(status_code=http.HTTPStatus.UNAUTHORIZED) if not user["active"]: raise HTTPException( status_code=http.HTTPStatus.BAD_REQUEST, detail=f"User must be activated via /user/activate/" ) return APIResponse(status_code=http.HTTPStatus.OK, schema=types.Schema[schemas.User], content=user) @resource_method("/activate/", methods=["POST"], name="activate") async def activate(self, worker: worker.RegisterWorker, data: types.Schema[schemas.UserCredentials]): """ tags: - User summary: User activate description: Activate an existing user responses: 200: description: User activated successfully. 401: description: User activation failed due to invalid credentials. 404: description: User not found. """ async with worker: try: user = await worker.user.retrieve(email=data["email"]) except NotFoundError: raise HTTPException(status_code=http.HTTPStatus.NOT_FOUND) if user["password"] != Password(data["password"]).encrypt(): raise HTTPException(status_code=http.HTTPStatus.UNAUTHORIZED) if not user["active"]: await worker.user.update({**user, "active": True}, id=user["id"]) return APIResponse(status_code=http.HTTPStatus.OK) @resource_method("/deactivate/", methods=["POST"], name="deactivate") async def deactivate(self, worker: worker.RegisterWorker, data: types.Schema[schemas.UserCredentials]): """ tags: - User summary: User deactivate description: Deactivate an existing user responses: 200: description: User deactivated successfully. 401: description: User deactivation failed due to invalid credentials. 404: description: User not found. """ async with worker: try: user = await worker.user.retrieve(email=data["email"]) except NotFoundError: raise HTTPException(status_code=http.HTTPStatus.NOT_FOUND) if user["password"] != Password(data["password"]).encrypt(): raise HTTPException(status_code=http.HTTPStatus.UNAUTHORIZED) if user["active"]: await worker.user.update({**user, "active": False}, id=user["id"]) return APIResponse(status_code=http.HTTPStatus.OK)
Dengan permintaan ini, pengguna harus diaktifkan, dan anda akan menerima 200 respons dengan badan kosong.
Seperti dalam kes sebelumnya, kami juga boleh menguji apa yang akan berlaku jika seseorang cuba mengaktifkan pengguna dengan kata laluan yang salah:
poetry add "flama[full]" "aiosqlite"
Dalam kes ini, anda sepatutnya menerima respons 401 dengan badan berikut:
# src/app.py from flama import Flama app = Flama( title="Domain-driven API", version="1.0.0", description="Domain-driven design with Flama ?", docs="/docs/", ) @app.get("/", name="info") def info(): """ tags: - Info summary: Ping description: Returns a brief description of the API responses: 200: description: Successful ping. """ return {"title": app.schema.title, "description": app.schema.description, "public": True}
Akhir sekali, kita juga harus cuba mengaktifkan pengguna yang tidak wujud:
flama run --server-reload src.app:app INFO: Started server process [3267] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Dalam kes ini, anda sepatutnya menerima respons 404 dengan badan berikut:
# src/__main__.py import flama def main(): flama.run( flama_app="src.app:app", server_host="0.0.0.0", server_port=8000, server_reload=True ) if __name__ == "__main__": main()
Sekarang pengguna diaktifkan, kami boleh cuba log masuk semula:
poetry run python src/__main__.py INFO: Started server process [3267] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
Yang, kali ini, harus mengembalikan 200 respons dengan maklumat pengguna:
# src/models.py import uuid import sqlalchemy from flama.sqlalchemy import metadata from sqlalchemy.dialects.postgresql import UUID __all__ = ["user_table", "metadata"] user_table = sqlalchemy.Table( "user", metadata, sqlalchemy.Column("id", UUID(as_uuid=True), primary_key=True, nullable=False, default=uuid.uuid4), sqlalchemy.Column("name", sqlalchemy.String, nullable=False), sqlalchemy.Column("surname", sqlalchemy.String, nullable=False), sqlalchemy.Column("email", sqlalchemy.String, nullable=False, unique=True), sqlalchemy.Column("password", sqlalchemy.String, nullable=False), sqlalchemy.Column("active", sqlalchemy.Boolean, nullable=False), )
Akhir sekali, kami boleh menyahaktifkan pengguna dengan menghantar permintaan POST ke /pengguna/nyahaktifkan/ dengan kelayakan pengguna:
# migrations.py from sqlalchemy import create_engine from src.models import metadata if __name__ == "__main__": # Set up the SQLite database engine = create_engine("sqlite:///models.db", echo=False) # Create the database tables metadata.create_all(engine) # Print a success message print("Database and User table created successfully.")
Dengan permintaan ini, pengguna harus dinyahaktifkan, dan anda akan menerima 200 respons dengan badan kosong.
Dalam siaran ini kami telah menceburi dunia Reka Bentuk Dipacu Domain (DDD) dan cara ia boleh dilaksanakan dalam aplikasi flama. Kami telah melihat cara DDD boleh membantu kami untuk memisahkan logik perniagaan aplikasi daripada logik akses data, dan cara pengasingan kebimbangan ini boleh menjadikan kod lebih boleh diselenggara dan boleh diuji. Kami juga telah melihat cara repositori dan corak pekerja boleh dilaksanakan dalam aplikasi flama dan cara ia boleh digunakan untuk merangkum logik akses data dan menyediakan cara untuk mengumpulkan semua operasi yang mesti dilakukan pada sumber data dalam satu transaksi. Akhir sekali, kami telah melihat cara kaedah sumber boleh digunakan untuk menentukan titik akhir API yang berinteraksi dengan data pengguna dan cara corak DDD boleh digunakan untuk melaksanakan keperluan perniagaan yang kami berikan pada permulaan contoh ini.
Walaupun proses log masuk yang telah kami huraikan di sini tidak sepenuhnya realistik, anda boleh menggabungkan bahan ini dan siaran sebelumnya tentang pengesahan JWT untuk melaksanakan proses yang lebih realistik, di mana log masuk itu akhirnya mengembalikan Token JWT. Jika anda berminat dengan ini, anda boleh menyemak siaran pada pengesahan JWT dengan flama.
Kami harap anda mendapati siaran ini berguna dan anda kini bersedia untuk melaksanakan DDD dalam aplikasi flama anda sendiri. Jika anda mempunyai sebarang soalan atau komen, sila hubungi kami. Kami sentiasa berbesar hati untuk membantu!
Nantikan lebih banyak siaran tentang flama dan topik menarik lain dalam dunia AI dan pembangunan perisian. Sehingga kali seterusnya!
Jika anda menyukai apa yang kami lakukan, terdapat cara percuma dan mudah untuk menyokong kerja kami. Hadiahkan kami ⭐ di Flama.
GitHub ⭐ bermakna dunia kepada kami dan memberi kami bahan api yang paling manis untuk terus mengusahakannya bagi membantu orang lain dalam perjalanannya membina API Pembelajaran Mesin yang mantap.
Anda juga boleh mengikuti kami di ?, tempat kami berkongsi berita dan kemas kini terkini kami, selain urutan menarik tentang AI, pembangunan perisian dan banyak lagi.
Atas ialah kandungan terperinci Reka Bentuk Didorong Domain Asli dengan Flama. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!