API란?
- Application Programming Interface로 요청하는 쪽과 응답하는 쪽 간에 통신 방법을 정의.
- 일반적으로 Server와 Client로 구분되어 사용.
→ Client에서 Server로 요청을 보내면, Server는 이에 응답함
- API의 사용 목적에 따라 다양한 종류의 API가 사용 중.
→ RESTfull 방식 : 최근 가장 많이 사용되는 방식으로, HTTP/1.1 기반 통신을 사용하며 json, xml 형식의 데이터를 직접 전달한다.
→ RPC 방식 : Remote Procedure Call로 Client가 원격으로 Server에 접속해 통신. gRPC가 등장하며 많이 쓰이는 추세이다.
- Python 라이브러리는 RESTful(Flask, FastAPI) 방식과 rpc(gRPC) 방식 모두 구현 가능.


Flask
- 가볍고 간편하게 구현할 수 있는 Rest API 라이브러리.
- 소규모 & 중규모 프로젝트에 적합하며 표준화되지 않았다.
- HTTP/1.1 통신은 Connecttion 당 하나의 처리만 가능하기때문에 동시에 많은 요청을 처리할 때 병목이 발생할 수 있다.
- 프로토타입이나 기능 Test 시 사용 권장
from flask import Flask, request, jsonify
from flask_swagger_ui import get_swaggerui_blueprint
app = Flask(__name__)
SWAGGER_URL = '/swagger'
API_URL = '/static/swagger.json'
swaggerui_blueprint = get_swaggerui_blueprint(
SWAGGER_URL,
API_URL,
config={
'app_name': "My Flask App"
}
)
app.register_blueprint(swaggerui_blueprint, url_prefix=SWAGGER_URL)
@app.route('/')
def hello():
"""
This is a simple example of a Flask endpoint
---
description: Returns a simple message
responses:
200:
description: A simple message
"""
return 'Hello, World!'
@app.route('/user/<username>')
def show_user_profile(username):
"""
This is an example of a Flask endpoint with a parameter
---
parameters:
- name: username
in: path
type: string
required: true
description: The username to look up
responses:
200:
description: Returns a message with the specified username
"""
return f'User {username}'
@app.route('/post', methods=['POST'])
def create_post():
"""
This is an example of a Flask endpoint that accepts a POST request
---
parameters:
- name: body
in: body
required: true
schema:
type: object
properties:
message:
type: string
responses:
201:
description: Returns the data sent in the request in JSON format
"""
data = request.get_json()
return jsonify(data), 201
if __name__ == '__main__':
app.run(debug=True)
FastAPI
- Flask 대비 속도가 빠르고 효율성을 높인 Framework이다.
- asyncio와 type hint를 통해 개발 생산성은 높이고 버그를 줄여준다.
- 고성능을 보장하여 Flask 대비 장점이 많은 것으로 평가받음.
- Flask처럼 HTTP/1.1 통신의 한계를 가지고 있다.
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI(title="My FastAPI App", docs_url="/docs", redoc_url="/redoc")
class Item(BaseModel):
name: str
price: float
@app.get("/")
def read_root():
"""
This is a simple example of a FastAPI endpoint
"""
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
"""
This is an example of a FastAPI endpoint with a path parameter
"""
return {"item_id": item_id, "q": q}
@app.post("/items/")
def create_item(item: Item):
"""
This is an example of a FastAPI endpoint that accepts a JSON request
"""
return item.dict()
@app.get("/docs")
def docs():
"""
This is an example of a FastAPI endpoint for swagger documentation
"""
return JSONResponse(content=app.openapi())
@app.get("/redoc")
def redoc():
"""
This is an example of a FastAPI endpoint for redoc documentation
"""
return HTMLResponse(content=app.openapi(dumps=lambda x: x))
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
gRPC
- HTTP/2.0 이용한 양방향 스트리밍 제공 ( 서버가 일방적으로 제공하는 것이 아님 )
→ Latency와 리소스 사용 측면에서 HTTP/1.1의 성능을 끌어올렸다.
→ Connection 당 여러개의 처리가 가능하다.
- protobuff로 바이너리 형태의 값을 전달하여 속도가 매우 빠르다.
- MSA 프로젝트 시 사용 권장
1) .proto 파일 구현
syntax = "proto3";
package greet;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
2) gRPC 서버 구현
import grpc
from concurrent import futures
import time
from protos.greeter_pb2 import (
HelloRequest,
HelloReply
)
from protos.greeter_pb2_grpc import (
GreeterServicer,
add_GreeterServicer_to_server
)
class MyGreeterServicer(GreeterServicer):
def SayHello(self, request, context):
return HelloReply(message='Hello, {}!'.format(request.name))
def run_server(host, port):
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
add_GreeterServicer_to_server(MyGreeterServicer(), server)
server.add_insecure_port(f'{host}:{port}')
server.start()
print(f"Server started at {host}:{port}...")
try:
while True:
time.sleep(60 * 60 * 24) # one day in seconds
except KeyboardInterrupt:
server.stop(0)
if __name__ == '__main__':
run_server('0.0.0.0', 50051)
3) gRPC Client 구현
import grpc
from protos.greeter_pb2 import HelloRequest
from protos.greeter_pb2_grpc import GreeterStub
def run_client(host, port):
channel = grpc.insecure_channel(f'{host}:{port}')
stub = GreeterStub(channel)
response = stub.SayHello(HelloRequest(name='John Doe'))
print(response.message)
if __name__ == '__main__':
run_client('localhost', 50051)
4) gRPC Swagger 구현
def run_server(host, port):
server = SwaggerDecoratedServer(
grpc.server(futures.ThreadPoolExecutor(max_workers=10)),
swagger_host=host,
swagger_port=port+1,
)
add_GreeterServicer_to_server(MyGreeterServicer(), server)
server.add_insecure_port(f'{host}:{port}')
server.start()
print(f"gRPC Server started at {host}:{port}...")
print(f"Swagger documentation available at http://{host}:{port+1}/docs")
try:
while True:
time.sleep(60 * 60 * 24) # one day in seconds
except KeyboardInterrupt:
server.stop(0)
비교
Flask | FastAPI | gRPC | |
통신방법 | RESTful | RESTful | RPC |
네트워크 | HTTP1.1 | HTTP1.1 | HTTP2.0 |
데이터 형식 | json,xml 등 | json,xml 등 | 바이너리 |
속도 | 느림 | 빠름 | 빠름 |
사용처 | 테스트, 프로토타입 | WEB/APP 서비스 | MSA 개발 시 |
비교 표를 위해 이렇게 표현했지만, Flask도 아직까지 충분히 좋은 성능을 보여주고 있어 많은 부분에서 사용 중이다. 하지만 성능적인 부분을 고려하면 앞으로는 FastAPI와 gRPC를 상황에 맞게 사용하게 될 것 같다.
'개발공부 > Python알고리즘' 카테고리의 다른 글
[Python] Segment Tree(세그먼트 트리) 설명 및 구현(백준 2042번) (1) | 2023.06.04 |
---|---|
[Python]dictionary를 이용한 알고리즘 시간 단축(feat. hashtable) (0) | 2023.02.04 |
[알고리즘] 다익스트라 vs 크루스칼/프림 차이를 알아보자 (0) | 2023.01.17 |
[알고리즘] 파이썬 프림(prim) & 크루스칼(kruskal) 예제 및 비교 (0) | 2023.01.15 |
[알고리즘] 파이썬 다익스트라(Dijkstra) 최단경로 문제 예 (0) | 2023.01.15 |
댓글