Python 강좌 / 웹 API 서버 만들고 입력값 검증하기

Flask로 작은 JSON API를 만들면 HTTP 요청을 Python 함수에 연결할 수 있습니다. 입력 객체·필수 필드·자료형·범위를 검사하고 성공과 실패를 상태 코드로 구분하는 것이 기본입니다.

로컬 실습 범위와 설치

아래 API는 같은 PC에서만 접속하는 개발 실습입니다. 데이터는 메모리 목록에 있어 프로그램을 종료하면 사라지고 여러 프로세스 사이에 공유되지 않습니다. 실제 공개 서비스에는 DB·인증·권한·배포 서버·동시성 등 추가 설계가 필요합니다.

관련 동작과 지원 조건은 웹 API 서버 만들고 입력값 검증하기 관련 공식 문서에서 확인할 수 있습니다.

python -m pip install flask

app.py에 코드를 저장하고 python app.py로 실행합니다. 이미 5000번 포트를 사용 중이면 코드와 접속 주소의 포트를 함께 바꾸세요.

전체 API 프로그램

app.py 파일의 전체 내용입니다.

from flask import Flask, jsonify, request

app = Flask(__name__)
app.config["MAX_CONTENT_LENGTH"] = 4096
expenses = []

@app.get("/api/expenses")
def list_expenses():
    return jsonify(expenses)

@app.post("/api/expenses")
def add_expense():
    data = request.get_json(silent=True)
    if not isinstance(data, dict):
        return jsonify(error="expected JSON object"), 400
    name, amount = data.get("name"), data.get("amount")
    if not isinstance(name, str) or not name.strip() or type(amount) is not int or amount < 0:
        return jsonify(error="invalid name or amount"), 400
    row = {"id": len(expenses) + 1, "name": name.strip(), "amount": amount}
    expenses.append(row)
    return jsonify(row), 201

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=5000, debug=False)

GET /api/expenses는 목록을 반환하고 POST는 새 항목을 만듭니다. 생성 성공은 201, 검증 실패는 400입니다. MAX_CONTENT_LENGTH는 요청 본문 크기를 제한하며 모든 애플리케이션 자원 제한을 대신하지는 않습니다.

테스트 클라이언트로 요청하기

test_client.py 파일의 전체 내용입니다.

from app import app, expenses

expenses.clear()
with app.test_client() as client:
    created = client.post("/api/expenses", json={"name":"lunch", "amount":8000})
    assert created.status_code == 201
    assert client.post("/api/expenses", json={"name":"x", "amount":True}).status_code == 400
    rows = client.get("/api/expenses")
    assert rows.status_code == 200 and len(rows.get_json()) == 1
    print(created.status_code, rows.get_json()[0]["amount"])
python test_client.py

서버 프로세스를 따로 실행하지 않아도 Flask 테스트 클라이언트가 요청 처리 흐름을 호출합니다. 정상 결과는 201 8000입니다. 이것은 실제 네트워크·프록시·배포 환경까지 검증하는 테스트는 아닙니다.

데이터 검증과 실행 수명

JSON의 true는 Python에서 bool이 되고 isinstance(True, int)는 참이므로 정수 금액에서 제외하려고 type(amount) is int로 검사했습니다. 잘못된 JSON을 None으로 받아 검증 실패를 반환하는 정책도 명시했습니다.

개발 서버를 인터넷에 그대로 노출하지 않습니다. 특히 디버거를 켜 놓고 공개 배포하지 않습니다. 시험을 마치면 Ctrl+C로 종료하고 재실행 시 목록이 초기화되는지 확인합니다. 거래를 영구 보관하려면 저장소와 트랜잭션을 연결해야 합니다.