Problems API ์๋น์ค
1. ๊ฐ์
Problems API ์๋น์ค๋ DynamoDB ํ ์ด๋ธ์ ์ ์ฅ๋ ์ฝ๋ฉ ๋ฌธ์ ์ ๋ํ ์ ๋ณด๋ฅผ ๊ฒ์ํ๊ธฐ ์ํ HTTP ์๋ํฌ์ธํธ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด ์๋น์ค๋ฅผ ํตํด โ์๋ฃ๋(completed)โ ์ํ์ ๋ชจ๋ ๋ฌธ์ ๋ชฉ๋ก์ ๊ฐ์ ธ์ค๊ณ (ํ์ด์ง๋ค์ด์ ๋ฐ ์์ฑ์๋ณ ํํฐ๋ง ์ต์ ํฌํจ), ํน์ ๋ฌธ์ ID๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ๋ฌธ์ ์ ์์ธ ์ ๋ณด๋ฅผ ๊ฒ์ํ ์ ์์ต๋๋ค.
์ด ์๋น์ค๋ AWS Lambda(์ปดํจํ ), API Gateway(์์ฒญ ๋ผ์ฐํ ), DynamoDB(๋ฐ์ดํฐ ์ ์ฅ)๋ฅผ ํ์ฉํ์ฌ ์๋ฒ๋ฆฌ์ค(Serverless) ๋ฐฉ์์ผ๋ก ์ค๊ณ๋์์ต๋๋ค. ์ธํ๋ผ๋ Terraform์ ํตํด ์ฝ๋๋ก ๊ด๋ฆฌ๋ฉ๋๋ค.
2. ๊ธฐ๋ฅ
- ๋ฌธ์ ๋ชฉ๋ก ์กฐํ: ํ์ด์ง๋ค์ด์
์ ์ง์ํ๋ ๋ฌธ์ ๋ชฉ๋ก์ ๊ฒ์ํฉ๋๋ค.
creatorId
๋ฅผ ์ฌ์ฉํ ํํฐ๋ง์ ์ง์ํฉ๋๋ค.- ์์ฑ ๋ ์ง(
createdAt
)๋ฅผ ๊ธฐ์ค์ผ๋ก ์ค๋ฆ์ฐจ์ ๋๋ ๋ด๋ฆผ์ฐจ์ ์ ๋ ฌ์ ์ง์ํฉ๋๋ค. generationStatus = "completed"
์ํ์ธ ๋ฌธ์ ๋ง ๋ฐํํฉ๋๋ค.
- ID๋ก ๋ฌธ์ ์กฐํ: ๊ณ ์ ํ
problemId
๋ฅผ ์ฌ์ฉํ์ฌ ๋จ์ผ ๋ฌธ์ ์ ์ ์ฒด ์์ธ ์ ๋ณด๋ฅผ ๊ฒ์ํฉ๋๋ค. - CORS ์ง์: ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฐ ํด๋ผ์ด์ธํธ ์ ๊ทผ์ ์ํ CORS(Cross-Origin Resource Sharing) ํค๋๋ฅผ ํฌํจํฉ๋๋ค.
- ์๋ฒ๋ฆฌ์ค ์ํคํ ์ฒ: AWS ๊ด๋ฆฌํ ์๋น์ค๋ฅผ ํ์ฉํ์ฌ ํ์ฅ์ฑ์ ํ๋ณดํ๊ณ ์ด์ ์ค๋ฒํค๋๋ฅผ ์ค์ ๋๋ค.
- Infrastructure as Code (IaC): ๋ชจ๋ AWS ๋ฆฌ์์ค๋ Terraform์ ์ฌ์ฉํ์ฌ ์ฝ๋๋ก ์ ์ํ๊ณ ๊ด๋ฆฌํฉ๋๋ค.
3. API ์๋ํฌ์ธํธ
API์ ๊ธฐ๋ณธ URL์ API Gateway ๋ฐฐํฌ์ ์ํด ๊ฒฐ์ ๋ฉ๋๋ค (์: https://{api-id}.execute-api.{region}.amazonaws.com/{stage}
).
3.1. ๋ชจ๋ ๋ฌธ์ ์กฐํ (Get All Problems)
๋ฌธ์ ๋ชฉ๋ก์ ๊ฒ์ํฉ๋๋ค. ์ฃผ๋ก generationStatus = "completed"
์ํ์ธ ๋ฌธ์ ๋ฅผ ๋ฐํํฉ๋๋ค.
- ๋ฉ์๋:
GET
- ๊ฒฝ๋ก:
/problems
- ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ:
creatorId
(์ ํ ์ฌํญ, ๋ฌธ์์ด): ๋ฌธ์ ์์ฑ์์ ID๋ก ๋ฌธ์ ๋ฅผ ํํฐ๋งํฉ๋๋ค. ์ด ํ๋ผ๋ฏธํฐ๊ฐ ์ ๊ณต๋๋ฉดCreatorIdCreatedAtGSI
๋ฅผ ์ฌ์ฉํ๋ฉฐ, ์ถ๊ฐ์ ์ผ๋กgenerationStatus = "completed"
์กฐ๊ฑด์ผ๋ก ํํฐ๋งํฉ๋๋ค.pageSize
(์ ํ ์ฌํญ, ์ซ์, ๊ธฐ๋ณธ๊ฐ:20
): ํ์ด์ง๋น ๋ฐํํ ์ต๋ ๋ฌธ์ ์์ ๋๋ค.sortOrder
(์ ํ ์ฌํญ, ๋ฌธ์์ด, ๊ธฐ๋ณธ๊ฐ:DESC
):createdAt
๊ธฐ์ค ์ ๋ ฌ ์์์ ๋๋ค.ASC
๋๋DESC
๊ฐ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.lastEvaluatedKey
(์ ํ ์ฌํญ, ๋ฌธ์์ด): ์ด์ ์๋ต์์ ๋ฐ์LastEvaluatedKey
๊ฐ์ URL ์ธ์ฝ๋ฉ๋ JSON ๋ฌธ์์ด ํํ๋ก ์ ๋ฌํ๋ฉฐ, ํ์ด์ง๋ค์ด์ ์ ์ฌ์ฉ๋ฉ๋๋ค.
- ์ฑ๊ณต ์๋ต (200 OK):
{ "items": [ { "problemId": "uuid-problem-1", "title": "Problem Title 1", "title_translated": "๋ฒ์ญ๋ ๋ฌธ์ ์ ๋ชฉ 1", "difficulty": "Medium", "algorithmType": "Dynamic Programming", "createdAt": "2023-10-26T10:00:00.000Z", "creatorId": "user-abc", "author": "Author Name", "generationStatus": "completed" } // ... ์ถ๊ฐ ๋ฌธ์ ํญ๋ชฉ๋ค ], "lastEvaluatedKey": "encoded_json_string_or_null", // ๋ค์ ํ์ด์ง ์กฐํ๋ฅผ ์ํ ํค (์์ผ๋ฉด null) "count": 20, // ํ์ฌ ์๋ต์ ํฌํจ๋ ํญ๋ชฉ ์ "scannedCount": 25 // ํํฐ๋ง ์ ์ค์บ๋ ํญ๋ชฉ ์ (ํด๋น๋๋ ๊ฒฝ์ฐ) }
items
๋ฐฐ์ด์ Lambda ํจ์ ๋ดProjectionExpression
์ ์ ์๋ ๋ฌธ์ ์์ฑ๋ค์ ์ผ๋ถ๋ฅผ ํฌํจํฉ๋๋ค.
- ์ค๋ฅ ์๋ต:
400 Bad Request
:lastEvaluatedKey
ํ์์ด ์๋ชป๋ ๊ฒฝ์ฐ.500 Internal Server Error
:PROBLEMS_TABLE_NAME
ํ๊ฒฝ ๋ณ์๊ฐ ์ค์ ๋์ง ์์๊ฑฐ๋ ๋ค๋ฅธ ์๋ฒ ์ธก ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ.
3.2. ID๋ก ๋ฌธ์ ์กฐํ (Get Problem by ID)
ํน์ ๋ฌธ์ ์ ์ ์ฒด ์์ธ ์ ๋ณด๋ฅผ ๊ฒ์ํฉ๋๋ค.
- ๋ฉ์๋:
GET
- ๊ฒฝ๋ก:
/problems/{problemId}
- ๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ:
problemId
(ํ์, ๋ฌธ์์ด): ๋ฌธ์ ์ ๊ณ ์ ์๋ณ์์ ๋๋ค.
- ์ฑ๊ณต ์๋ต (200 OK):
{ "problemId": "uuid-problem-1", "userPrompt": "Generate a hard problem about graphs.", "difficulty": "Hard", "language": "python", "targetLanguage": "ko", "createdAt": "2023-10-26T10:00:00.000Z", "completedAt": "2023-10-26T10:05:00.000Z", "generationStatus": "completed", "errorMessage": null, "title": "Graph Traversal Challenge", "title_translated": "๊ทธ๋ํ ํ์ ์ฑ๋ฆฐ์ง", "description": "Detailed problem description...", "description_translated": "์์ธ ๋ฒ์ญ๋ ๋ฌธ์ ์ค๋ช ...", "intent": "User's intent for the problem...", "finalTestCases": "[{\"input\": ...}, ...]", "validatedSolutionCode": "def solution(...): ...", "startCode": "def solution(...): \n # Your code here\n pass", "constraints": "Problem constraints...", // ... ProblemDetail ์ธํฐํ์ด์ค์ ์ ์๋ ๋ค๋ฅธ ์์ฑ๋ค "creatorId": "user-xyz", "author": "Author Name" }
- ์ค๋ฅ ์๋ต:
400 Bad Request
:problemId
๊ฐ ๋๋ฝ๋ ๊ฒฝ์ฐ.404 Not Found
: ์ฃผ์ด์งproblemId
์ ํด๋นํ๋ ๋ฌธ์ ๊ฐ ์๋ ๊ฒฝ์ฐ.500 Internal Server Error
:PROBLEMS_TABLE_NAME
ํ๊ฒฝ ๋ณ์๊ฐ ์ค์ ๋์ง ์์๊ฑฐ๋ ๋ค๋ฅธ ์๋ฒ ์ธก ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ.
3.3. CORS ํ๋ฆฌํ๋ผ์ดํธ (CORS Preflight)
/problems
๋ฐ /problems/{problemId}
๊ฒฝ๋ก๋ ๋ชจ๋ CORS ํ๋ฆฌํ๋ผ์ดํธ ๊ฒ์ฌ๋ฅผ ์ํด OPTIONS
์์ฒญ์ ์ง์ํฉ๋๋ค. API Gateway๋ ์ด๋ฌํ ์์ฒญ์ ๋ํด MOCK ํตํฉ์ผ๋ก ๊ตฌ์ฑ๋์ด ์์ผ๋ฉฐ, Lambda ํจ์ ๋ํ ๋ช
์์ ์ผ๋ก OPTIONS
์์ฒญ์ ์ฒ๋ฆฌํ์ฌ ์ ์ ํ CORS ํค๋๋ฅผ ๋ฐํํฉ๋๋ค.
- ๋ฉ์๋:
OPTIONS
- ๊ฒฝ๋ก:
/problems
๋๋/problems/{problemId}
- ์ฑ๊ณต ์๋ต (200 OK):
- ํค๋:
Access-Control-Allow-Origin: *
(์ฐธ๊ณ : ํ๋ก๋์ ํ๊ฒฝ์์๋ ํน์ ๋๋ฉ์ธ์ผ๋ก ์ ํํด์ผ ํฉ๋๋ค.)Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token
- ๋ณธ๋ฌธ:
{"message": "CORS preflight check successful"}
(Lambda์์ ์ฒ๋ฆฌํ๋ ๊ฒฝ์ฐ) ๋๋ ๋น์ด ์์ (API Gateway MOCK ํตํฉ๋ง ์ฌ์ฉํ๋ ๊ฒฝ์ฐ)
- ํค๋:
4. ๊ธฐ์ ์คํ
- AWS Lambda: Node.js 20.x ๋ฐํ์ (๋ฐฑ์๋ ๋ก์ง ์ฒ๋ฆฌ).
@aws-sdk/client-dynamodb
: DynamoDB ํด๋ผ์ด์ธํธ๋ฅผ ์ํ AWS SDK v3.@aws-sdk/lib-dynamodb
: ์์ฌ์ด JSON ์ฒ๋ฆฌ๋ฅผ ์ํ AWS SDK v3 DynamoDB Document Client.
- Amazon API Gateway: HTTP ์๋ํฌ์ธํธ ๊ด๋ฆฌ, ์์ฒญ ๋ผ์ฐํ ๋ฐ CORS ์ฒ๋ฆฌ.
- Amazon DynamoDB: ๋ฌธ์ ๋ฐ์ดํฐ ์ ์ฅ์ ์ํ NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค. ํ
์ด๋ธ ์์ฒด๋
problem-generator-v3
๋ชจ๋์์ ๊ด๋ฆฌํฉ๋๋ค. - Terraform: AWS ๋ฆฌ์์ค ํ๋ก๋น์ ๋ ๋ฐ ๊ด๋ฆฌ๋ฅผ ์ํ Infrastructure as Code (IaC) ๋๊ตฌ.
- AWS IAM: Lambda ๋ฐ API Gateway์ ๊ถํ ๋ฐ ์ญํ ๊ด๋ฆฌ.
- AWS CloudWatch: ๋ก๊น ๋ฐ ๋ชจ๋ํฐ๋ง.
5. ๋ฐ์ดํฐ ๋ชจ๋ธ (DynamoDB)
API๋ DynamoDB ํ
์ด๋ธ๊ณผ ์ํธ์์ฉํฉ๋๋ค (ํ
์ด๋ธ ์ด๋ฆ์ PROBLEMS_TABLE_NAME
ํ๊ฒฝ ๋ณ์๋ฅผ ํตํด ์ ๊ณต๋จ).
- ํ
์ด๋ธ ์ด๋ฆ: Terraform์์
local.problems_table_name
์ผ๋ก ์ฐธ์กฐ๋๋ฉฐ, ์ด๋problem-generator-v3
๋ชจ๋์ ์๊ฒฉ ์ํ(remote state)์์ ๊ฐ์ ธ์ต๋๋ค. - ๊ธฐ๋ณธ ํค (Primary Key):
problemId
(๋ฌธ์์ด): ํํฐ์ ํค (Partition Key).
- ์ด API์์ ์ฌ์ฉ๋๋ ๊ธ๋ก๋ฒ ๋ณด์กฐ ์ธ๋ฑ์ค (Global Secondary Indexes, GSIs):
CompletedProblemsByCreatedAtGSI
(getAllProblems.mjs
์ ๋ช ๋ช ๋ ์ด๋ฆ)- ๋ชฉ์ : ์๋ฃ๋(completed) ๋ชจ๋ ๋ฌธ์ ๋ฅผ ์์ฑ ๋ ์ง ์์ผ๋ก ์กฐํ.
- ํํฐ์
ํค (PK):
generationStatus
(๋ฌธ์์ด) - ์ ๋ ฌ ํค (SK):
createdAt
(๋ฌธ์์ด, ISO 8601 ํ์) - ์ฟผ๋ฆฌ ๋ก์ง:
generationStatus = "completed"
,createdAt
๊ธฐ์ค์ผ๋ก ์ ๋ ฌ.
CreatorIdCreatedAtGSI
(getAllProblems.mjs
์ ๋ช ๋ช ๋ ์ด๋ฆ)- ๋ชฉ์ : ํน์ ์ฌ์ฉ์๊ฐ ์์ฑํ ๋ฌธ์ ๋ฅผ ์์ฑ ๋ ์ง ์์ผ๋ก ์กฐํ.
- ํํฐ์
ํค (PK):
creatorId
(๋ฌธ์์ด) - ์ ๋ ฌ ํค (SK):
createdAt
(๋ฌธ์์ด, ISO 8601 ํ์) - ์ฟผ๋ฆฌ ๋ก์ง:
creatorId = :creatorIdVal
,createdAt
๊ธฐ์ค์ผ๋ก ์ ๋ ฌ. ์ถ๊ฐ์ ์ผ๋กgenerationStatus = "completed"
์กฐ๊ฑด์ ๋ง์กฑํ๋ ํญ๋ชฉ๋ง ํํฐ๋งํฉ๋๋ค.
- ์ฃผ์ ์์ฑ (์ผ๋ถ, ์ ์ฒด ๋ชฉ๋ก์
problemApi.ts
์ProblemSummary
๋ฐProblemDetail
ํ์ ์ ์ ์ฐธ์กฐ):problemId
: String (PK) - ๋ฌธ์ ์ ๊ณ ์ ID.title
: String - ๋ฌธ์ ์ ๋ชฉ.title_translated
: String (์ ํ ์ฌํญ) - ๋ฒ์ญ๋ ๋ฌธ์ ์ ๋ชฉ.description
: String - ๋ฌธ์ ์ ์ ์ฒด ์ค๋ช .description_translated
: String (์ ํ ์ฌํญ) - ๋ฒ์ญ๋ ๋ฌธ์ ์ค๋ช .difficulty
: String - ๋ฌธ์ ๋์ด๋ (์: โEasyโ, โMediumโ, โHardโ).algorithmType
: String (์ ํ ์ฌํญ) - ์๊ณ ๋ฆฌ์ฆ ์ ํ (์: โArraysโ, โDynamic Programmingโ).createdAt
: String (ISO 8601 ํ์) - ์์ฑ ํ์์คํฌํ.creatorId
: String (์ ํ ์ฌํญ) - ๋ฌธ์ ์์ฑ์ ์์ฒญํ ์ฌ์ฉ์ ID.author
: String (์ ํ ์ฌํญ) - ๋ฌธ์ ์ถ์ ์ (AI ๋ชจ๋ธ ์ด๋ฆ ๋๋ ์ฌ์ฉ์).generationStatus
: String - ๋ฌธ์ ์์ฑ ์ํ (์: โpendingโ, โcompletedโ, โfailedโ). ์ด API๋ ์ฃผ๋ก โcompletedโ ์ํ์ ๋ฌธ์ ๋ฅผ ์กฐํํฉ๋๋ค.finalTestCases
: String (JSON ๋ฐฐ์ด ํ์) - ๋ฌธ์ ์ ํ ์คํธ ์ผ์ด์ค.startCode
: String (์ ํ ์ฌํญ) - ์ฌ์ฉ์๋ฅผ ์ํ ๊ธฐ๋ณธ ์ ๊ณต ์ฝ๋.validatedSolutionCode
: String (์ ํ ์ฌํญ) - AI๊ฐ ์์ฑํ ์๋ฃจ์ ์ฝ๋.language
: String - ๋ฌธ์ ์ ์ฃผ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด (์: โpythonโ, โjavascriptโ).
6. Lambda ํจ์
API๋ capstone-2025-04/backend/lambdas/problems-api/
๋๋ ํ ๋ฆฌ์ ์ ์๋ ๋ ๊ฐ์ ์ฃผ์ Lambda ํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค:
getAllProblems.mjs
- Terraform ๋ฆฌ์์ค ์ด๋ฆ:
aws_lambda_function.get_all_problems
- AWS์์์ ํจ์ ์ด๋ฆ:
${var.project_name}-getAllProblems-${var.environment}
- ํธ๋ค๋ฌ:
getAllProblems.handler
- ๋ชฉ์ :
GET /problems
์์ฒญ์ ์ฒ๋ฆฌํฉ๋๋ค. GSIs๋ฅผ ์ฌ์ฉํ์ฌ DynamoDB์์ ๋ฌธ์ ๋ชฉ๋ก์ ์กฐํํฉ๋๋ค. - ์ฃผ์ ํ๊ฒฝ ๋ณ์:
PROBLEMS_TABLE_NAME
: DynamoDB ํ ์ด๋ธ ์ด๋ฆ.AWS_NODEJS_CONNECTION_REUSE_ENABLED=1
: SDK ์ฐ๊ฒฐ ์ฌ์ฌ์ฉ ์ต์ ํ.
- Terraform ๋ฆฌ์์ค ์ด๋ฆ:
getProblemById.mjs
- Terraform ๋ฆฌ์์ค ์ด๋ฆ:
aws_lambda_function.get_problem_by_id
- AWS์์์ ํจ์ ์ด๋ฆ:
${var.project_name}-getProblemById-${var.environment}
- ํธ๋ค๋ฌ:
getProblemById.handler
- ๋ชฉ์ :
GET /problems/{problemId}
์์ฒญ์ ์ฒ๋ฆฌํฉ๋๋ค. ๊ธฐ๋ณธ ํค์ ๋ํดGetItem
์์ ์ ์ฌ์ฉํ์ฌ DynamoDB์์ ๋จ์ผ ๋ฌธ์ ๋ฅผ ๊ฐ์ ธ์ต๋๋ค. - ์ฃผ์ ํ๊ฒฝ ๋ณ์:
PROBLEMS_TABLE_NAME
: DynamoDB ํ ์ด๋ธ ์ด๋ฆ.AWS_NODEJS_CONNECTION_REUSE_ENABLED=1
: SDK ์ฐ๊ฒฐ ์ฌ์ฌ์ฉ ์ต์ ํ.
- Terraform ๋ฆฌ์์ค ์ด๋ฆ:
์ฐธ๊ณ : getProblems.mjs
ํ์ผ์ Lambda ์์ค ๋๋ ํ ๋ฆฌ์ ์กด์ฌํ์ง๋ง, ํ์ฌ lambdas.tf
์ Terraform ๊ตฌ์ฑ์ ์ํด ๋ฐฐํฌ๋์ง ์์ต๋๋ค. Terraform ๊ตฌ์ฑ์ ๊ฐ ๊ฒฝ๋ก์ ๋ํด getAllProblems.mjs
๋ฐ getProblemById.mjs
๋ฅผ ๋ฐฐํฌํฉ๋๋ค.
7. ์ธํ๋ผ ๋ฐ ๋ฐฐํฌ (Terraform)
์ด API์ ์ธํ๋ผ๋ capstone-2025-04/infrastructure/problems-api/
๋๋ ํ ๋ฆฌ์ ์ ์๋์ด ์์ต๋๋ค.
์ฌ์ ์ค๋น ์ฌํญ
- Terraform CLI (์: v1.x ๋ฒ์ )
- ์ ์ ํ ์๊ฒฉ ์ฆ๋ช ๋ฐ ๊ธฐ๋ณธ ๋ฆฌ์ ์ผ๋ก ๊ตฌ์ฑ๋ AWS CLI.
- Terraform ์๊ฒฉ ์ํ ๋ฐฑ์๋(S3 bucket ๋ฐ DynamoDB table) (
backend.tf
ํ์ผ์ ๊ตฌ์ฑ๋จ). ์ด๋ ์ฌ์ ์ ์ค์ ๋์ด ์์ด์ผ ํฉ๋๋ค (์:backend-setup
๋ชจ๋์ ์ํด). problem-generator-v3
Terraform ๋ชจ๋์ด ์ฑ๊ณต์ ์ผ๋ก ์ ์ฉ(apply)๋์ด ์์ด์ผ ํฉ๋๋ค. ์ด API๋ ํด๋น ๋ชจ๋์ ์ํ๋ฅผ ์ฝ์ด DynamoDB ํ ์ด๋ธ ์ด๋ฆ๊ณผ ARN์ ๊ฐ์ ธ์ต๋๋ค.
๋ฐฐํฌ ๋จ๊ณ
- Terraform ๋ชจ๋ ๋๋ ํ ๋ฆฌ๋ก ์ด๋ํฉ๋๋ค:
cd capstone-2025-04/infrastructure/problems-api
- Terraform์ ์ด๊ธฐํํฉ๋๋ค:
terraform init
- (์ ํ ์ฌํญ) ์คํ ๊ณํ์ ๊ฒํ ํฉ๋๋ค:
terraform plan -var-file="dev.tfvars" # ๋๋ ํด๋น ํ๊ฒฝ์ .tfvars ํ์ผ
aws_region
,project_name
,environment
์ ๊ฐ์ ๋ณ์๋ฅผ ์ํด.tfvars
ํ์ผ์ ์์ฑํ๊ฑฐ๋ ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. - Terraform ๊ตฌ์ฑ์ ์ ์ฉํฉ๋๋ค:
terraform apply -var-file="dev.tfvars" # ๋๋ ํด๋น ํ๊ฒฝ์ .tfvars ํ์ผ
ํ๋กฌํํธ๊ฐ ๋ํ๋๋ฉด
yes
๋ฅผ ์ ๋ ฅํ์ฌ ํ์ธํฉ๋๋ค.
์ฃผ์ Terraform ํ์ผ
apigateway.tf
: API Gateway REST API, ๋ฆฌ์์ค, ๋ฉ์๋, ํตํฉ ๋ฐ ๋ฐฐํฌ๋ฅผ ์ ์ํฉ๋๋ค.lambdas.tf
: AWS Lambda ํจ์๋ฅผ ์ ์ํ๋ฉฐ, ์์ค ์ฝ๋ ํจํค์ง(data "archive_file"
)์ ํฌํจํฉ๋๋ค.iam.tf
: Lambda ์คํ ๋ฐ API Gateway ๋ก๊น ์ ์ํ IAM ์ญํ ๋ฐ ์ ์ฑ ์ ์ ์ํฉ๋๋ค.dynamodb.tf
:problem-generator-v3
๋ชจ๋์์ DynamoDB ํ ์ด๋ธ ์ธ๋ถ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํterraform_remote_state
๋ฐ์ดํฐ ์์ค๋ฅผ ์ ์ํฉ๋๋ค. ์๋ก์ด ํ ์ด๋ธ์ ์์ฑํ์ง๋ ์์ต๋๋ค.variables.tf
: ๋ชจ๋์ ์ ๋ ฅ ๋ณ์ (์:aws_region
,project_name
,environment
).outputs.tf
: ๋ฐฐํฌ ํ ์์ฑ๋๋ ์ถ๋ ฅ ๊ฐ (์:problems_api_invoke_url
).providers.tf
: AWS ๊ณต๊ธ์ ๊ตฌ์ฑ์ ์ง์ ํฉ๋๋ค.backend.tf
: Terraform S3 ์๊ฒฉ ์ํ ๋ฐฑ์๋๋ฅผ ๊ตฌ์ฑํฉ๋๋ค.
Lambda ์ฝ๋ ํจํค์ง
lambdas.tf
ํ์ผ์ data "archive_file"
๋ธ๋ก์ ์ฌ์ฉํ์ฌ ๊ฐ๋ณ .mjs
ํ์ผ์ lambda_zips
ํ์ ๋๋ ํ ๋ฆฌ(lambdas.tf
ํ์ผ ๊ธฐ์ค ์๋ ๊ฒฝ๋ก) ๋ด์ .zip
์์นด์ด๋ธ(์: getAllProblems.zip
, getProblemById.zip
)๋ก ํจํค์งํฉ๋๋ค. ์ด ์์
์ terraform plan/apply
๋จ๊ณ์์ ์ํ๋ฉ๋๋ค. ์ด๋ ๊ฒ ์์ฑ๋ zip ํ์ผ๋ค์ Lambda ํจ์์ ์
๋ก๋๋ฉ๋๋ค.
8. ํ๊ฒฝ ๋ณ์ (Lambda)
PROBLEMS_TABLE_NAME
: (ํ์) ๋ฌธ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ DynamoDB ํ ์ด๋ธ์ ์ด๋ฆ์ ๋๋ค. ์ด ๊ฐ์ Terraform (local.problems_table_name
)์ผ๋ก๋ถํฐ ์ ๋ฌ๋ฉ๋๋ค.AWS_NODEJS_CONNECTION_REUSE_ENABLED
: AWS SDK์ TCP ์ฐ๊ฒฐ ์ฌ์ฌ์ฉ์ ํ์ฑํํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํค๊ธฐ ์ํด1
๋ก ์ค์ ๋ฉ๋๋ค.
9. CORS ๊ตฌ์ฑ
CORS๋ ๋ค์ ๋ ๊ฐ์ง ์์ค์์ ์ฒ๋ฆฌ๋ฉ๋๋ค:
- API Gateway:
/problems
๋ฐ/problems/{problemId}
๋ฆฌ์์ค์ ๋ํดOPTIONS
๋ฉ์๋๊ฐ MOCK ํตํฉ์ผ๋ก ์ ์๋์ด ์์ต๋๋ค. ์ด๋ฌํ ํตํฉ์ ํ์ํAccess-Control-Allow-*
ํค๋๋ฅผ ๋ฐํํฉ๋๋ค. - Lambda ํจ์: ๊ฐ Lambda ํธ๋ค๋ฌ๋ ๋ช
์์ ์ผ๋ก
event.httpMethod === "OPTIONS"
๋ฅผ ํ์ธํ๊ณ CORS ํค๋์ ํจ๊ป 200 ์๋ต์ ๋ฐํํฉ๋๋ค. ์ด๋ API Gateway MOCK ํตํฉ์ดOPTIONS
์ ์ฌ์ฉ๋์ง ์๋ ๊ฒฝ์ฐ ๋์ฒด ๋ฉ์ปค๋์ฆ์ผ๋ก ์๋ํ๊ฑฐ๋ ์ฃผ์ ๋ฉ์ปค๋์ฆ์ด ๋ ์ ์์ต๋๋ค.
Access-Control-Allow-Origin
ํค๋๋ ํ์ฌ *
(๋ชจ๋ ์ค๋ฆฌ์ง ํ์ฉ)๋ก ์ค์ ๋์ด ์์ต๋๋ค. ํ๋ก๋์
ํ๊ฒฝ์์๋ ์ด ๊ฐ์ ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์
์ ํน์ ๋๋ฉ์ธ์ผ๋ก ์ ํํด์ผ ํฉ๋๋ค.
10. ์ค๋ฅ ์ฒ๋ฆฌ
- Lambda ํจ์๋ ์ ์ ํ HTTP ์ํ ์ฝ๋์ ํจ๊ป JSON ํ์์ ์๋ต์ ๋ฐํํฉ๋๋ค.
- ์ผ๋ฐ์ ์ธ ์ค๋ฅ ์๋ต์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
400 Bad Request
: ์๋ชป๋ ์ ๋ ฅ ๊ฐ (์: ํ์์ด ์๋ชป๋lastEvaluatedKey
).404 Not Found
: ํน์ ๋ฆฌ์์ค (์: ID๋ก ์กฐํํ ๋ฌธ์ )๋ฅผ ์ฐพ์ ์ ์๋ ๊ฒฝ์ฐ.500 Internal Server Error
: ์๋ฒ ์ธก ๊ตฌ์ฑ ๋ฌธ์ (์:PROBLEMS_TABLE_NAME
๋๋ฝ) ๋๋ DynamoDB ์์ ์ค ์๊ธฐ์น ์์ ์ค๋ฅ ๋ฐ์ ์. ์ค๋ฅ ์ธ๋ถ ์ ๋ณด๋ CloudWatch Logs์ ๊ธฐ๋ก๋ฉ๋๋ค.
- ํ๋ก ํธ์๋
problemApi.ts
ํ์ผ์๋ ์ด๋ฌํ ์๋ต์ ์ฒ๋ฆฌํ๊ธฐ ์ํApiError
ํด๋์ค์handleApiResponse
ํจ์๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.