Python을 배워보자

Flask로 RESTful API 구현 및 Vue.js와의 CORS 문제 해결

_Blue_Sky_ 2025. 3. 1. 20:38
728x90

 

Python의 경량 프레임워크 Flask를 사용해 Django 없이 간단한 RESTful API를 구현하는 방법을 소개합니다. GET, POST, PUT, DELETE 메서드로 아이템을 관리하며, Vue.js 프론트엔드와 연동 시 발생할 수 있는 CORS 문제를 flask-cors로 해결합니다. 메모리 내 데이터로 동작하는 기본 예제와 Oracle DB 연결 옵션을 제공하며, 특정 출처와 메서드를 제한하는 CORS 설정도 다룹니다. Vue.js에서 Flask API를 호출하는 간단한 예제 포함.
 


Python으로 Django를 사용하지 않고 간단한 RESTful API를 구현하려면, FlaskFastAPI 같은 가벼운 프레임워크가 적합합니다. 여기서는 초경량 프레임워크인 Flask를 사용해 간단한 예제를 제공하겠습니다. FastAPI도 훌륭하지만, Flask가 더 간단하고 직관적이어서 먼저 소개합니다.

Flask로 간단한 RESTful API 구현
1. 설치
bash
 
pip install flask
2. 코드 예제 (app.py)
python
 
from flask import Flask, request, jsonify

app = Flask(__name__)

# 간단한 데이터 저장소 (메모리 내)
items = [
    {"id": 1, "name": "Item 1"},
    {"id": 2, "name": "Item 2"}
]

# GET: 모든 아이템 조회
@app.route('/items', methods=['GET'])
def get_items():
    return jsonify(items)

# GET: 특정 ID로 아이템 조회
@app.route('/items/<int:item_id>', methods=['GET'])
def get_item(item_id):
    item = next((item for item in items if item['id'] == item_id), None)
    if item:
        return jsonify(item)
    return jsonify({"error": "Item not found"}), 404

# POST: 새 아이템 추가
@app.route('/items', methods=['POST'])
def create_item():
    data = request.get_json()
    if not data or 'name' not in data:
        return jsonify({"error": "Name is required"}), 400
    new_id = max(item['id'] for item in items) + 1 if items else 1
    new_item = {"id": new_id, "name": data['name']}
    items.append(new_item)
    return jsonify(new_item), 201

# PUT: 아이템 수정
@app.route('/items/<int:item_id>', methods=['PUT'])
def update_item(item_id):
    item = next((item for item in items if item['id'] == item_id), None)
    if not item:
        return jsonify({"error": "Item not found"}), 404
    data = request.get_json()
    if 'name' in data:
        item['name'] = data['name']
    return jsonify(item)

# DELETE: 아이템 삭제
@app.route('/items/<int:item_id>', methods=['DELETE'])
def delete_item(item_id):
    global items
    item = next((item for item in items if item['id'] == item_id), None)
    if not item:
        return jsonify({"error": "Item not found"}), 404
    items = [item for item in items if item['id'] != item_id]
    return jsonify({"message": "Item deleted"})

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

 
 
3. 실행
bash
 
python app.py
  • 서버가 http://localhost:5000에서 시작됩니다.

4. API 엔드포인트 테스트
curl이나 Postman으로 테스트할 수 있습니다.
GET: 모든 아이템 조회
bash
 
curl http://localhost:5000/items
응답:
json
 
[
    {"id": 1, "name": "Item 1"},
    {"id": 2, "name": "Item 2"}
]
GET: 특정 아이템 조회
bash
 
curl http://localhost:5000/items/1
응답:
json
 
{"id": 1, "name": "Item 1"}
POST: 새 아이템 추가
bash
 
curl -X POST -H "Content-Type: application/json" -d '{"name": "Item 3"}' http://localhost:5000/items
응답:
json
 
{"id": 3, "name": "Item 3"}
PUT: 아이템 수정
bash
 
curl -X PUT -H "Content-Type: application/json" -d '{"name": "Updated Item"}' http://localhost:5000/items/1
응답:
json
 
{"id": 1, "name": "Updated Item"}
DELETE: 아이템 삭제
bash
 
curl -X DELETE http://localhost:5000/items/1
응답:
json
 
{"message": "Item deleted"}

특징
  • 경량: Flask는 최소한의 기능만 제공하며, 필요에 따라 확장 가능.
  • RESTful: GET, POST, PUT, DELETE 등 HTTP 메서드를 지원.
  • 데이터: 예제에서는 메모리 내 리스트를 사용했지만, DB(예: SQLite, Oracle)를 연결할 수도 있음.

DB 연결 추가 (선택 사항)
Oracle DB를 사용 중이시니, 간단히 연결 예제를 추가합니다.
설치
bash
 
pip install cx_Oracle
수정된 app.py (Oracle 연결 예시)
python
 
from flask import Flask, jsonify
import cx_Oracle

app = Flask(__name__)

# Oracle DB 연결 설정
dsn = cx_Oracle.makedsn("localhost", 1521, service_name="ORCL")
connection = cx_Oracle.connect(user="your_username", password="your_password", dsn=dsn)

@app.route('/items', methods=['GET'])
def get_items():
    cursor = connection.cursor()
    cursor.execute("SELECT id, name FROM items")  # 테이블이 있다고 가정
    rows = cursor.fetchall()
    cursor.close()
    return jsonify([{"id": row[0], "name": row[1]} for row in rows])

if __name__ == '__main__':
    try:
        app.run(debug=True, host='0.0.0.0', port=5000)
    finally:
        connection.close()
주의
  • items 테이블이 Oracle DB에 존재해야 함.
  • 접속 정보는 실제 환경에 맞게 수정.

FastAPI 대안
만약 비동기 지원과 자동 Swagger UI가 필요하다면 FastAPI도 추천합니다. 설치 및 기본 예제는 아래와 같습니다:
bash
 
pip install fastapi uvicorn
python
 
from fastapi import FastAPI

app = FastAPI()

@app.get("/items")
async def read_items():
    return [{"id": 1, "name": "Item 1"}]
bash
 
uvicorn main:app --reload

Flask로 충분히 간단한 RESTful API를 구현할 수 있습니다. 추가로 궁금한 점 있으면 말씀해주세요!

Flask 자체로는 CORS(Cross-Origin Resource Sharing) 설정이 기본적으로 제공되지 않기 때문에, Vue.js 같은 프론트엔드에서 Flask 백엔드 API를 호출할 때 CORS 문제가 발생할 수 있습니다. 예를 들어, Vue.js가 http://localhost:3000에서 실행되고 Flask가 http://localhost:5000에서 실행된다면, 브라우저는 서로 다른 출처(포트가 다름)로 인식해 요청을 차단할 가능성이 있습니다.

 
 
CORS 문제 확인
CORS 오류가 발생하면 브라우저 콘솔에 아래와 비슷한 메시지가 나타납니다:
 
Access to XMLHttpRequest at 'http://localhost:5000/items' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the server.

해결 방법: Flask에 CORS 추가
Flask에서 CORS를 처리하려면 flask-cors 확장을 설치하고 설정하면 됩니다.
1. 설치
bash
 
pip install flask-cors
2. 코드 수정 (app.py)
python
 
from flask import Flask, request, jsonify
from flask_cors import CORS

app = Flask(__name__)
CORS(app)  # 모든 출처 허용 (기본 설정)

# 간단한 데이터 저장소
items = [
    {"id": 1, "name": "Item 1"},
    {"id": 2, "name": "Item 2"}
]

@app.route('/items', methods=['GET'])
def get_items():
    return jsonify(items)

@app.route('/items/<int:item_id>', methods=['GET'])
def get_item(item_id):
    item = next((item for item in items if item['id'] == item_id), None)
    if item:
        return jsonify(item)
    return jsonify({"error": "Item not found"}), 404

@app.route('/items', methods=['POST'])
def create_item():
    data = request.get_json()
    if not data or 'name' not in data:
        return jsonify({"error": "Name is required"}), 400
    new_id = max(item['id'] for item in items) + 1 if items else 1
    new_item = {"id": new_id, "name": data['name']}
    items.append(new_item)
    return jsonify(new_item), 201

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

CORS 설정 세부 조정
CORS(app)은 모든 출처에서 요청을 허용합니다. 보안을 위해 특정 출처만 허용하려면 아래처럼 수정하세요:
특정 출처만 허용
python
 
CORS(app, resources={r"/items*": {"origins": "http://localhost:3000"}})
  • http://localhost:3000에서 오는 요청만 허용.
  • Vue.js 개발 서버가 3000 포트에서 실행 중일 때 유용.
메서드 제한
python
 
CORS(app, resources={r"/items*": {"origins": "http://localhost:3000", "methods": ["GET", "POST"]}})
  • GET과 POST만 허용.

Vue.js에서 테스트
Vue.js에서 Flask API를 호출하는 코드는 이전에 제공한 것과 동일하게 작동합니다. 예:
vue
 
<template>
  <div>
    <button @click="fetchItems">Get Items</button>
    <pre>{{ items }}</pre>
  </div>
</template>

<script>
export default {
  data() {
    return {
      items: [],
    };
  },
  methods: {
    async fetchItems() {
      try {
        const response = await this.$axios.get('http://localhost:5000/items');
        this.items = response.data;
      } catch (error) {
        console.error('Error:', error);
      }
    },
  },
};
</script>

CORS 문제 없을 때
위처럼 flask-cors를 설정하면 Vue.js에서 Flask로의 요청이 정상적으로 처리됩니다. 설정을 추가하지 않으면 CORS 오류가 발생하니, 반드시 포함하세요.
개발 환경 팁
  • Flask의 debug=True 모드에서는 CORS 설정이 잘 동작하지만, 배포 시에는 서버 설정(Nginx, Gunicorn 등)에서도 CORS를 고려해야 할 수 있습니다.

결론
Flask 자체로는 CORS 문제가 발생할 수 있지만, flask-cors를 사용하면 쉽게 해결됩니다. 위 코드를 적용하면 Vue.js와 Flask 간 통신에 문제가 없을 겁니다. 추가 질문 있으면 말씀해주세요!
728x90