FastAPI 기반 주니어 개발자용 공통 프레임워크 (인증/로깅/예외/DB 내재화)
Project description
pxa-framework
FastAPI 기반 주니어 개발자용 공통 프레임워크. 주니어 개발자는 라이브러리 하나(pxa-framework)만 설치하면, 로깅·예외처리·사용자 인증·DB 연결·표준 응답 등 공통기능이 모두 내장된 앱 위에서 도메인 로직만 작성하면 됩니다.
from pxa import create_app, ApiResponse, NotFoundError
from pxa.auth import current_user
from pxa.fastapi import APIRouter, Depends # fastapi 직접 import 금지
app = create_app(authenticator=my_authenticate) # 공통기능 전부 내장
router = APIRouter(prefix="/items")
@router.get("/{item_id}", response_model=ApiResponse)
def get_item(item_id: int):
item = find(item_id)
if item is None:
raise NotFoundError("없는 항목") # -> pxa-20004
return ApiResponse.ok(result=item, message="조회 성공")
app.include_router(router)
1. 핵심 설계 개요
| 요구사항 | 구현 위치 |
|---|---|
| 1. Opaque Token + Redis + HttpOnly 쿠키 | pxa/auth/ (session_store.py, router.py, dependencies.py) |
| 2. 사용자 DB 저장 + DB 추상화(PostgreSQL↔MariaDB) | pxa/config.py(DbConfig.url), pxa/db/engine.py |
| 3. FastAPI 0.128 | pyproject.toml (fastapi==0.128.*) |
| 4. Set-Cookie 응답헤더 | pxa/auth/router.py(_set_session_cookie) |
| 5. HTTP 200 고정 + pxa-1xxxx/2xxxx 코드 | pxa/codes.py, pxa/exceptions.py(_json) |
| 6. 표준 응답 포맷(성공/메시지/결과) | pxa/response.py(ApiResponse) |
| 7. ORM+SQL 혼용, is_valid, 404=pxa-20004, 필수값 검증 | pxa/db/repository.py, pxa/db/base.py, pxa/db/sql_loader.py, pxa/db/sql/ |
| 8. 트랜잭션 관리(예외 시 rollback) | pxa/db/engine.py(session_scope) |
| 9. 커넥션 풀 관리(은닉) | pxa/db/engine.py(init_engine) |
| 10. 설정 파일 분리 | config/config.yaml, pxa/config.py |
| 11. 예외/에러코드/메시지 공통 모듈 | pxa/exceptions.py, pxa/codes.py |
| 12. 로그 디렉토리 설정 가능 | pxa/logging_conf.py, config.yaml(logging.dir) |
| 13. Redis 은닉 | pxa/auth/session_store.py (개발자 직접 접근 불필요) |
| 14. pytest API 테스트(DB 연결 제외) | tests/ |
| 15. Nexus/PyPI 패키징 | 본 문서 5장 |
| 16. PEP 네이밍 강제 점검 | .flake8 (flake8 + pep8-naming) |
| FastAPI 비노출(파사드) | pxa/fastapi.py |
1-1. FastAPI 비노출 — pxa.fastapi 파사드
주니어 개발자는 fastapi / pydantic 을 직접 import 하지 않습니다. 필요한 심볼은 모두 pxa.fastapi 에서 가져옵니다.
# 잘못된 예 (금지)
from fastapi import APIRouter, Depends
from pydantic import BaseModel
# 올바른 예
from pxa.fastapi import APIRouter, Depends, BaseModel
프레임워크가 내부적으로 어떤 웹 프레임워크/버전(FastAPI 0.128)을 쓰는지 사용자 코드와 분리되어, 향후 업그레이드/교체 시에도 주니어 코드는 그대로 둘 수 있습니다. pxa.fastapi 재노출 심볼: APIRouter, Depends, Request, Response, BackgroundTasks, HTTPException, status, Query/Path/Body/Header/Cookie/Form/File/UploadFile, 응답 타입(JSONResponse 등), BaseModel/Field/field_validator, TestClient.
CI 에서 fastapi 직접 사용을 차단하려면(파사드 파일만 예외):
grep -rnE "^\s*(from|import)\s+fastapi" --include=*.py . | grep -v "src/pxa/fastapi.py"
2. 응답 규약 (요구사항 5, 6)
모든 응답의 HTTP status 는 항상 200이며, 정상/비정상은 애플리케이션 코드로 구분합니다.
{ "success": true, "code": "pxa-10000", "message": "정상 처리되었습니다.", "result": { } }
pxa-10000: 정상pxa-2xxxx: 비정상 (예:pxa-20004데이터 없음,pxa-20002필수값 누락,pxa-20003미인증)
참고: 요구사항 7의 "없는 데이터 → 404"는 애플리케이션 코드
pxa-20004로 표현됩니다(요구사항 5에 따라 HTTP 자체는 200 유지). HTTP 404를 그대로 내보내려면pxa/codes.py의NOT_FOUND.http_status와exceptions.py(_json)만 조정하면 됩니다.
에러코드 추가는 pxa/codes.py의 AppCode Enum 에 한 줄 추가하면 됩니다.
3. ORM 과 SQL 혼용 (요구사항 7)
- 단일 테이블 CRUD → ORM:
Repository(Model, session)의get_or_404 / create / update / delete.create/update전에is_valid()로 필수값·정합성을 DB 저장 전에 검증합니다. - 복잡한 쿼리 → SQL 파일:
.sql파일을pxa/db/sql/(또는 앱별 디렉토리)에 두고SqlRepository.query("파일명", 파라미터=...)로 호출합니다. SQL 은 코드와 디렉토리로 분리됩니다.
from pxa.db import Repository, SqlRepository, session_scope
from pxa.models import User
with session_scope() as db: # 트랜잭션: 예외 시 자동 rollback
repo = Repository(User, db)
user = repo.get_or_404(1) # 없으면 pxa-20004
sql = SqlRepository(db)
rows = sql.query("example_user_search", keyword="kim", limit=10, offset=0)
모델은 __required__ 로 필수 컬럼을, validate() 오버라이드로 정합성 규칙을 선언합니다(pxa/models/user.py 참고).
4. 설정 / 로그 / DB 전환 (요구사항 2, 9, 10, 12)
모든 환경값은 config/config.yaml 에 있습니다. 환경변수 PXA_CONFIG로 경로 지정, PXA_DB__HOST 처럼 개별 override 가능합니다.
- DB 전환:
db.dialect를postgresql→mariadb로 바꾸고pip install "pxa-framework[mariadb]"설치만 하면 됩니다. 커넥션 풀(pool_size등)은 프레임워크가 내부 관리하므로 주니어는 몰라도 됩니다. - 로그 위치:
logging.dir변경으로 저장 디렉토리를 지정합니다(자정 회전, 보관일수 설정).
5. 패키징 & 배포 (Nexus / PyPI) (요구사항 15)
5-1. 빌드 (공통)
pip install --upgrade build twine
python -m build # dist/*.whl + dist/*.tar.gz 생성
twine check dist/* # 메타데이터 검증
pyproject.toml의package-data설정으로pxa/db/sql/*.sql이 wheel 에 포함됩니다. 같은 버전은 덮어쓸 수 없으니 업로드마다version을 올리세요(0.1.0 → 0.1.1).
5-2. 사내 Nexus 업로드 (권장)
Nexus 에서 PyPI(hosted) 저장소(예: pypi-internal)를 만든 뒤 ~/.pypirc 등록:
[distutils]
index-servers =
nexus
[nexus]
repository = https://nexus.example.com/repository/pypi-internal/
username = <NEXUS_USER>
password = <NEXUS_TOKEN>
업로드 & 설치:
twine upload -r nexus dist/*
pip install pxa-framework --index-url https://nexus.example.com/repository/pypi-internal/simple/
매번 옵션 주기 번거로우면 pip.conf(Windows pip.ini)에 고정:
[global]
index-url = https://nexus.example.com/repository/pypi-internal/simple/
extra-index-url = https://pypi.org/simple/
5-3. 공개 PyPI 업로드 (외부 공개 시)
API 토큰 인증(username 은 리터럴 __token__). TestPyPI 리허설 후 운영 업로드를 권장합니다.
twine upload --repository testpypi dist/* # (선택) 리허설
twine upload dist/* # 운영 PyPI
공개 PyPI 는 패키지명이 전역 유일해야 합니다.
pxa-framework가 점유돼 있으면pyproject.toml의name을 고유값(예:yourorg-pxa-framework)으로 바꾸세요. 사내 전용이면 5-2(Nexus)만으로 충분합니다.
5-4. Windows 빌드 에러 트러블슈팅
다음 에러는 Windows 260자 경로 제한(MAX_PATH) 때문입니다(프로젝트가 매우 긴 경로 아래 있을 때):
error: could not create '...\src\pxa_framework.egg-info\dependency_links.txt': No such file or directory
ERROR Backend subprocess exited when trying to invoke build_sdist
python -m build 가 만드는 중첩 임시 경로(pxa_framework-0.1.0\src\pxa_framework.egg-info\...)가 260자를 넘으면 Windows 가 파일 생성에 실패하고 ENOENT(No such file or directory)로 보고됩니다. 해결책:
- (가장 쉬움) 짧은 경로에서 빌드:
robocopy "%CD%" C:\build\pxa /E /XD .venv dist build /XF *.egg-info cd /d C:\build\pxa rmdir /s /q src\pxa_framework.egg-info 2>nul py -m build
- Windows 긴 경로 허용: 레지스트리
HKLM\SYSTEM\CurrentControlSet\Control\FileSystem의LongPathsEnabled=1설정 후 재부팅. - wheel 만 빌드:
py -m build --wheel(Nexus 업로드엔 충분). - 잔여물 정리: 프로젝트의
.venv,*.egg-info,build,dist를 지운 뒤 빌드.
5-5. (선택) CI 자동 배포
태그 push 시: python -m build → twine check dist/* → twine upload(자격증명은 CI 시크릿). 버전 태그와 pyproject.toml 버전을 일치시키세요.
6. 테스트 & 네이밍 점검 (요구사항 14, 16)
pip install -e ".[dev]"
pytest # API 위주 테스트 (DB 연결 제외, fakeredis 사용)
flake8 src tests # PEP8 + pep8-naming(N8xx) 규칙 강제 점검
CI 에서 flake8 종료코드가 0이 아니면 빌드를 실패시켜 네이밍 위반을 차단하세요.
7. 디렉토리 구조
pxa-framework/
├── pyproject.toml # 패키지/의존성/빌드 설정
├── .flake8 # PEP 네이밍 강제 (요구사항 16)
├── config/config.yaml # 환경설정 (요구사항 10, 12)
├── src/pxa/
│ ├── app.py # create_app 팩토리
│ ├── fastapi.py # FastAPI 파사드 (fastapi 비노출)
│ ├── config.py # 설정 로더
│ ├── codes.py # AppCode (pxa-1xxxx/2xxxx)
│ ├── response.py # ApiResponse 표준 포맷
│ ├── exceptions.py # 공통 예외 + 핸들러
│ ├── logging_conf.py # 로깅
│ ├── middleware.py # 요청 로깅
│ ├── auth/ # Opaque Token + Redis + 쿠키
│ ├── db/ # 엔진/풀/트랜잭션/ORM/SQL
│ │ └── sql/ # 분리된 SQL 파일
│ └── models/ # ORM 모델
├── example/main.py # 주니어 개발자 예제
└── tests/ # pytest (API 위주)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pxa_framework-0.1.0.tar.gz.
File metadata
- Download URL: pxa_framework-0.1.0.tar.gz
- Upload date:
- Size: 26.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9dd1781baebbac01dd87ef7dbe44f4bd708aae0cd8520ebf7ee448649922118e
|
|
| MD5 |
74c3f79eaa508124ebde6dc999bda6bd
|
|
| BLAKE2b-256 |
ce3fc199650ab062e80304712f24ff1580149bd702e2f3e343c911f9d2bf33aa
|
File details
Details for the file pxa_framework-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pxa_framework-0.1.0-py3-none-any.whl
- Upload date:
- Size: 28.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
282824aa79c664aeb2d9363e1737809bc8214331b9a56e64809e9cb8d5084f06
|
|
| MD5 |
9b18576c2d23dbff5525f84d5dce2808
|
|
| BLAKE2b-256 |
8c4f472890cebc6170651956cd11089861d1bfe8a8f7d79df5683a05df8e752f
|