REST API 기본 설명
https://swlock.blogspot.com/2021/03/python-rest-api.html
지난 글에서는 REST API POST/GET 예제로만 만들었습니다.
이번에는 좀 더 복잡한 예제를 만들었는데
REST API 주고받는 규격 부분은 서버 측과 약속이 필요한 부분입니다.
여기 예제에서는 json 으로 처리했으며 이 부분은 다른 서버와는 다를 수 있습니다.
Flask 서버로 만든 예제입니다.
/stock/<상품> 이런형태로 여기에 POST/PUT/GET/PATCH/DELETE가 이루어집니다.
각각의 기본 설명은 이전 설명을 참고하세요.
from flask import Flask, make_response, jsonify, request stock = { "fruit": { "apple": 10, "banana": 20 } } app = Flask(__name__) @app.route("/stock") def get_stock(): res = make_response(jsonify(stock), 200) return res @app.route("/stock/<goods>") def get_goods(goods): """ Returns a goods from stock """ if goods in stock: res = make_response(jsonify(stock[goods]), 200) return res res = res = make_response(jsonify({"error": "Not found"}), 404) return res @app.route("/stock/<goods>", methods=["POST"]) def create_goods(goods): """ Creates a new goods if it doesn't exist """ req = request.get_json() if goods in stock: res = make_response(jsonify({"error": "goods already exists"}), 400) return res stock.update({goods: req}) res = make_response(jsonify({"message": "goods created"}), 201) return res @app.route("/stock/<goods>", methods=["PUT"]) def put_goods(goods): """ Replaces or creates a goods """ req = request.get_json() if goods in stock: stock[goods] = req res = make_response(jsonify({"message": "goods replaced"}), 200) return res stock[goods] = req res = make_response(jsonify({"message": "goods created"}), 201) return res @app.route("/stock/<goods>", methods=["PATCH"]) def patch_goods(goods): """ Updates or creates a goods """ req = request.get_json() if goods in stock: for k, v in req.items(): stock[goods][k] = v res = make_response(jsonify({"message": "goods updated"}), 200) return res stock[goods] = req res = make_response(jsonify({"message": "goods created"}), 201) return res @app.route("/stock/<goods>", methods=["DELETE"]) def delete_goods(goods): """ If the goods exists, delete it """ if goods in stock: del stock[goods] res = make_response(jsonify({}), 204) return res res = make_response(jsonify({"error": "goods not found"}), 404) return res if __name__ == '__main__': app.run(debug=True)
client 예제입니다.
import requests def print_roundtrip(response, *args, **kwargs): format_headers = lambda d: '\n'.join(f'{k}: {v}' for k, v in d.items()) print(("" "---------------- request ----------------\n" "{req.method} {req.url}\n" "{reqhdrs}\n" "\n" "{req.body}\n" "---------------- response ----------------\n" "{res.status_code} {res.reason} {res.url}\n" "{reshdrs}\n" "\n" "{res.text}\n" "").format( req=response.request, res=response, reqhdrs=format_headers(response.request.headers), reshdrs=format_headers(response.headers), )) data1={"cat":1,"dog":2} data2={"cat":3,"lion":4,"bird":2} data3={"cat":3,"dog":4} resp = requests.get('http://127.0.0.1:5000/stock', hooks={'response': print_roundtrip}) resp = requests.get('http://127.0.0.1:5000/stock/fruit', hooks={'response': print_roundtrip}) resp = requests.get('http://127.0.0.1:5000/stock/animal', hooks={'response': print_roundtrip}) resp = requests.post('http://127.0.0.1:5000/stock/animal', json=data1, hooks={'response': print_roundtrip}) resp = requests.get('http://127.0.0.1:5000/stock', hooks={'response': print_roundtrip}) resp = requests.get('http://127.0.0.1:5000/stock/animal', hooks={'response': print_roundtrip}) resp = requests.put('http://127.0.0.1:5000/stock/animal', json=data2, hooks={'response': print_roundtrip}) resp = requests.get('http://127.0.0.1:5000/stock/animal', hooks={'response': print_roundtrip}) resp = requests.patch('http://127.0.0.1:5000/stock/animal', json=data3, hooks={'response': print_roundtrip}) resp = requests.get('http://127.0.0.1:5000/stock/animal', hooks={'response': print_roundtrip}) resp = requests.delete('http://127.0.0.1:5000/stock/animal', hooks={'response': print_roundtrip}) resp = requests.get('http://127.0.0.1:5000/stock/animal', hooks={'response': print_roundtrip})
print_roundtrip 함수는 로그 출력을 위한 부분입니다.
순서대로 결과를 보면서 각각 어떻게 동작하는지 살펴 보도록 합시다.
---------------- request ----------------
GET http://127.0.0.1:5000/stock
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
None
---------------- response ----------------
200 OK http://127.0.0.1:5000/stock
Content-Type: application/json
Content-Length: 56
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 06 Oct 2021 23:09:55 GMT
{
"fruit": {
"apple": 10,
"banana": 20
}
}
설명
처음입니다. GET http://127.0.0.1:5000/stock 을 했기 때문에 서버에 존재하는 기본 fruit의 값이 넘어왔습니다.
---------------- request ----------------
GET http://127.0.0.1:5000/stock/fruit
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
None
---------------- response ----------------
200 OK http://127.0.0.1:5000/stock/fruit
Content-Type: application/json
Content-Length: 35
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 06 Oct 2021 23:09:55 GMT
{
"apple": 10,
"banana": 20
}
설명
GET http://127.0.0.1:5000/stock/fruit 이 동작입니다. fruit안에 있는 값을 넘겨 받습니다.
---------------- request ----------------
GET http://127.0.0.1:5000/stock/animal
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
None
---------------- response ----------------
404 NOT FOUND http://127.0.0.1:5000/stock/animal
Content-Type: application/json
Content-Length: 27
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 06 Oct 2021 23:09:55 GMT
{
"error": "Not found"
}
설명
GET http://127.0.0.1:5000/stock/animal 입니다. 이동작은 animal이란곳에는 아무런 데이터가 없기 때문에 404에러가 리턴됩니다.
---------------- request ----------------
POST http://127.0.0.1:5000/stock/animal
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 20
Content-Type: application/json
b'{"cat": 1, "dog": 2}'
---------------- response ----------------
201 CREATED http://127.0.0.1:5000/stock/animal
Content-Type: application/json
Content-Length: 33
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 06 Oct 2021 23:09:55 GMT
{
"message": "goods created"
}
설명
animal에 없는걸 알았으니 이번에는 넣을 차례입니다.
POST http://127.0.0.1:5000/stock/animal 여기에 b'{"cat": 1, "dog": 2}' 이값을 넣습니다.
---------------- request ----------------
GET http://127.0.0.1:5000/stock
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
None
---------------- response ----------------
200 OK http://127.0.0.1:5000/stock
Content-Type: application/json
Content-Length: 104
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 06 Oct 2021 23:09:55 GMT
{
"animal": {
"cat": 1,
"dog": 2
},
"fruit": {
"apple": 10,
"banana": 20
}
}
설명
전체 값을 읽어보면 animal,fruit 모두 나옵니다.
---------------- request ----------------
GET http://127.0.0.1:5000/stock/animal
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
None
---------------- response ----------------
200 OK http://127.0.0.1:5000/stock/animal
Content-Type: application/json
Content-Length: 28
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 06 Oct 2021 23:09:55 GMT
{
"cat": 1,
"dog": 2
}
설명
구체적으로 animal 만 GET할 수도 있습니다.
---------------- request ----------------
PUT http://127.0.0.1:5000/stock/animal
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 32
Content-Type: application/json
b'{"cat": 3, "lion": 4, "bird": 2}'
---------------- response ----------------
200 OK http://127.0.0.1:5000/stock/animal
Content-Type: application/json
Content-Length: 34
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 06 Oct 2021 23:09:55 GMT
{
"message": "goods replaced"
}
설명
이번엔 PUT입니다. 이건 존재하는 값을 교체하는 것입니다. 즉 animal 전체가 교체됩니다.
---------------- request ----------------
GET http://127.0.0.1:5000/stock/animal
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
None
---------------- response ----------------
200 OK http://127.0.0.1:5000/stock/animal
Content-Type: application/json
Content-Length: 43
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 06 Oct 2021 23:09:55 GMT
{
"bird": 2,
"cat": 3,
"lion": 4
}
설명
교체한 값을 읽어봅니다. PUT으로 넣은값이 잘들어가 있습니다.
---------------- request ----------------
PATCH http://127.0.0.1:5000/stock/animal
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 20
Content-Type: application/json
b'{"cat": 3, "dog": 4}'
---------------- response ----------------
200 OK http://127.0.0.1:5000/stock/animal
Content-Type: application/json
Content-Length: 33
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 06 Oct 2021 23:09:55 GMT
{
"message": "goods updated"
}
설명
PATCH는 PUT과 비슷하긴한데 전체 교체가 아니라 있는 아이템만 교체하거나 추가됩니다. 그래서 삭제는 이루어 지지 않습니다.
---------------- request ----------------
GET http://127.0.0.1:5000/stock/animal
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
None
---------------- response ----------------
200 OK http://127.0.0.1:5000/stock/animal
Content-Type: application/json
Content-Length: 56
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 06 Oct 2021 23:09:55 GMT
{
"bird": 2,
"cat": 3,
"dog": 4,
"lion": 4
}
설명
다시 읽어보면 추가되거나 교체한 항목이 존재합니다.
---------------- request ----------------
DELETE http://127.0.0.1:5000/stock/animal
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 0
None
---------------- response ----------------
204 NO CONTENT http://127.0.0.1:5000/stock/animal
Content-Type: application/json
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 06 Oct 2021 23:09:55 GMT
설명
DELTE는 animal 데이터를 삭제합니다.
---------------- request ----------------
GET http://127.0.0.1:5000/stock/animal
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
None
---------------- response ----------------
404 NOT FOUND http://127.0.0.1:5000/stock/animal
Content-Type: application/json
Content-Length: 27
Server: Werkzeug/1.0.1 Python/3.8.3
Date: Wed, 06 Oct 2021 23:09:55 GMT
{
"error": "Not found"
}
설명
삭제한것을 읽어보면 404 에러가 발생합니다. 정상적으로 삭제되었습니다.
예제를 하나씩 따라하다보면 REST API가 이해가 되리라 생각됩니다.
댓글 없음:
댓글 쓰기