Skip to content

Commit 770888b

Browse files
authored
Merge pull request #217 from Pseudo-Lab/fix/api-prefix
feat: API ๊ฒฝ๋กœ /api/v1 ํ†ต์ผ, Traefik ๋ผ์šฐํŒ… ๊ทœ์น™ ์ •๋น„
2 parents 7fc6a24 + fbf0f85 commit 770888b

7 files changed

Lines changed: 51 additions & 33 deletions

File tree

โ€Žgetcloser/.gitignoreโ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.env

โ€Žgetcloser/backend/app/api/v1/auth/auth.pyโ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88

99
router = APIRouter()
1010

11-
@router.post('/', response_model=UserResponse)
11+
# Accept both /auth and /auth/ to avoid redirects (307) when the trailing slash is
12+
# omitted by clients such as the frontend.
13+
@router.post("", response_model=UserResponse)
14+
@router.post("/", response_model=UserResponse, include_in_schema=False)
1215
def auth(user_auth: UserAuth, db: Session = Depends(get_db)):
1316
token = auth_user(db, user_auth.email)
1417
return token

โ€Žgetcloser/backend/app/main.pyโ€Ž

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from fastapi import FastAPI
22
from fastapi.middleware.cors import CORSMiddleware
3-
from fastapi.openapi.utils import get_openapi
43
from dotenv import load_dotenv
54
import os
65

@@ -27,21 +26,6 @@
2726
redoc_url="/redoc",
2827
)
2928

30-
# Swagger ๊ธฐ๋ณธ ๊ฒฝ๋กœ๋ฅผ /api ๋กœ ์ง€์ •
31-
def custom_openapi():
32-
if app.openapi_schema:
33-
return app.openapi_schema
34-
openapi_schema = get_openapi(
35-
title=app.title,
36-
version=app.version,
37-
description=app.description,
38-
routes=app.routes,
39-
)
40-
openapi_schema["servers"] = [{"url": "/api"}]
41-
app.openapi_schema = openapi_schema
42-
return app.openapi_schema
43-
44-
app.openapi = custom_openapi
4529

4630
# CORS ๋ฏธ๋“ค์›จ์–ด ์„ค์ •
4731
origins = os.getenv("CORS_ORIGINS", "").split(",")
@@ -53,7 +37,8 @@ def custom_openapi():
5337
allow_headers=["*"],
5438
)
5539

56-
app.include_router(api_router, prefix="/v1")
40+
# ๋ชจ๋“  ํ™˜๊ฒฝ์—์„œ /api ํ”„๋ฆฌํ”ฝ์Šค ์‚ฌ์šฉ (๊ฐœ๋ฐœ/ํ”„๋กœ๋•์…˜ ํ†ต์ผ)
41+
app.include_router(api_router, prefix="/api/v1")
5742
app.include_router(test_db.test_router)
5843

5944

โ€Žgetcloser/docker-compose.dev.ymlโ€Ž

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
version: '3.8'
22

33
services:
4-
# frontend:
5-
# build:
6-
# context: ./frontend
7-
# labels:
8-
# - "org.pseudolab.project=getcloser"
9-
# ports:
10-
# - "${FRONTEND_PORT}:80"
11-
# restart: always
4+
frontend:
5+
build:
6+
context: ./frontend
7+
dockerfile: Dockerfile.dev
8+
labels:
9+
- "org.pseudolab.project=getcloser"
10+
ports:
11+
- "3000:3000"
12+
environment:
13+
NODE_ENV: development
14+
NEXT_PUBLIC_API_BASE: http://backend:8000/api
15+
volumes:
16+
- ./frontend:/app
17+
- /app/node_modules
18+
- /app/.next
19+
restart: always
1220

1321
backend:
1422
build:
@@ -17,10 +25,11 @@ services:
1725
labels:
1826
- "org.pseudolab.project=getcloser"
1927
ports:
20-
- "${BACKEND_PORT}:8000"
28+
- "8000:8000"
2129
environment:
2230
ENV: development
2331
DATABASE_URL: postgresql+psycopg2://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_DATABASE}
32+
CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000}
2433
SECRET_KEY: ${SECRET_KEY:-change-me-in-prod}
2534
ACCESS_TOKEN_EXPIRE_MINUTES: ${ACCESS_TOKEN_EXPIRE_MINUTES:-60}
2635
volumes:

โ€Žgetcloser/docker-compose.yamlโ€Ž

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,18 @@ services:
5454
- traefik.docker.network=traefik
5555

5656
# --- Traefik Router (backend) ---
57-
- traefik.http.routers.getcloser-api.rule=Host(`${APP_HOST}`) && PathPrefix(`/api`) || Host(`${APP_HOST}`) && PathPrefix(`/docs`) || Host(`${APP_HOST}`) && PathPrefix(`/redoc`) || Host(`${APP_HOST}`) && PathPrefix(`/health`) || Host(`${APP_HOST}`) && Path(`/openapi.json`)
57+
# ๋ฐฑ์—”๋“œ๋กœ ๋ผ์šฐํŒ…๋˜๋Š” ๊ฒฝ๋กœ:
58+
# - /api/* : API ์—”๋“œํฌ์ธํŠธ (๋ฐฑ์—”๋“œ์—์„œ /api/v1/* ๋กœ ๋ผ์šฐํŒ…)
59+
# - /docs, /redoc : Swagger UI ๋ฌธ์„œ (๋ฐฑ์—”๋“œ์—์„œ /docs, /redoc๋กœ ๋ผ์šฐํŒ…)
60+
# - /health : ํ—ฌ์Šค์ฒดํฌ (๋ฐฑ์—”๋“œ์—์„œ /health๋กœ ๋ผ์šฐํŒ…)
61+
# - /openapi.json : OpenAPI ์Šคํ‚ค๋งˆ (๋ฐฑ์—”๋“œ์—์„œ /openapi.json๋กœ ๋ผ์šฐํŒ…)
62+
# ๋ฐฑ์—”๋“œ์— /api ํ”„๋ฆฌํ”ฝ์Šค๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ stripPrefix ๋ฏธ๋“ค์›จ์–ด ์—†์ด ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ
63+
- traefik.http.routers.getcloser-api.rule=Host(`${APP_HOST}`) && (PathPrefix(`/api`) || PathPrefix(`/docs`) || PathPrefix(`/redoc`) || PathPrefix(`/health`) || Path(`/openapi.json`))
5864
- traefik.http.routers.getcloser-api.entrypoints=websecure
5965
- traefik.http.routers.getcloser-api.tls=true
6066
- traefik.http.routers.getcloser-api.tls.certresolver=le
6167
- traefik.http.services.getcloser-api.loadbalancer.server.port=8000
6268

63-
# /api ํ”„๋ฆฌํ”ฝ์Šค ์ œ๊ฑฐ (๋ฐฑ์—”๋“œ ๋‚ด๋ถ€๋Š” / ๊ธฐ์ค€์œผ๋กœ ๋™์ž‘)
64-
- traefik.http.middlewares.getcloser-stripapi.stripPrefix.prefixes=/api
65-
- traefik.http.routers.getcloser-api.middlewares=getcloser-stripapi
66-
6769
# HTTP โ†’ HTTPS ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ (backend)
6870
- traefik.http.routers.getcloser-api-http.rule=Host(`${APP_HOST}`) && PathPrefix(`/api`)
6971
- traefik.http.routers.getcloser-api-http.entrypoints=web

โ€Žgetcloser/frontend/.env.exampleโ€Ž

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
FROM node:24-alpine
2+
3+
WORKDIR /app
4+
5+
# ์‹œ์Šคํ…œ ์˜์กด์„ฑ ์„ค์น˜
6+
RUN apk add --no-cache libc6-compat
7+
8+
# package.json๊ณผ lock ํŒŒ์ผ ๋ณต์‚ฌ
9+
COPY package*.json ./
10+
11+
# ์˜์กด์„ฑ ์„ค์น˜
12+
RUN npm ci
13+
14+
# ์†Œ์Šค ์ฝ”๋“œ ๋ณต์‚ฌ
15+
COPY . .
16+
17+
# ๊ฐœ๋ฐœ ๋ชจ๋“œ๋กœ ์‹คํ–‰
18+
CMD ["npm", "run", "dev"]
19+

0 commit comments

Comments
ย (0)