#6. Python์œผ๋กœ API ๊ฐœ๋ฐœ(๋ฐ์ดํƒ€๋ฒ ์ด์Šค ๋ชจ๋ธ ์ž‘์—…)

 

#6. Python์œผ๋กœ API ๊ฐœ๋ฐœ(๋ฐ์ดํƒ€๋ฒ ์ด์Šค ๋ชจ๋ธ ์ž‘์—…)

#5. Python์œผ๋กœ API ๊ฐœ๋ฐœ(๊ธฐ๋ณธํ™˜๊ฒฝ๊ตฌ์„ฑ) #5. Python์œผ๋กœ API ๊ฐœ๋ฐœ(๊ธฐ๋ณธํ™˜๊ฒฝ๊ตฌ์„ฑ) โŒ˜ server.py ( ์œ„์น˜: linkservice/server/server.py) --------------------------------------------------------------------------------------------------- app.py

firstvalue.tistory.com

 

์ด์ „ ํฌ์ŠคํŒ…์— ๋ฐ์ดํƒ€๋ฒ ์ด์Šค ๋ชจ๋ธ๋ง ์ž‘์—…์„ ํ–ˆ๊ณ , ์—ฌ๊ธฐ์„œ๋Š”  server.py์— flask_restful์—์„œ ์ œ๊ณต๋˜๋Š”

API Resource์„ ์ถ”๊ฐ€ํ•ด ๋ณด์ž.

 

โŒ˜ server.py ( ์œ„์น˜: linkservice/server/server.py)

----------------------------------------------------------------------------------------------------------

๊ธฐ์กด server.py ์— ์ถ”๊ฐ€ํ•ด๋ณด์ž.

import socket
from config.create_app import create_app
from flask import Flask
    #flask_restful์—์„œ API์™€  src ๋ฐ‘์— links.py์— class๋“ค์„ import ํ•œ๋‹ค.
from flask_restful import Api
from src.links import LinkRegister, LinksAll, LinkSelect, LinkRemove, LinkUpdate
from db_init import db

env = socket.gethostbyname(socket.gethostname())
if 'linkservice.com' in env :
   app = create_app('production')
else:
   app = create_app('development')
# print(app.config)
    # API ์„ ์–ธ
api = Api(app)
    #API์— Resource๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
api.add_resource(LinkRegister, '/api/link/create')
api.add_resource(LinksAll, '/api/links')
api.add_resource(LinkSelect, '/api/link/select/<int:id>')
api.add_resource(LinkRemove, '/api/link/delete/<int:id>')
api.add_resource(LinkUpdate, '/api/link/update/<int:id>')

if __name__ == "__main__":
# ORM
    db.init_app(app)
    app.run(debug=True, port=5000)

 

์ €์žฅ ํ›„ ์ด์ œ ์‹คํ–‰ํ•ด์„œ ํ™•์ธํ•ด๋ณด์ž.

 

โŽฎ์‹คํ–‰๋ฐฉ๋ฒ•

   1.     ํ„ฐ๋ฏธ๋„์—์„œ ๊ฐ€์ƒํ™” ์‹คํ–‰ ( source ./bin/activate )

   2.     python3 server.py ์‹คํ–‰

   3.     POSTMAN์—์„œ API ํ…Œ์ŠคํŠธ

 

์‹คํ–‰ํ›„ POSTMAN์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด์ž.

1.1.  API ํ…Œ์ŠคํŠธ

โ˜‘๏ธŽ POST /api/link/create - ๋งํฌ์ •๋ณด ๋“ฑ๋ก

          Body์— JSON์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ๊ณ  ์ง„ํ–‰ํ•ด๋ณด์ž.

message์„ ์ •์ƒ์ ์œผ๋กœ return ๋ฐ›๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

 

โ˜‘๏ธŽ GET /api/links – ์ „์ฒด ๋งํฌ์ •๋ณด ์กฐํšŒ

โ˜‘๏ธŽ GET /api/link/select/<int:id>        - ID์— ํ•ด๋‹นํ•œ ๋งํฌ์ •๋ณด์กฐํšŒ

 

 

โ˜‘๏ธŽ PUT /api/link/update/<int:id>           - name์„ ์ˆ˜์ •ํ•ด๋ณด์ž.

 

โ˜‘๏ธŽ DELETE /api/link/delete/<int:id> - ID์— ํ•ด๋‹นํ•œ ๋งํฌ์ •๋ณด ์‚ญ์ œ

 

LINKS ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ CRUD API๊ฐ€ ์™„์„ฑ๋˜์—ˆ๋‹ค.

 

์ฃผ์š” ํ…Œ์ด๋ธ”์ธ LINKS์˜ CRUD API๊ฐ€ ์™„์„ฑ๋˜์—ˆ์œผ๋ฏ€๋กœ, ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ์‹ค์ œ ํ™”๋ฉด์„ ๊ตฌํ˜„์„ ํ•ด๋ณด๊ณ , ์•„์ง๊นŒ์ง€ DB๋ฐ API์„ค๊ณ„์— ๋น ์ง„ ๊ฒƒ์€ ํ™”๋ฉด์„ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ์ถ”๊ฐ€์ ์œผ๋กœ ์ œ์ž‘ํ•ด ๋ณด๊ธฐ๋กœ ํ•œ๋‹ค.

#5. Python์œผ๋กœ API ๊ฐœ๋ฐœ(๊ธฐ๋ณธํ™˜๊ฒฝ๊ตฌ์„ฑ)

 

#5. Python์œผ๋กœ API ๊ฐœ๋ฐœ(๊ธฐ๋ณธํ™˜๊ฒฝ๊ตฌ์„ฑ)

โŒ˜ server.py ( ์œ„์น˜: linkservice/server/server.py) --------------------------------------------------------------------------------------------------- app.py๋กœ ๋ณดํ†ต ๋ช…์นญ ํ•˜์ง€๋งŒ, ์—ฌ๊ธฐ์„œ๋Š” server.py๋กœ ๋„ค์ž„์„ ๋ณ€๊ฒฝํ•˜์—ฌ ์ง„ํ–‰ํ•œ๋‹ค. ์‹ค

firstvalue.tistory.com

Python Flask์˜ ๊ธฐ๋ณธํ™˜๊ฒฝ์ด ๊ตฌ์„ฑ๋˜์—ˆ๊ณ , ์ด์   ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ จ ์ž‘์—…์„ ์ง„ํ–‰ํ•œ๋‹ค.

 

SQLAlchemy๋Š” Python์—์„œ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ORM(Object-Relational Mapping) ์ด๋ฉฐ, ๊ฐ์ฒด์™€ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ๋งคํ•‘(์—ฐ๊ฒฐ)ํ•ด์ฃผ๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” Flask์—์„œ ํ™•์žฅํ˜•ํƒœ๋กœ SQLALchemy์„ ์ง€์›ํ•˜๋Š” Flask-SQLALchemy ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

โŒ˜ db_init.py ( ์œ„์น˜: linkservice/server/db_init.py)

---------------------------------------------------------------------------------------------------------

db_init.py๋Š” db = SQLAlchemy() ์„ ์–ธ์„ ํ•ด์ฃผ๋Š” ๊ณตํ†ต ๋ชจ๋“ˆ๋กœ ํ™œ์šฉ ํ•œ๋‹ค.

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

โŒ˜ links_model.py ( ์œ„์น˜: linkservice/server/models/links_model.py)

---------------------------------------------------------------------------------------------------

์ด์ œ๋ถ€ํ„ฐ links ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ DB๋ชจ๋ธ์„ ์ œ์ž‘ํ•˜๊ณ , ๊ธฐ๋ณธ์ ์ธ id ๊ฐ’์œผ๋กœ ์‚ญ์ œ/์กฐํšŒ/์—…๋ฐ์ดํŠธ ๋“ฑ ํ•„์š”ํ•œ ๊ธฐ๋ณธ METHOD์„ ์ •์˜ํ•œ๋‹ค.

from db_init import db
from sqlalchemy import func

class LinkModel(db.Model):
	# DB ์Šคํ‚ค๋งˆ๊ฐ€ ๊ธฐ๋ณธ(public)์ด ์•„๋‹ˆ๋ฉด ๋ณ„๋„๋กœ ์„ ์–ธ์„ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
    __table_args__ = {'schema': 'aip'}
    
	# ๋ฌผ๋ฆฌ ํ…Œ์ด๋ธ”๋ช…
    __tablename__ = "links"
    
	# ์ปฌ๋Ÿผ ๋งตํ•‘
    
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))
    tag = db.Column(db.String(50))
    sort = db.Column(db.Integer)
    imageurl = db.Column(db.Text)
    linkurl = db.Column(db.Text)
    create_date = db.Column(db.Date)
    update_date = db.Column(db.Date)

    def __init__(self, id, name, tag, sort, imageurl, linkurl, create_date,update_date):
        self.id = id
        self.name = name
        self.tag = tag
        self.sort = sort
        self.imageurl = imageurl
        self.linkurl = linkurl
        self.create_date = create_date
        self.update_date = update_date

    def save(links):
        """
        ์ •๋ณด ์ €์žฅ    :param ์ •๋ณด ๊ฐ์ฒด
        """
        db.session.merge(links)
        db.session.commit()
        db.session.close()

	# Link์ •๋ณด ์ €์žฅ์‹œ sort ์ˆœ์„œ์˜ max๊ฐ’์„ ๊ตฌํ•œ๋‹ค. ๋งŒ์•ฝ null์ด๋ฉด 0 ์œผ๋กœ ๋ณ€๊ฒฝ
    # ํ™”๋ฉด์— ์ถœ๋ ฅ๋˜๋Š” ์ˆœ์„œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ sortํ•ญ๋ชฉ์ด ํ•„์š”ํ•˜๋ฉฐ, ๋งํฌ์ •๋ณด ๋“ฑ๋ก์‹œ max๊ฐ’์„ ์ €์žฅํ•˜๊ธฐ์œ„ํ•ด์„œ ํ•„์š”
    
    @classmethod
    def max_sort(self):
      result = db.session.query(func.coalesce(func.max(self.sort), 0)).scalar()

      return result+1

	# ๊ธฐ๋ณธ์ ์ธ ์กฐํšŒ/์‚ญ์ œ/์—…๋ฐ์ดํŠธ ์ฝ”๋“œ๋ฅผ ๊ตฌ์„ฑํ•œ๋‹ค. ( param : id )
    
    @classmethod
    # id๋กœ ์กฐํšŒ
    def find_by_id(self, id):
		links= db.session.query(self).filter_by(id=id).first()
        return links

    @classmethod
    # id๋กœ ์‚ญ์ œ    
    def delete_by_id(self, id):
		try:
        	db.session.query(self).filter_by(id=id).delete(synchronize_session=False)
      	except:
        	db.session.rollback()
      	finally:
        	db.session.commit()
        	db.session.close()

    @classmethod
    # id๋กœ values๊ฐ’์„ ์—…๋ฐ์ดํŠธ
    def update_by_id(self, id, values):
        db.session.query(self).filter_by(id=id).update(values)     
        db.session.commit()   
        db.session.close()     

    def __str__(self):
        return "[" + str(self.__class__) + "]: " + str(self.__dict__)

Links ํ…Œ์ด๋ธ”์˜ DB๋ชจ๋ธ๊ณผ ๊ธฐ๋ณธ ์ •๋ณด ์กฐํšŒ/์‚ญ์ œ/์—…๋ฐ์ดํŠธ ๊ด€๋ จ ๋ฉ”์„œ๋“œ๋„ ์ œ์ž‘์ด ๋๋‚ฌ์œผ๋‹ˆ,

์ด์   API ํ˜•ํƒœ๋กœ ์ œ๊ณตํ•˜๊ณ ์ž Resource๋ฅผ ์ œ์ž‘ํ•œ๋‹ค. 

 

1.1. Resource ์ œ์ž‘

โŒ˜ links.py ( ์œ„์น˜: linkservice/server/src/links.py)

---------------------------------------------------------------------------------------------------

links.py์—์„œ API ํ˜ธ์ถœ ์‹œ ์‹คํ–‰๋˜๋Š” class์„ ์ •์˜ํ•ด๋ณด์ž.

-       class LinkRegister(Resource) : ๋งํฌ์ •๋ณด๋ฅผ DB์— ๋“ฑ๋ก(Insert) ํ•œ๋‹ค.

-       class LinksAll(Resource) : ์ „์ฒด ๋งํฌ ์ •๋ณด๋ฅผ ์กฐํšŒํ•œ๋‹ค.

-       class LinkSelect(Resource) : ์„ ํƒํ•œ ๋งํฌ์ •๋ณด๋ฅผ ์กฐํšŒํ•œ๋‹ค..

-       class LinkRemove(Resource) : ์„ ํƒํ•œ ๋งํฌ์ •๋ณด๋ฅผ ์‚ญ์ œํ•œ๋‹ค..

-       class LinkUpdate(Resource) : ์„ ํƒํ•œ ๋งํฌ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค..

from db_init import db
from flask_restful import Resource, reqparse
from flask import jsonify, request
from flask_marshmallow import Marshmallow
from models.links_model import LinkModel
from datetime import date as date_function

ma = Marshmallow() #๊ฐ์ฒด๋ฅผ Python ๋ฐ์ดํ„ฐ ์œ ํ˜•์œผ๋กœ ์ง๋ ฌํ™”

class LinkSchema(ma.SQLAlchemyAutoSchema):
    class Meta:
        model = LinkModel

"""
POST /api/link/create -  ๋“ฑ๋ก resource
"""
class LinkRegister(Resource):
# ์ž…๋ ฅ ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ •
# DBํ•ญ๋ชฉ์— ๋งž๊ฒŒ ํŒŒ๋ผ๋ฉ”ํƒ€๋กœ ๋ฐ›์•„ ์ €์žฅํ•œ๋‹ค.
    parser = reqparse.RequestParser()
    parser.add_argument('name',type=str,required=True,help="ํ•„์ˆ˜ํ•ญ๋ชฉ์ž…๋‹ˆ๋‹ค.")
    parser.add_argument('tag',type=str)
    parser.add_argument('sort',type=str)     
    parser.add_argument('imageurl',type=str )      
    parser.add_argument('linkurl',type=str )    

    def post(self):
        # Request Parameter๋ฅผ dictionary ํ˜•ํƒœ๋กœ ์ €์žฅ
        data = LinkRegister.parser.parse_args()
        name = data['name']
        tag = data['tag']
        sort = LinkModel.max_sort() #Sort์ˆœ์„œ๋ฅผ ์œ„ํ•œ ๊ฐ’์œผ๋กœ ์ž…๋ ฅ์‹œ max๊ฐ’์„ ์ž…๋ ฅํ•œ๋‹ค.
        imageurl = data['imageurl']
        linkurl = data['linkurl']
        create_date = date_function.today()  #create_date๋Š” datetime์œผ๋กœ ์ €์žฅ
        update_date = date_function.today()

        LinkModel.save(LinkModel(None, name, tag, sort, imageurl, linkurl, create_date, update_date))

        return {'message':f'๋งํฌ ์ •๋ณด๊ฐ€ ๋“ฑ๋ก ๋˜์—ˆ์Šต๋‹ˆ๋‹ค'},201

"""
GET /api/links - ์ „์ฒด ๋งํฌ์ •๋ณด ์กฐํšŒ
"""

class LinksAll(Resource):

    def get(self):
    # ์ž…๋ ฅ ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ • - ๋ชฉ๋ก์ „์ฒด ์ถœ๋ ฅ์œผ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†์Œ.
        link = LinkModel.query.order_by(LinkModel.sort).all()
        link_schema = LinkSchema(many=True)
        output = link_schema.dump(link)
        return jsonify({'links' : output})

"""
GET /api/link/select/<int:id> - ๋งํฌ ์ •๋ณด ์กฐํšŒ
"""
class LinkSelect(Resource):

    def get(self,id):
        # ์ •๋ณด ์กฐํšŒ
        link = LinkModel.find_by_id(id)
        link_schema = LinkSchema()
        output = link_schema.dump(link)
        return jsonify({'links' : output})

"""
DELETE /api/link/delete/<int:id> - ๋งํฌ์ •๋ณด์‚ญ์ œ
"""
class LinkRemove(Resource):
    def delete(self, id):
        # ์ •๋ณด ์‚ญ์ œ ( links_model์˜ delete_by_id ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ )
        LinkModel.delete_by_id(id)

        return {'message':'์ •์ƒ์ ์œผ๋กœ ์‚ญ์ œ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'},201

"""
PUT /api/link/update/<int:id> - ๋งํฌ ์ •๋ณด ์ˆ˜์ •
"""
class LinkUpdate(Resource):

    def put(self,id):
        #Request๋ฅผ json์œผ๋กœ ๋ฐ›๋Š”๋‹ค.
        values = request.get_json()
        # ์ •๋ณด ์ˆ˜์ • ( links_model์˜ update_by_id ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ )
        LinkModel.update_by_id(id, values)
        return {'message':'์ •๋ณด๊ฐ€ ์ˆ˜์ • ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'},201

 

์ฐธ๊ณ ์ž๋ฃŒ :

Sqlalchemy

 

ORM Quick Start — SQLAlchemy 2.0 Documentation

ORM Quick Start For new users who want to quickly see what basic ORM use looks like, here’s an abbreviated form of the mappings and examples used in the SQLAlchemy Unified Tutorial. The code here is fully runnable from a clean command line. As the descri

docs.sqlalchemy.org

Flask + marshmallow for beautiful APIs 

 

Flask-Marshmallow: Flask + marshmallow for beautiful APIs — Flask-Marshmallow 0.14.0 documentation

Flask-Marshmallow: Flask + marshmallow for beautiful APIs changelog // github // pypi // issues Flask + marshmallow for beautiful APIs Flask-Marshmallow is a thin integration layer for Flask (a Python web framework) and marshmallow (an object serialization

flask-marshmallow.readthedocs.io


๋‹ค์Œ ํŽธ์—๋Š” server.py์— flask_restful์—์„œ ์ œ๊ณต๋˜๋Š” API Resource์„ ์ถ”๊ฐ€ํ•ด ๋ณด์ž.

+ Recent posts