Если я запущу
uvicorn src.main:app --reload
и доступ к SwaggerUI, вы увидите, что http://127.0.0.1:8000/blogs работает:
[
{
"title": "blog with relationship",
"description": "description",
"written_by": {
"username": "Sarthak",
"email": "[email protected]",
"blogs": [
{
"title": "blog with relationship",
"description": "description"
},
{
"title": "blog with relationship",
"description": "description"
}
]
}
},
{
"title": "blog with relationship",
"description": "description",
"written_by": {
"username": "Sarthak",
"email": "[email protected]",
"blogs": [
{
"title": "blog with relationship",
"description": "description"
},
{
"title": "blog with relationship",
"description": "description"
}
]
}
}
]
Это раздел SwaggerUI/docs:
[img]https://i. sstatic.net/rUUE0Klk.png[/img]
Я развернул это приложение в виде архива .zip в AWS Lambda, шаблон которого:
# This AWS SAM template has been generated from your function's configuration. If
# your function has one or more triggers, note that the AWS resources associated
# with these triggers aren't fully specified in this template and include
# placeholder values. Open this template in AWS Application Composer or your
# favorite IDE and modify it to specify a serverless application with other AWS
# resources.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: An AWS Serverless Application Model template describing your function.
Resources:
Full:
Type: AWS::Serverless::Function
Properties:
CodeUri: .
Description: ''
MemorySize: 128
Timeout: 60
Handler: src.main.handler
Runtime: python3.12
Architectures:
- x86_64
EphemeralStorage:
Size: 512
EventInvokeConfig:
MaximumEventAgeInSeconds: 21600
MaximumRetryAttempts: 2
FunctionUrlConfig:
AuthType: NONE
InvokeMode: BUFFERED
PackageType: Zip
Policies:
- Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
Resource: arn:aws:logs:us-east-1:820363156269:*
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- >-
arn:aws:logs:us-east-1:820363156269:log-group:/aws/lambda/Full:*
RecursiveLoop: Terminate
SnapStart:
ApplyOn: None
RuntimeManagementConfig:
UpdateRuntimeOn: Auto
К сожалению, если я отправлю запрос GET к конечной точке, сгенерированной AWS Lambda:
https://cjosbvzkkcjiaa4e7frfwtacia0mola ... .aws/blogs
Я получаю:
Ошибка слишком большого количества перенаправлений
Это также происходит при использовании Postman:
GET https://cjosbvzkkcjiaa4e7frfwtacia0mola ... .aws/blogs
Error: Exceeded maxRedirects. Probably stuck in a redirect loop https://cjosbvzkkcjiaa4e7frfwtacia0mola ... aws/blogs/
Request Headers
User-Agent: PostmanRuntime/7.42.0
Accept: */*
Postman-Token: 7d793a8b-31e7-48d6-aef2-a2530b2651e0
Host: cjosbvzkkcjiaa4e7frfwtacia0molag.lambda-url.us-east-1.on.aws
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Я пытался увеличить параметр maxRedirects в Postman, но это не сработало.
Обратите внимание: если я ПОЛУЧУ это: https: //cjosbvzkkcjiaa4e7frfwtacia0molag.lambda-url.us-east-1.on.aws/blogs/1, это действительно работает:
{
"title": "blog with relationship",
"description": "description",
"written_by": {
"username": "Sarthak",
"email": "[email protected]",
"blogs": [
{
"title": "blog with relationship",
"description": "description"
},
{
"title": "blog with relationship",
"description": "description"
}
]
}
}
Также GET https://cjosbvzkkcjiaa4e7frfwtacia0mola ... ws/users/1 работает:
{
"username": "Sarthak",
"email": "[email protected]",
"blogs": [
{
"title": "blog with relationship",
"description": "description"
},
{
"title": "blog with relationship",
"description": "description"
}
]
}
Как это?
Если я протестирую приложение с помощью панели Test в менеджере консоли AWS Lambda, используя шаблон прокси-сервера AWS:
{
"body": "eyJ0ZXN0IjoiYm9keSJ9",
"resource": "/{proxy+}",
"path": "/blogs",
"httpMethod": "GET",
"isBase64Encoded": true,
"queryStringParameters": {
"foo": "bar"
},
"multiValueQueryStringParameters": {
"foo": [
"bar"
]
},
"pathParameters": {
"proxy": "/blogs"
},
"stageVariables": {
"baz": "qux"
},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, sdch",
"Accept-Language": "en-US,en;q=0.8",
"Cache-Control": "max-age=0",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "US",
"Host": "1234567890.execute-api.us-east-1.amazonaws.com",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Custom User Agent String",
"Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==",
"X-Forwarded-For": "127.0.0.1, 127.0.0.2",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"multiValueHeaders": {
"Accept": [
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
],
"Accept-Encoding": [
"gzip, deflate, sdch"
],
"Accept-Language": [
"en-US,en;q=0.8"
],
"Cache-Control": [
"max-age=0"
],
"CloudFront-Forwarded-Proto": [
"https"
],
"CloudFront-Is-Desktop-Viewer": [
"true"
],
"CloudFront-Is-Mobile-Viewer": [
"false"
],
"CloudFront-Is-SmartTV-Viewer": [
"false"
],
"CloudFront-Is-Tablet-Viewer": [
"false"
],
"CloudFront-Viewer-Country": [
"US"
],
"Host": [
"0123456789.execute-api.us-east-1.amazonaws.com"
],
"Upgrade-Insecure-Requests": [
"1"
],
"User-Agent": [
"Custom User Agent String"
],
"Via": [
"1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)"
],
"X-Amz-Cf-Id": [
"cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA=="
],
"X-Forwarded-For": [
"127.0.0.1, 127.0.0.2"
],
"X-Forwarded-Port": [
"443"
],
"X-Forwarded-Proto": [
"https"
]
},
"requestContext": {
"accountId": "123456789012",
"resourceId": "123456",
"stage": "prod",
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
"requestTime": "09/Apr/2015:12:34:56 +0000",
"requestTimeEpoch": 1428582896000,
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"accessKey": null,
"sourceIp": "127.0.0.1",
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "Custom User Agent String",
"user": null
},
"path": "/blogs",
"resourcePath": "/{proxy+}",
"httpMethod": "GET",
"apiId": "1234567890",
"protocol": "HTTP/1.1"
}
}
Я получаю такой ответ:
{
"statusCode": 307,
"headers": {
"content-length": "0",
"location": "https://0123456789.execute-api.us-east- ... s/?foo=bar"
},
"multiValueHeaders": {},
"body": "",
"isBase64Encoded": false
}
как вы можете видеть здесь:
Это структура проекта:
[img]https://i. sstatic.net/XWxCJ1ec.png[/img]
И я выполнил эту команду для создания каталога зависимостей:
pip3 install -r requirements.txt --platform manylinux2014_x86_64 --target=dependencies --implementation cp --python-version 3.12 --only-binary=:all: --upgrade openai
Затем добавляем содержимое зависимостей в aws_lambda_artifact.zip:
(cd dependencies; zip ../aws_lambda_artifact.zip -r .)
И, наконец, добавляем в архив .zip содержимое каталога src:
zip aws_lambda_artifact.zip -u -r src
Здесь вы можете видеть, что архив содержит каталог src:
[img]https: //i.sstatic.net/53iIGjtH.png[/img]
А это его содержимое:

Если вам это нужно, это main.py файл:
from fastapi import FastAPI
from mangum import Mangum
from src import models
from src.database import engine
from src.routers import blog, user, authentication
app = FastAPI()
handler = Mangum(app)
models.Base.metadata.create_all(bind=engine)
app.include_router(blog.router)
app.include_router(user.router)
app.include_router(authentication.router)
А это файл requirements.txt:
fastapi==0.114.2
mangum==0.17.0
SQLAlchemy==2.0.34
passlib==1.7.4
bcrypt==4.2.0
python-jose==3.3.0
python-multipart==0.0.9
Это файл routers/blog.py:
from typing import List
from fastapi import APIRouter, Depends, status
from sqlalchemy.orm import Session
from src.database import get_db
from src.oauth2 import get_current_user
from src.repository import blog_repository
from src.schemas import ShowBlog, Blog, User
router = APIRouter(
prefix="/blogs",
tags=["blogs"]
)
@router.get("/", response_model=List[ShowBlog])
async def blogs(db: Session = Depends(get_db)):
return blog_repository.get_all(db)
@router.get("/{blog_id}", response_model=ShowBlog)
async def get_blog(blog_id: int, db: Session = Depends(get_db)):
return blog_repository.get(blog_id, db)
@router.post("/create-blog", status_code=status.HTTP_201_CREATED)
async def create_blog(request: Blog, db: Session = Depends(get_db)):
return blog_repository.create(request, db)
@router.put("/{blog_id}", status_code=status.HTTP_202_ACCEPTED)
async def update_blog(blog_id: int, request: Blog, db: Session = Depends(get_db)):
return blog_repository.update(blog_id, request, db)
@router.delete("/{blog_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_blog(blog_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)):
return blog_repository.delete(blog_id, db)
Подробнее здесь: https://stackoverflow.com/questions/789 ... d-to-aws-l