Flask with REST API¶
(1) API(Application Programming Interface)란?¶
- 프로그램 간 상호작용을 돕는 매개체
- 올바른 값을 사용자가 요청하지 못했다면 오류를 출력하는 인터페이스 제공
(2) REST(Representational State Transfer)란?¶
- 웹 서버가 요청을 응답하는 방법 중 하나
- 데이터가 아닌 일종의 자원 관점으로 접근한다.
"HTTP URI"로 자원을 명시하고, "HTTP Method"로 해당 자원에 대한 CRUD를 진행한다.
- HTTP URI란? : 웹 상에서 자원을 요청할 때, 해당 자원의 위치를 지정한다. URL은 Location(장소)의 개념이 강하며, URI는 Identifier(식별자)의 개념이 강하므로, 개념적으로 보면 URL은 URI의 하위 카테고리에 위치해있다.
- HTTP Method란? : 정보를 요청할 때 사용될 수 있는 포로토콜(get, post, put...)의 집합체
왜 자원의 관점으로 접근해야 하는가? : Resource(URI)가 모두 동일한 장소를 가리키고 있음에도 HTTP Method에서 사용하는 프로토콜에 따라서 각각 다른 행동을 취해줄 수 있기 때문이다.
- Stateless(무상태성) : Clinet의 Context를 서버에서 유지하지 않는다. 각 사용자의 요청만 독립적이고 즉각적으로 처리만 해주면 된다. 자원을 저장해서 처리하는 과정이 생략되기 때문에 훨씬 원활한 사용이 가능하다.
(2.1) REST API example¶
In [2]:
# Coffee shop example
from flask import Flask, jsonify, request
app = Flask(__name__)
menus = [
{"id" : 1, "name" : "Expresso", "price" : 3800},
{"id" : 2, "name" : "Americano", "price" : 4800},
{"id" : 3, "name" : "CafeLatte", "price" : 5800},
]
@app.route('/')
def hello_flask():
return "Hello World!"
# GET /menus | 자료를 가지고 온다.
# menus의 정보로 접근한다.
@app.route('/menus')
def get_menus():
# 기존 list 형식으로는 jsonify가 되지 않으므로 새로운 list생성
return jsonify({"menus" : menus})
# POST /menus | 자료를 자원에 추가한다.
@app.route('/menus', methods = ['POST'])
def create_menu():
# 전달받은 자료를 menus 자원에 추가
# json과 dictionary는 다른 데이터 타입이므로 하기된 변환과정을 거쳐야 함.
request_data = request.get_json() # {"name" : ..., "price" : ...}
new_menu = {
"id" : 4,
"name" : request_data['name'],
"price" : request_data['price'],
}
# 생성된 새로운 메뉴를 추가
menus.append(new_menu)
# json 형식의 메뉴 반환
return jsonify(new_menu)
if __name__ == '__name__':
app.run()
--------------------------------------------------------------------------- ModuleNotFoundError Traceback (most recent call last) ~\AppData\Local\Temp/ipykernel_9900/1186557023.py in <module> 1 # Coffee shop example ----> 2 from flask import Flask, jsonify, request 3 4 app = Flask(__name__) 5 ModuleNotFoundError: No module named 'flask'
- 가상환경으로 들어가서
flask run
을 입력하면 주소창 출력 - 해당 주소창으로 들어가면 "Hello World!" 출력
- 주소창에 "/menus"를 입력하면 메뉴가 뜨는 것을 확인할 수 있다.
(2.2) Postman 설치 및 활용¶
- "postman" 검색 후 다운로드 실시
- 로그인 후(Google 아이디 사용 가능) 상단에서 "Workspaces" 선택
- "Create Collection" 후 이름 설정 실시
In [ ]:
{
"menus": [
{
"id": 1,
"name": "Expresso",
"price": 3800
},
{
"id": 2,
"name": "Americano",
"price": 4800
},
{
"id": 3,
"name": "CafeLatte",
"price": 5800
},
{
"id": 4,
"name": "dolce Latte",
"price": 5100
}
]
}
- 생성한 Collection이 띄워진 상태에서 상단 메뉴바 바로 아래 탭에서 +버튼 클릭
- (Read) 상태는 "GET"으로 만든 후, 입력창에 cmd를 통해 출력된 주소를 입력하여
Hello World!"
출력확인 - 상태는 "GET"으로 만든 후, 입력창에 '출력된 주소/menus'를 입력하여 json 형태의 자료가 출력되는지 확인. Save를 통해 저장 가능
- 정의되지 않은 호출을 진행할 경우, "404 NOT FOUND" 출력(오류코드)
In [ ]:
# request
{
"name" : "dolce Latte",
"price" : 5100
}
- (Create) 주소입력창 하단 메뉴에서 "Body" 클릭 후, 해당 메뉴 하단의 "raw"를 통해 데이터 요청 실시 (형태 : json, raw와 같은 수준의 메뉴 우측 끝에 request 형태 지정 가능)
In [3]:
# Post를 두 번 눌렀을 때 처리 결과
{
"menus": [
{
"id": 1,
"name": "Expresso",
"price": 3800
},
{
"id": 2,
"name": "Americano",
"price": 4800
},
{
"id": 3,
"name": "CafeLatte",
"price": 5800
},
{
"id": 4,
"name": "dolce Latte",
"price": 5100
},
{
"id": 4,
"name": "dolce Latte",
"price": 5100
}
]
}
Out[3]:
{'menus': [{'id': 1, 'name': 'Expresso', 'price': 3800}, {'id': 2, 'name': 'Americano', 'price': 4800}, {'id': 3, 'name': 'CafeLatte', 'price': 5800}, {'id': 4, 'name': 'dolce Latte', 'price': 5100}, {'id': 4, 'name': 'dolce Latte', 'price': 5100}]}
In [ ]:
@app.route('/<name>')
def my_view_func(name):
return name
- DELETE 구현
In [ ]:
# Delete /<삭제할 id번호> | 자료를 삭제한다.
# <삭제할 id번호>에서 반드시 "int:"를 넣어 타입을 정의한다.
@app.route('/menus/<int:id_num>', methods=['DELETE'])
def delete_menu(id_num):
index_num = -1
# for문을 통해 id값과 같은 id_num이 있는지를 탐색합니다.
for i in range(len(menus)):
# 만약 id_num과 지정된 id가 같다면
if id_num == menus[i].get('id'):
# 삭제할 인덱스 저장
index_num = i
break
# 인덱스 삭제
if index_num != -1:
del menus[index_num]
# 삭제된 menus list을 json형태로 반환
return jsonify(menus)
- PUT 구현
In [ ]:
Update /<수정할 id번호> | 자료를 수정한다.
@app.route('/menus/<int:id_num>', methods = ['PUT'])
def update_menu(id_num):
# 전달받은 자료를 menus 자원에 추가
# json과 dictionary는 다른 데이터 타입이므로 하기된 변환과정을 거쳐야 함.
updated_request_data = request.get_json() # {"name" : ..., "price" : ...}
update_menu_data = {
"name" : updated_request_data['name'],
"price" : updated_request_data['price'],
}
# for문을 통해 id값과 같은 id_num이 있는지 탐색
for i in range(len(menus)):
# 만약 id_num과 지정된 id가 같다면
if id_num == menus[i].get('id'):
menus[i]['name'] = update_menu_data['name']
menus[i]['price'] = update_menu_data['price']
break
# menus 반환
return jsonify(menus)
Bonus Mission 1 : ID 갱신¶
- 새로운 menus를 추가할 때마다 id를 하나씩 증가하도록 코드를 수정하라.
In [ ]:
max_value = -1
for i in range(len(menus)):
if menus[i]['id'] > max_value:
max_value = menus[i]['id']
- 이후 i 대신 max_value를 넣으면 정상작동한다.
Bonus Mission 2 : 데이터베이스 연동¶
- 수업에서 다룬 API는 서버 재시작 시 정보가 리셋되므로, 이 문제를 해결하기 위해서는 데이터베이스를 도입하여 flask와 연동해야 한다.
- SQL과 ORM 중 하나를 선택하여 데이터베이스와 flask app을 연동한다.
- 데이터베이스 연동을 진행하기 위해서는, 데이터베이스 설치와 더불어 전용 문법을 적용하여 app.py 내부의 파일을 전부 수정해야 한다.
- 본 프로젝트를 오랜 시간 진행해보았지만, 실력의 한계를 느껴 해당 보너스 미션은 포기한다.
'전문지식 함양 > TIL' 카테고리의 다른 글
[프로그래머스 겨울방학 인공지능 과정] EDA example (0) | 2022.01.13 |
---|---|
[프로그래머스 겨울방학 인공지능 과정] FLASK 실습 (0) | 2022.01.13 |
[프로그래머스 겨울방학 인공지능 과정] Flask 기초 (0) | 2022.01.10 |
[프로그래머스 겨울방학 인공지능 과정] 1주차 실습과제 (0) | 2022.01.09 |
[프로그래머스 겨울방학 인공지능 과정] Matplotlib 기초 (0) | 2022.01.07 |