Stay Hungry,Stay Foolish!

microservices-with-fastapi

microservices-with-fastapi

https://github.com/fanqingsong/microservices-with-fastapi

Microservices, API Gateway, Authentication with FastAPI, non-blocking i/o

  • 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)

Services

  • 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.

Running

  • 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

 

posted @ 2024-06-24 21:45  lightsong  阅读(4)  评论(0编辑  收藏  举报
Life Is Short, We Need Ship To Travel