from flask import Flask, request, jsonify, current_app
from flask.json import JSONEncoder
from sqlalchemy import create_engine, text
## Default JSON encoder는 set를 JSON으로 변환할 수 없다.
## 그럼으로 커스텀 엔코더를 작성해서 set을 list로 변환하여
## JSON으로 변환 가능하게 해주어야 한다.
class CustomJSONEncoder(JSONEncoder):
def default(self, obj):
if isinstance(obj, set):
return list(obj)
return JSONEncoder.default(self, obj)
def get_user(user_id):
user = current_app.database.execute(text("""
SELECT
id,
name,
email,
profile
FROM users
WHERE id = :user_id
"""), {
'user_id' : user_id
}).fetchone()
return {
'id' : user['id'],
'name' : user['name'],
'email' : user['email'],
'profile' : user['profile']
} if user else None
def insert_user(user):
return current_app.database.execute(text("""
INSERT INTO users (
name,
email,
profile,
hashed_password
) VALUES (
:name,
:email,
:profile,
:password
)
"""), user).lastrowid
def insert_tweet(user_tweet):
return current_app.database.execute(text("""
INSERT INTO tweets (
user_id,
tweet
) VALUES (
:id,
:tweet
)
"""), user_tweet).rowcount
def insert_follow(user_follow):
return current_app.database.execute(text("""
INSERT INTO users_follow_list (
user_id,
follow_user_id
) VALUES (
:id,
:follow
)
"""), user_follow).rowcount
def insert_unfollow(user_unfollow):
return current_app.database.execute(text("""
DELETE FROM users_follow_list
WHERE user_id = :id
AND follow_user_id = :unfollow
"""), user_unfollow).rowcount
def get_timeline(user_id):
timeline = current_app.database.execute(text("""
SELECT
t.user_id,
t.tweet
FROM tweets t
LEFT JOIN users_follow_list ufl ON ufl.user_id = :user_id
WHERE t.user_id = :user_id
OR t.user_id = ufl.follow_user_id
"""), {
'user_id' : user_id
}).fetchall()
return [{
'user_id' : tweet['user_id'],
'tweet' : tweet['tweet']
} for tweet in timeline]
def create_app(test_config = None):
app = Flask(__name__)
app.json_encoder = CustomJSONEncoder
if test_config is None:
app.config.from_pyfile("config.py")
else:
app.config.update(test_config)
database = create_engine(app.config['DB_URL'], encoding = 'utf-8', max_overflow = 0)
app.database = database
@app.route("/ping", methods=['GET'])
def ping():
return "pong"
@app.route("/sign-up", methods=['POST'])
def sign_up():
new_user = request.json
new_user_id = insert_user(new_user)
new_user = get_user(new_user_id)
return jsonify(new_user)
@app.route('/tweet', methods=['POST'])
def tweet():
user_tweet = request.json
tweet = user_tweet['tweet']
if len(tweet) > 300:
return '300자를 초과했습니다', 400
insert_tweet(user_tweet)
return '', 200
@app.route('/follow', methods=['POST'])
def follow():
payload = request.json
insert_follow(payload)
return '', 200
@app.route('/unfollow', methods=['POST'])
def unfollow():
payload = request.json
insert_unfollow(payload)
return '', 200
@app.route('/timeline/<int:user_id>', methods=['GET'])
def timeline(user_id):
return jsonify({
'user_id' : user_id,
'timeline' : get_timeline(user_id)
})
return app
회원가입 테스트
http -v POST localhost:5000/sign-up name="어피치" email="123@gmail.com" profile="HI~" password="1234" && http -v POST localhost:5000/sign-up name="라이언" email="456@gmail.com" profile="HI~" password="12345"
tweet 테스트
$ http -v POST localhost:5000/tweet id=1 tweet="My first Tweet"
POST /tweet HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 38
Content-Type: application/json
Host: localhost:5000
User-Agent: HTTPie/2.4.0
{
"id": "1",
"tweet": "My first Tweet"
}
HTTP/1.0 200 OK
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Sun, 21 Feb 2021 04:19:32 GMT
Server: Werkzeug/1.0.1 Python/3.8.5
timeline 테스트
lego7@DESKTOP-VLQ1E3A MINGW64 ~/Desktop/Projects/api (master)
$ http -v GET localhost:5000/timeline/1
GET /timeline/1 HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:5000
User-Agent: HTTPie/2.4.0
HTTP/1.0 200 OK
Content-Length: 170
Content-Type: application/json
Date: Sun, 21 Feb 2021 04:20:26 GMT
Server: Werkzeug/1.0.1 Python/3.8.5
{
"timeline": [
{
"tweet": "Hello World",
"user_id": 1
},
{
"tweet": "My first Tweet",
"user_id": 1
}
],
"user_id": 1
}
반응형
'SW ENGINEERING > Flask' 카테고리의 다른 글
보안 점검 SQL Injection (0) | 2021.02.24 |
---|---|
API 개발하기(16) - DB Schema (0) | 2021.02.21 |
API 개발하기(14) - timeline 엔드포인트 (0) | 2021.02.21 |
API 개발하기(13) - tweet 엔드포인트 (0) | 2021.02.21 |
API 개발하기(12) - MySQL 설정 & 회원가입엔드포인트 (0) | 2021.02.18 |
최근댓글