microservices-with-fastapi
microservices-with-fastapi
https://github.com/fanqingsong/microservices-with-fastapi
- This repo is composed of a bunch of small microservices considering API gateway approach
- Expected number of microservices was two, but considering that services should not create dependency on each other to prevent SPOF, also to prevent duplicate codes, I decided to put one API gateway in front that does JWT authentication for both services which I am inspired by Netflix/Zuul
- We have 3 services including gateway.
- Only gateway can access internal microservices through the internal network (users, orders)
- gateway: Built on top of FastAPI, simple API gateway which its only duty is to make proper routing while also handling authentication and authorization
- users (a.k.a. admin): Keeps user info in its own fake db (file system). Can be executed simple CRUD operations through the service. There is also another endpoint for login, but client is abstracted from real response. Thus, gateway service will handle login response and generate JWT token accordingly.
- orders: Users (subscribed ones – authentication) can create and view (their – authorization) orders.
- check ./gateway/.env → 2 services URL are defined based on twelve-factor config
- docker-compose up --build
- visit → http://localhost:8001/docs
docker-compose
version: '3.7' services: gateway: image: baranbartu/k-api-gateway:latest command: sh -c "uvicorn main:app --reload --host 0.0.0.0 --port 8001" build: context: ./gateway dockerfile: Dockerfile env_file: - ./gateway/.env ports: - 8001:8001 depends_on: - users - orders networks: - microservices volumes: - ./gateway:/app users: image: baranbartu/k-users:latest command: sh -c "uvicorn main:app --reload --host 0.0.0.0 --port 8002" build: context: ./users dockerfile: Dockerfile env_file: - ./users/.env ports: - 8002:8002 networks: - microservices volumes: - ./users:/app orders: image: baranbartu/k-orders:latest command: sh -c "uvicorn main:app --reload --host 0.0.0.0 --port 8003" build: context: ./orders dockerfile: Dockerfile env_file: - ./orders/.env ports: - 8003:8003 networks: - microservices volumes: - ./orders:/app networks: microservices: driver: bridge
gateway API
route出自:https://github.com/dotX12/fastapi-gateway
from fastapi import FastAPI, status, Request, Response, Depends from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from conf import settings from core import route, get_token_from_core from datastructures.users import (UsernamePasswordForm, UserForm, UserUpdateForm) from datastructures.orders import OrderForm app = FastAPI(debug=True) oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/token") @app.post("/api/token") async def get_token_by_api(form_data: OAuth2PasswordRequestForm = Depends(), request: Request = None, response: Response = None): print("called in get_token_by_api") return await get_token_from_core(form_data.username, form_data.password, request, response) @route( request_method=app.post, path='/api/login', status_code=status.HTTP_201_CREATED, payload_key='username_password', service_url=settings.USERS_SERVICE_URL, authentication_required=False, post_processing_func='post_processing.access_token_generate_handler', response_model='datastructures.users.LoginResponse' ) async def login(username_password: UsernamePasswordForm, request: Request, response: Response): pass @route( request_method=app.post, path='/api/users', status_code=status.HTTP_201_CREATED, payload_key='user', service_url=settings.USERS_SERVICE_URL, authentication_required=True, post_processing_func=None, authentication_token_decoder='auth.decode_access_token', service_authorization_checker='auth.is_admin_user', service_header_generator='auth.generate_request_header', response_model='datastructures.users.UserResponse', ) async def create_user(user: UserForm, request: Request, response: Response, token: str=Depends(oauth2_scheme)): pass @route( request_method=app.get, path='/api/users', status_code=status.HTTP_200_OK, payload_key=None, service_url=settings.USERS_SERVICE_URL, authentication_required=True, post_processing_func=None, authentication_token_decoder='auth.decode_access_token', service_authorization_checker='auth.is_admin_user', service_header_generator='auth.generate_request_header', response_model='datastructures.users.UserResponse', response_list=True ) async def get_users(request: Request, response: Response, token: str=Depends(oauth2_scheme)): pass @route( request_method=app.get, path='/api/users/{user_id}', status_code=status.HTTP_200_OK, payload_key=None, service_url=settings.USERS_SERVICE_URL, authentication_required=True, post_processing_func=None, authentication_token_decoder='auth.decode_access_token', service_authorization_checker='auth.is_admin_user', service_header_generator='auth.generate_request_header', response_model='datastructures.users.UserResponse', ) async def get_user(user_id: int, request: Request, response: Response, token: str=Depends(oauth2_scheme)): pass @route( request_method=app.delete, path='/api/users/{user_id}', status_code=status.HTTP_204_NO_CONTENT, payload_key=None, service_url=settings.USERS_SERVICE_URL, authentication_required=True, post_processing_func=None, authentication_token_decoder='auth.decode_access_token', service_authorization_checker='auth.is_admin_user', service_header_generator='auth.generate_request_header', ) async def delete_user(user_id: int, request: Request, response: Response, token: str=Depends(oauth2_scheme)): pass @route( request_method=app.put, path='/api/users/{user_id}', status_code=status.HTTP_200_OK, payload_key='user', service_url=settings.USERS_SERVICE_URL, authentication_required=True, post_processing_func=None, authentication_token_decoder='auth.decode_access_token', service_authorization_checker='auth.is_admin_user', service_header_generator='auth.generate_request_header', response_model='datastructures.users.UserResponse', ) async def update_user(user_id: int, user: UserUpdateForm, request: Request, response: Response, token: str=Depends(oauth2_scheme)): pass @route( request_method=app.get, path='/api/orders', status_code=status.HTTP_200_OK, payload_key=None, service_url=settings.ORDERS_SERVICE_URL, authentication_required=True, post_processing_func=None, authentication_token_decoder='auth.decode_access_token', service_authorization_checker='auth.is_default_user', service_header_generator='auth.generate_request_header', response_model='datastructures.orders.OrderResponse', response_list=True, ) async def get_orders(request: Request, response: Response, token: str=Depends(oauth2_scheme)): pass @route( request_method=app.post, path='/api/orders', status_code=status.HTTP_200_OK, payload_key='order', service_url=settings.ORDERS_SERVICE_URL, authentication_required=True, post_processing_func=None, authentication_token_decoder='auth.decode_access_token', service_authorization_checker='auth.is_default_user', service_header_generator='auth.generate_request_header', response_model='datastructures.orders.OrderResponse', ) async def create_order(order: OrderForm, request: Request, response: Response, token: str=Depends(oauth2_scheme)): pass
OTHERS
以nginx作为gateway
https://dev.to/paurakhsharma/microservice-in-python-using-fastapi-24cc#introduction-microservice
https://github.com/paurakhsharma/python-microservice-fastapi
Building-Python-Microservices-with-FastAPI
https://github.com/PacktPublishing/Building-Python-Microservices-with-FastAPI
https://sgp1.vultrobjects.com/books/Codeing/Building%20Python%20Microservices%20with%20FastAPI.pdf
K8S version
https://github.com/Kludex/fastapi-microservices
one frontend and two backend
https://github.com/nikhil25803/fastapi-microservice/tree/main
出处:http://www.cnblogs.com/lightsong/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。