Skip to content

Commit 7d2f6b5

Browse files
committed
users get, post, delete, update impl
1 parent 2f32cd4 commit 7d2f6b5

9 files changed

Lines changed: 236 additions & 140 deletions

File tree

Pipfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ verify_ssl = true
77
pytest = "*"
88
pytest-cov = "*"
99
pylint = "*"
10+
autopep8 = "*"
1011

1112
[packages]
1213
flask = "*"
@@ -16,6 +17,7 @@ flask-migrate = "*"
1617
pymysql = "*"
1718
flask-restplus = "*"
1819
flask-marshmallow = "*"
20+
marshmallow-jsonapi = "*"
1921

2022
[requires]
2123
python_version = "3.7"

Pipfile.lock

Lines changed: 23 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/__init__.py

Lines changed: 3 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,19 @@
11
"""
22
app init
33
"""
4-
54
from flask import Flask, render_template, jsonify
65
from flask_restplus import Resource, Api, fields, reqparse
76
from flask_sqlalchemy import SQLAlchemy
87
from sqlalchemy.exc import SQLAlchemyError
98
from sqlalchemy.sql import text
109
from flask_marshmallow import Marshmallow
10+
from app.api.database import DB
11+
from app.users.views import API
1112

12-
DB = SQLAlchemy()
1313
SQLALCHEMY_DATABASE_URI = \
1414
("mysql+pymysql://{USER}:{PASSWORD}@{ADDR}:{PORT}/{NAME}?charset=utf8")
15-
# API Doc에 대한 설명을 덧 붙이기 위한 생성자
16-
API = Api(version='1.0', title='Board API',
17-
description='A simple Board RESTPlus API',)
1815
# 설명할 API에 대한 것
19-
api_ns = API.namespace('userinfo', description='UserInfo operations')
2016
MA = Marshmallow()
21-
22-
class UserInfo(DB.Model):
23-
""" UserInfo model """
24-
__tablename__ = "userinfo"
25-
__table_args__ = {'mysql_collate' : 'utf8_general_ci'}
26-
id = DB.Column("id", DB.Integer, primary_key=True)
27-
name = DB.Column("name", DB.String(250), nullable=False)
28-
age = DB.Column("age", DB.Integer, nullable=False)
29-
tel = DB.Column("tel", DB.String(20), nullable=False)
30-
email = DB.Column("email", DB.String(50), nullable=False)
31-
created = DB.Column(DB.TIMESTAMP, server_default=text("CURRENT_TIMESTAMP"), nullable=False)
32-
33-
def __init__(self, name, age, tel, email):
34-
self.name = name
35-
self.age = age
36-
self.tel = tel
37-
self.email = email
38-
3917
def create_app() -> (Flask):
4018
""" create_app() 함수를 호출해 앱을 초기화 """
4119

@@ -58,116 +36,5 @@ def create_app() -> (Flask):
5836
API.init_app(app)
5937
MA.init_app(app)
6038

61-
""" API model을 보이기 위한 설명 추가 """
62-
# 나중에 따로 빼야 할 것 같다.
63-
user_info = API.model('UserInfo', {
64-
'name' : fields.String(required=True, description="User's name"),
65-
'age' : fields.Integer(required=True, description="User's age"),
66-
'tel' : fields.String(required=True, description="User's tel"),
67-
'email' : fields.String(required=True, description="User's email")
68-
})
69-
70-
class UserSchema(MA.Schema):
71-
class Meta:
72-
# Fields to expose
73-
fields = ("name", "age", "tel", "email")
74-
75-
76-
77-
""" API.route part"""
78-
@api_ns.route("/hello")
79-
class HelloWorld(Resource):
80-
def get(self):
81-
return {'hello': 'world'}
82-
83-
@api_ns.route('/users')
84-
class Show(Resource):
85-
post_parser = reqparse.RequestParser(bundle_errors=True)
86-
post_parser.add_argument('name', required=True, type=str, help="user name",location='json')
87-
post_parser.add_argument('age', required=True, type=int, help="user age",location='json')
88-
post_parser.add_argument('tel', required=True, type=str, help="user tel",location='json')
89-
post_parser.add_argument('email', required=True, type=str, help="user email",location='json')
90-
def get(self):
91-
user_schema = UserSchema(many=True)
92-
all_users = DB.session.query(UserInfo).all()
93-
result = user_schema.dump(all_users)
94-
return jsonify(result.data)
95-
96-
@api_ns.expect(user_info)
97-
def post(self):
98-
args_ = self.post_parser.parse_args()
99-
user = UserInfo(name=args_['name'], age=args_['age'], tel=args_['tel'], email=args_['email'])
100-
message = "not working"
101-
try:
102-
DB.session.add(user)
103-
DB.session.commit()
104-
message = "success"
105-
except SQLAlchemyError as err:
106-
message = str(err)
107-
DB.session.rollback()
108-
finally:
109-
DB.session.close()
110-
return message
111-
112-
@api_ns.expect(user_info)
113-
def delete(self):
114-
args_ = self.post_parser.parse_args()
115-
user = UserInfo.query.filter_by(name=args_['name']).first()
116-
try:
117-
DB.session.delete(user)
118-
DB.session.commit()
119-
message = "success"
120-
except SQLAlchemyError as err:
121-
message = str(err)
122-
DB.session.rollback()
123-
finally:
124-
DB.session.close()
125-
return message
126-
127-
@api_ns.route('/test')
128-
class Test(Resource):
129-
post_parser = reqparse.RequestParser(bundle_errors=True)
130-
post_parser.add_argument('name', required=True, type=str, help="user name",location='json')
131-
post_parser.add_argument('age', required=True, type=int, help="user age",location='json')
132-
post_parser.add_argument('tel', required=True, type=str, help="user tel",location='json')
133-
post_parser.add_argument('email', required=True, type=str, help="user email",location='json')
134-
def get(self):
135-
return {'test' : 'test'}
136-
137-
@api_ns.expect(user_info)
138-
def post(self):
139-
args_ = self.post_parser.parse_args()
140-
user = UserInfo(name=args_['name'], age=args_['age'], tel=args_['tel'], email=args_['email'])
141-
return {'name' : 'server' + user.name, 'age' : user.age, 'tel' : user.tel, 'email' : user.email}
142-
143-
144-
@api_ns.route('/test')
145-
class HelloWorld(Resource):
146-
post_parser = reqparse.RequestParser(bundle_errors=True)
147-
post_parser.add_argument('name', required=True, type=str, help="user name",location='json')
148-
post_parser.add_argument('tel', type=str, help="user tel",location='json')
149-
150-
def get(self):
151-
userInfo = DB.session.query(UserInfo).all()
152-
import pdb; pdb.set_trace()
153-
return {'hello': 'world'}
154-
155-
@api_ns.expect(user_info)
156-
def post(self):
157-
""" 유저 생성 """
158-
args_ = self.post_parser.parse_args()
159-
user = UserInfo(name=args_['name'], tel=args_['tel'])
160-
message = "not working"
161-
try:
162-
DB.session.add(user)
163-
DB.session.commit()
164-
message = "success"
165-
except SQLAlchemyError as err:
166-
message = str(err)
167-
DB.session.rollback()
168-
finally:
169-
DB.session.close()
170-
return message
171-
17239
""" return part """
173-
return app
40+
return app

app/api/database.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,62 @@
11
from flask import jsonify
2+
from flask import make_response
23
from flask_sqlalchemy import SQLAlchemy
34
from sqlalchemy.exc import IntegrityError
45
from marshmallow import ValidationError
56
from app.constants import STATUS_CODE
6-
from flask_restplus import reqparse
7+
from flask_restplus import reqparse
8+
9+
DB = SQLAlchemy()
10+
11+
class CRUD:
12+
body = ''
13+
status_code = STATUS_CODE.NOT_IMPLEMENTED
14+
def add(self, resource, schema):
15+
try:
16+
DB.session.add(resource)
17+
DB.session.commit()
18+
query = resource.query.get(resource.id)
19+
self.body = jsonify(schema.dump(resource).data)
20+
self.status_code = STATUS_CODE.CREATED
21+
except IntegrityError as error:
22+
DB.session.rollback()
23+
error_message = str(error)
24+
self.body = jsonify({"error": error_message, "type":"IntegrityError"})
25+
if "Duplicate entry" in error_message:
26+
self.status_code = 404
27+
else:
28+
self.status_code = 400
29+
finally:
30+
response = (self.body, self.status_code.value)
31+
response = make_response(response)
32+
33+
return response
34+
35+
def update(self, args, schema):
36+
try:
37+
for key, value in args.items():
38+
setattr(self, key, value)
39+
DB.session.commit()
40+
self.body = jsonify(schema.dump(self).data)
41+
self.status_code = STATUS_CODE.OK
42+
except IntegrityError as error:
43+
DB.session.rollback()
44+
error_message = str(error)
45+
self.body = jsonify({"error": error_message, "type":"IntegrityError"})
46+
if "Duplicate entry" in error_message:
47+
self.status_code = STATUS_CODE.CONFLICT
48+
else:
49+
self.status_code = STATUS_CODE.BAD_REQUEST
50+
finally:
51+
response = (self.body, self.status_code.value)
52+
response = make_response(response)
53+
return response
54+
55+
def delete(self, resource, schema):
56+
DB.session.delete(resource)
57+
DB.session.commit()
58+
self.body = jsonify({"message":"success"})
59+
self.status_code = STATUS_CODE.OK
60+
response = (self.body, self.status_code.value)
61+
response = make_response(response)
62+
return response

app/constants.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from enum import Enum
2+
3+
class STATUS_CODE(Enum):
4+
OK = 200
5+
CREATED = 201
6+
NO_CONTENT = 204
7+
BAD_REQUEST = 400
8+
UNAUTHORIZED = 401
9+
FORBIDDEN = 403
10+
NOT_FOUND = 404
11+
METHOD_NOT_ALLOWED = 405
12+
CONFLICT = 409
13+
INTERNAL_SERVER_ERROR = 500
14+
NOT_IMPLEMENTED = 501
15+
BAD_GATEWAY = 502
16+
17+
responses = {item.value: item.name for item in STATUS_CODE}
18+
19+
def support_codes(unsupport_codes):
20+
unsupport_codes = [code.value for code in unsupport_codes]
21+
return {code: name for code, name in responses.items() if code not in unsupport_codes}
22+
23+
GET = support_codes(unsupport_codes=[
24+
STATUS_CODE.CREATED, STATUS_CODE.NO_CONTENT,
25+
STATUS_CODE.CONFLICT,
26+
STATUS_CODE.METHOD_NOT_ALLOWED,
27+
STATUS_CODE.NOT_IMPLEMENTED])
28+
POST = support_codes(unsupport_codes=[
29+
STATUS_CODE.OK, STATUS_CODE.NO_CONTENT,
30+
STATUS_CODE.METHOD_NOT_ALLOWED,
31+
STATUS_CODE.NOT_IMPLEMENTED])
32+
PATCH = support_codes(unsupport_codes=[
33+
STATUS_CODE.CREATED,
34+
STATUS_CODE.NO_CONTENT,
35+
STATUS_CODE.METHOD_NOT_ALLOWED,
36+
STATUS_CODE.NOT_IMPLEMENTED])
37+
DELETE = support_codes(unsupport_codes=[
38+
STATUS_CODE.CREATED,
39+
STATUS_CODE.CONFLICT,
40+
STATUS_CODE.METHOD_NOT_ALLOWED,
41+
STATUS_CODE.NOT_IMPLEMENTED])

app/users/__init__.py

Whitespace-only changes.

app/users/models.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from app.api.database import DB, CRUD
2+
from marshmallow_jsonapi import Schema, fields
3+
from flask_sqlalchemy import SQLAlchemy
4+
from marshmallow import validate
5+
from sqlalchemy.sql import text
6+
7+
8+
class Users(DB.Model, CRUD):
9+
__tablename__ = 'users'
10+
__table_args__ = {'mysql_collate': 'utf8_general_ci'}
11+
12+
id = DB.Column(DB.Integer, primary_key=True)
13+
name = DB.Column(DB.String(255), nullable=False)
14+
email = DB.Column(DB.String(50), unique=True, nullable=False)
15+
password = DB.Column(DB.String(255), nullable=False)
16+
created = DB.Column(DB.TIMESTAMP, server_default=text(
17+
"CURRENT_TIMESTAMP"), nullable=False)
18+
19+
def __init__(self, name, email, password):
20+
self.name = name
21+
self.email = email
22+
self.password = password
23+
24+
25+
class UsersSchema(Schema):
26+
not_blank = validate.Length(min=1, error='Field cannot be blank')
27+
id = fields.Integer(dump_only=True)
28+
email = fields.String(validate=not_blank)
29+
name = fields.String(validate=not_blank)
30+
password = fields.String(validate=not_blank)
31+
created = fields.String(validate=not_blank)
32+
33+
def get_top_level_links(self, data, many):
34+
if many:
35+
self_link = "/users"
36+
else:
37+
self_link = "/users/{}".format(data['id'])
38+
return {'self': self_link}
39+
40+
class Meta:
41+
type_ = 'users'
42+
strict = True

0 commit comments

Comments
 (0)