1.    React๋กœ ํ™”๋ฉด ๊ฐœ๋ฐœ

์ž, ์ด์ œ๋ถ€ํ„ฐ REACT๋กœ ํ™”๋ฉด์„ ๊ฐœ๋ฐœ ํ•ด๋ณด์ž.

 

์•ž์—์„œ ์‚ฌ์ „ ์ค€๋น„์‹œ ํ”„๋กœ์ ํŠธ ํด๋”์ธ linkservice์•„๋ž˜์— npx create-react-app ์œผ๋กœ ์ด๋ฏธ client์„ ์ƒ์„ฑํ–ˆ๋‹ค.

#4. ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ ๋ฐ ํ™˜๊ฒฝ์„ค์ •

 

#4. ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ ๋ฐ ํ™˜๊ฒฝ์„ค์ •

1.1. ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ ๋ฐ ํ™˜๊ฒฝ์„ค์ • ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ๋Š” ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ๋ฅผ ๋‚˜๋ˆ„๊ณ ์ž client / server๋กœ ๊ตฌ๋ถ„ ํ•œ๋‹ค. โŽฎํ”„๋กœ์ ํŠธ ํด๋” : linkserver/ |-------- client ( React ๊ตฌ์กฐ) |-------- server ( Python๊ตฌ

firstvalue.tistory.com

 

1.1.  React ๊ธฐ๋ณธ์„ค์ •

๊ธฐ๋ณธ ํด๋”๊ตฌ์กฐ์—์„œ ํ•„์š” ์—†๋Š” ํŒŒ์ผ์„ ๋ชจ๋‘ ์ง€์šด๋‹ค.

      ยท public ํด๋” ๋ฐ‘์— index.html์„ ์ œ์™ธํ•˜๊ณ  ๋ชจ๋‘ ์‚ญ์ œ

      ยท src ํด๋” ๋ฐ‘์— App.js, index.js ์„ ์ œ์™ธํ•˜๊ณ  ๋ชจ๋‘ ์‚ญ์ œ

React ํŒŒ์ผ ๊ตฌ์กฐ๋ฅผ ๊ฐ„๋‹จํžˆ ์„ค๋ช…ํ•œ๋‹ค๋ฉด,

1. index.js

src ํด๋”์— ๋ฉ”์ธ Script๋กœ ์—ฌ๊ธฐ์—์„œ HTML ํ…œํ”Œ๋ฆฟ ๋ฐ JavaScript์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์กฐํ•ฉํ•˜์—ฌ ๋ Œ๋”๋ง์„ ํ•œ๋‹ค.

 

2. App.js

src ํด๋”์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•˜๋Š” Script์ด๋‹ค. ์‹ค์ œ๋กœ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” ๋‚ด์šฉ ๋“ฑ์€ ์—ฌ๊ธฐ์—์„œ ์ •์˜๋œ๋‹ค.

 

3. index.html

public ํด๋”์— ์žˆ์œผ๋ฉฐ, HTML ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ์ด๋‹ค. ์ด ํŒŒ์ผ์ด ์ง์ ‘ ํ‘œ์‹œ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ณ , index.js์— ์˜ํ•ด ๋ Œ๋”๋ง ๋œ ๊ฒฐ๊ณผ๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.

 

   ๐Ÿ“Œ App.js์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•˜๊ณ  -> index.js ์—์„œ ReactDOM.rendor ํ•˜๊ณ   -> index.html์—์„œ ํ‘œ์‹œ๋œ๋‹ค.

 

๋จผ์ €, App.js ์„ ์ˆ˜์ •ํ•œ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ์—์„œ ํ•„์š” ์—†๋Š” ๋‚ด์šฉ ์ง€์šฐ๊ณ , ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ถ”๊ฐ€ ํ•œ๋‹ค.

 


index.js ์—์„œ reportWebVitals ๋ถ€๋ถ„๊ณผ import index.css์„ ์ฃผ์„์ฒ˜๋ฆฌ ํ•œ๋‹ค.

   ๐Ÿ“Œ ์ฐธ๊ณ ๋กœ, reportWebVitals๋Š” Create React App์—์„œ ์„œ๋“œํŒŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ Index ํŒŒ์ผ์— ์จ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ

       reportWebVitals() ์— console.log์„ ๋„ฃ์–ด์ฃผ๋ฉด ๊ฐœ๋ฐœ์ฐฝ์„ ํ†ตํ•ด ์•ฑ์˜ ํผํฌ๋จผ์Šค ์‹œ๊ฐ„๋“ค์„ ๋ถ„์„ํ•˜์—ฌ objectํ˜•ํƒœ๋กœ

      ๋ณด์—ฌ์ค€๋‹ค.

 

 

์ด์   ํ„ฐ๋ฏธ๋„์—์„œ yarn start์„ ์‹คํ–‰ํ•˜๊ณ , ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ ‘์†ํ•ด๋ณด์ž.

1.2. ๋””์ž์ธ ๊ฐ€์ ธ์˜ค๊ธฐ

๋””์ž์ธ๊นŒ์ง€ ํ•˜๋ฉด 1์ธ ๊ฐœ๋ฐœ์ž๋กœ ๊ฐ€์žฅ ์ด์ƒ์ ์ด๋งŒ, ๊ทธ๋งŒํผ ๋งŽ์€ ๋…ธ๋ ฅ์ด ํ•„์š”ํ•˜๋‹ค. ๋‚˜๋„ ๋””์ž์ธ ๋งŒํผ์€ ๋งŽ์ด ๋ฐฐ์šฐ์ง€ ๋ชปํ•ด์„œ ์–•์€ ์ง€์‹์œผ๋กœ ํ™”๋ฉด์„ ๋งŒ๋“ค์–ด ๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

๋””์ž์ธ์ด ํ•„์š” ์—†๋Š” ๋ถ„๋“ค์€ ๋””์ž์ธ ์„ค๋ช…๋ถ€๋ถ„์„ ์ œ์™ธํ•˜๊ณ , ๊ฐœ๋ฐœ๋ถ€๋ถ„๋งŒ ๋ด๋„ ๋œ๋‹ค.

 

์šฐ์„  Bootstrap ๋ฌด๋ฃŒ ๋””์ž์ธ์„ ๊ฐ€์ง€๊ณ  ์™€์„œ ๋ณ€๊ฒฝํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

๋””์ž์ธ ์ฐธ์กฐ : https://getbootstrap.com/docs/5.3/examples/

์šฐ๋ฆฌ๋Š” Albumํ™”๋ฉด์„ ๊ฐ€์ง€๊ณ  ์‹œ์ž‘ํ•˜๊ณ ์ž ํ•œ๋‹ค. https://getbootstrap.com/docs/5.3/examples/album/ ์ ‘์†ํ›„ ์˜ค๋ฅธ์ชฝ ๋งˆ์šฐ์Šค ํด๋ฆญํ•ด์„œ ํŽ˜์ด์ง€ ์†Œ์Šค๋ณด๊ธฐ์—์„œ HTML์„ ๋ณต์‚ฌํ•˜์—ฌ index.html์— ๋ถ™์—ฌ ๋„ฃ๋Š”๋‹ค.

 

BootStrap ๋ฌด๋ฃŒ๋””์ž์ธ HTML์ฝ”๋“œ๋ฅผ index.html์— ๋ถ™ํžŒ๋‹ค.

 

Title๋“ฑ ํ…์ŠคํŠธ ๋ถ€๋ถ„์„ ๋นผ๊ฑฐ๋‚˜, ์ˆ˜์ •ํ•˜์‹œ๊ณ , HTML์—์„œ ๋ณธ๋ฌธ์— ํ•ด๋‹น๋˜๋Š” <main></main> ๊ณผ <footer></footer> ๋Š” ์‚ญ์ œํ•˜๊ณ  ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์—์„œ ํ•„์š”ํ•œ ๋ถ€๋ถ„์€ ์ถ”๊ฐ€/์ˆ˜์ •/์‚ญ์ œํ•ด์„œ ์ดˆ๊ธฐ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•ด๋ณด์ž

 

<main></main> ๋ถ€๋ถ„์ด ๊ฐ€์žฅ ์ค‘์š”ํ•˜๋ฏ€๋กœ, ์†Œ์Šค๋‚ด ํ™•์ธํ•˜๊ธฐ ๋ฐ”๋ž€๋‹ค.

 

<!doctype html>
<html lang="ko">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1">
  <meta name="description" content="">
  <meta name="generator" content="Hugo 0.88.1">
  <title>๋งํฌ์„œ๋น„์Šค</title>

  <!-- Bootstrap core CSS -->
  <link href="https://getbootstrap.kr/docs/5.1/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>

<body>
  <header>
    <div class="collapse bg-dark" id="navbarHeader">
      <div class="container">
        <div class="row">
          <div class="col-12">
            <h4 class="text-white">๋งํฌ์„œ๋น„์Šค</h4>
            <p class="text-muted">๊ฐœ๋ฐœ์€ ์—„์—ฐํžˆ ์กด์ค‘ ๋ฐ›์•„์•ผ ํ•  ๊ฐœ์ธ์˜ ์ฐฝ์ž‘๋ฌผ์ž…๋‹ˆ๋‹ค. 
            </p>
          </div>
        <div class="col-12">
          <h6 class="text-white">Developers</h4>
          <ul class="list-unstyled">
            <li class="text-muted">(์ฃผ)XXXXXXXX</li>
            <li class="text-muted">์‚ฌ์—…์ž๋ฒˆํ˜ธ:XXX-XX-xxxxx</li>
            <li class="text-muted">๋Œ€ํ‘œ์ „ํ™”:000-1111-2222</li>            
          </ul>
        </div>
      </div>

      </div>
    </div>
    <div class="navbar navbar-dark bg-dark shadow-sm">
      <div class="container">
        <a href="/" class="navbar-brand d-flex align-items-center">
          <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor"
            stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" class="me-2"
            viewBox="0 0 24 24">
            <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" />
            <circle cx="12" cy="13" r="4" />
          </svg>
          <strong>๋งํฌ์„œ๋น„์Šค</strong>
        </a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarHeader"
          aria-controls="navbarHeader" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
      </div>
    </div>
  </header>


  <main>
    <!-- ๋ฐฐ๊ฒฝ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ -->
    <section class="container" id="section">
    </section>    

    <div class="album py-4 bg-light" >
      <div class="container" id="root">
            <!--   ์—ฌ๊ธฐ์— ๋ณธ๋ฌธ๋‚ด์šฉ์„  ์ฒ˜๋ฆฌ -->
      </div>
    </div>
  </main>
  <!-- <footer class="text-muted py-2" id="footer">
  </footer> -->
</body>
</html>

๐Ÿ“Œ ๋””์ž์ธ ๋ฐ ํผ๋ธ”๋ฆฌ์‹ฑ์ด ๊ฐ€๋Šฅํ•˜์‹  ๋ถ„๋“ค์€ ๊ฐ์ž ๋‹ค๋ฅธ ๋””์ž์ธ์œผ๋กœ ํ•ด๋„ ๋ฌด๋ฐฉํ•˜๋‹ค.

 

์ด์   ํ™”๋ฉด์ด ์ž˜ ์ถœ๋ ฅ๋˜๋Š”์ง€ ํ™•์ธ ํ•œ๋‹ค.


๋‹ค์ŒํŽธ์—๋Š” Component์ œ์ž‘์„ ํ•ด๋ณด์ž.

 

 

#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์„ ์ถ”๊ฐ€ํ•ด ๋ณด์ž.

#5. Python์œผ๋กœ API ๊ฐœ๋ฐœ

 

#5. Python์œผ๋กœ API ๊ฐœ๋ฐœ

1. Python์œผ๋กœ API ๊ฐœ๋ฐœ Python์˜ Flask์„ ์ด์šฉํ•˜์—ฌ API์ œ์ž‘์„ ํ•ด๋ณด์ž. ์šฐ์„  PostgreSQL์—์„œ DB ์„ค๊ณ„์— ๋งž๊ฒŒ ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•œ๋‹ค. (DB์ƒ์„ฑ ๋ฐฉ๋ฒ•์€ ๋ณ„๋„ ์„ค๋ช…ํ•˜์ง€ ์•Š๋Š”๋‹ค.) 1.1. Python Flask APIํ™˜๊ฒฝ ์„ค์ • โŒ˜ config.py (

firstvalue.tistory.com

 

Flask๋กœ REST API ๊ตฌํ˜„ํ•˜๊ธฐ

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

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

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

์‹ค์ œ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•˜๋Š” ํŒŒ์ผ๋กœ python3 server.py๋กœ ๊ตฌ๋™ํ•œ๋‹ค.

์šฐ์„  ์„ค์ •ํŒŒ์ผ๋“ค๋กœ ์ž˜ ๋˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž.

์•„๋ž˜๋Š” host๊ฐ€ ๋ผ์ด๋ธŒ ๋„๋ฉ”์ธ(linkserver.com) ์ด ์•„๋‹Œ ๊ฒฝ์šฐ, DEVํ™˜๊ฒฝ์œผ๋กœ ์ธ์‹ํ•œ๋‹ค.

import socket
from flask import Flask

env = socket.gethostbyname(socket.gethostname())
if 'linkserver.com' in env :
   app = create_app('production')
   print('์šด์˜๊ณ„ ํ™˜๊ฒฝ์ž…๋‹ˆ๋‹ค.')
else:
    app = create_app('development')
    print(' DEV ํ™˜๊ฒฝ์ž…๋‹ˆ๋‹ค.')
    
#print(app.config)

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

์œ„ ๋‚ด์šฉ์„ ๋ชจ๋‘ ์ €์žฅํ•œ ํ›„ ํ„ฐ๋ฏธ๋„์„ ์—ด์–ด์„œ python3 server.py์„ ์‹คํ–‰ํ•ด๋ณด์ž.

 

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

1.    ๊ฐ€์ƒํ™” ํ™˜๊ฒฝ ์‹œ์ž‘

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

์œ„์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹ค.

 

Flask ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์—†์–ด์„œ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜์ธ๋ฐ, ์•ž์œผ๋กœ ์ง„ํ–‰์‹œ ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ชจ๋‘ ๋ฏธ๋ฆฌ ์„ค์น˜ํ•ด๋ณด์ž

 

โŽฎLIBRARY์„ค์น˜

1.    pip install flask

2.    pip install Flask-RESTful

3.    pip install Flask-SQLAlchemy

4.    pip install marshmallow-sqlalchemy

5.    pip install flask-marshmallow

6.    pip install psycopg2

7.    pip install pillow

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ชจ๋‘ ์„ค์น˜ํ•œ ํ›„ ๋‹ค์‹œ ํ•œ๋ฒˆ ํ„ฐ๋ฏธ๋„์—์„œ python3 server.py ์„ ์‹คํ–‰ํ•œ๋‹ค.

server.py์— print(app.config) ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ํ™˜๊ฒฝํŒŒ์ผ์ด ์ž˜ ์ ์šฉ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 


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

 

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

 

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

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

firstvalue.tistory.com

 

1.    Python์œผ๋กœ API ๊ฐœ๋ฐœ

Python์˜ Flask์„ ์ด์šฉํ•˜์—ฌ API์ œ์ž‘์„ ํ•ด๋ณด์ž.

์šฐ์„  PostgreSQL์—์„œ DB ์„ค๊ณ„์— ๋งž๊ฒŒ ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•œ๋‹ค.

(DB์ƒ์„ฑ ๋ฐฉ๋ฒ•์€ ๋ณ„๋„ ์„ค๋ช…ํ•˜์ง€ ์•Š๋Š”๋‹ค.)

 

1.1.  Python Flask APIํ™˜๊ฒฝ ์„ค์ •

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

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

config.py์€ ๊ฐœ๋ฐœ๊ณ„(Development)์™€ ์šด์˜๊ณ„(Production) ํ™˜๊ฒฝ์„ค์ •์„ ์œ„ํ•œ ๊ฒƒ์œผ๋กœ ์„œ๋ฒ„(server.py) ๊ตฌ๋™ ์‹œ ํ˜ธ์ถœํ•œ๋‹ค.

 

SQLALCHEMY_DATABASE_URI์ •๋ณด๋ฅผ ์—ฌ๋Ÿฌ๋ถ„์˜ DB์ •๋ณด๋กœ ๋ณ€๊ฒฝํ•˜๊ณ , ๋‹ค๋ฅธ ์˜ต์…˜๋“ค์€ ์ฐธ๊ณ ํ•˜์—ฌ ํ•„์š”์‹œ ์ถ”๊ฐ€/์‚ญ์ œ ํ•˜๋ฉด ๋œ๋‹ค.

 

์ด๋ฏธ์ง€ ์ €์žฅ ์œ„์น˜์„ค์ •์€ CDNํ˜น์€ NASํ˜•ํƒœ๋กœ ์ œ์ž‘ํ•˜๊ณ ์ž ๋ณ„๋„ ํด๋”๋กœ ๋ถ„๋ฆฌํ–ˆ์œผ๋ฉฐ, ๋งํฌ์ •๋ณด์™€ ์ด๋ฏธ์ง€ ์ •๋ณด ์ €์žฅ์€ IMAGE_URLํ˜•ํƒœ๋กœ ์ €์žฅ๋œ๋‹ค. 

ํ™˜๊ฒฝํŒŒ์ผ ๋‚ด์šฉ์€ ์•ž์œผ๋กœ ์ง„ํ–‰ํ•˜๋ฉด์„œ ์„ค๋ช…๋  ๊ฒƒ์ด๋‹ค

 

import os
dir = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))

class Development(object):
    DEBUG = True
    FLASK_APP = 'linkservice_dev'
    ENV = 'development'
    
## DB URL FOR DEVELOPMENT
    SQLALCHEMY_DATABASE_URI = 'postgresql://์‚ฌ์šฉ์ž:์‚ฌ์šฉ์žํŒจ์Šค์›Œ๋“œ@localhost:5432/๋ฐ์ดํƒ€๋ฒ ์ด์Šค๋ช…'

# ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์ปค๋ฐ‹ ์ „ํ›„๋กœ ์•Œ๋ฆผ ์—ฌ๋ถ€
    SQLALCHEMY_TRACK_MODIFICATIONS = True

# Query Debug ์—ฌ๋ถ€ ๋ฐ DB POOL
    SQLALCHEMY_ECHO = True
    SQLALCHEMY_POOL_SIZE = 20
    SQLALCHEMY_POOL_RECYCLE = 3600

#JSON์—์„œ ํ•œ๊ธ€ ํ‘œํ˜„์„ ์œ„ํ•ด์„œ ๋ฐ˜์˜
    JSON_AS_ASCII = False
    
#์ด๋ฏธ์ง€ ์œ„์น˜ ์„ค์ •
    image_folder = os.path.normpath(os.path.join(dir, os.pardir)) + '/client/public/images/'
    COVER_IMAGE_FORDER = image_folder
    IMAGE_FORDER = image_folder
    IMAGE_URL = 'http://127.0.0.1:3000/images/'

class Production(object):
    DEBUG = False
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_ECHO = False
    FLASK_APP = 'linkservice'
    ENV = 'production'
    
## DB URL FOR PRODUCTION
    SQLALCHEMY_DATABASE_URI = 'postgresql://์‚ฌ์šฉ์ž:์‚ฌ์šฉ์žํŒจ์Šค์›Œ๋“œ@localhost:5432/๋ฐ์ดํƒ€๋ฒ ์ด์Šค๋ช…'

#JSON์—์„œ ํ•œ๊ธ€ ํ‘œํ˜„์„ ์œ„ํ•ด์„œ ๋ฐ˜์˜
    JSON_AS_ASCII = False    

#์ด๋ฏธ์ง€ ์œ„์น˜ ์„ค์ •
    image_folder = os.path.normpath(os.path.join(dir, os.pardir)) + '/images/'
    COVER_IMAGE_FORDER = image_folder
    IMAGE_FORDER = image_folder 

#์šด์˜๊ณ„ 
    IMAGE_URL = 'https://www.linkservice.com/img/'

app_config = {
    'development': Development(),
    'production': Production(),
}

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

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

create_app.py๋Š” ํ™˜๊ฒฝํŒŒ์ผ์„ ์ฝ์–ด Flask App์„ ์‹คํ–‰ํ•œ๋‹ค.

from . import config
from flask import Flask

def create_app(environment):
    # configํŒŒ์ผ์—์„œ ๋ถˆ๋ ค์˜ค๊ธฐ
    config_map = {
        'development': config.Development(),
        'production': config.Production(),
    }
    config_obj = config_map[environment.lower()]   
    
    app = Flask(__name__)
    app.config.from_object(config_obj)

    return app

1.1. ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ ๋ฐ ํ™˜๊ฒฝ์„ค์ •

ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ๋Š” ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ๋ฅผ ๋‚˜๋ˆ„๊ณ ์ž client / server๋กœ ๊ตฌ๋ถ„ ํ•œ๋‹ค.

โŽฎํ”„๋กœ์ ํŠธ ํด๋” : linkserver/

       |-------- client ( React ๊ตฌ์กฐ)

       |-------- server ( Python๊ตฌ์กฐ )

 

โŽฎํ”„๋กœ์ ํŠธ ํด๋”๋ฅผ ๋งŒ๋“ค๊ณ   Client ํ™˜๊ฒฝ๊ณผ Server ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•ด ๋ณด๊ฒ ๋‹ค.

ํ„ฐ๋ฏธ๋„์„ ์—ด์–ด์„œ,

     > mkdir linkservice

     > cd linkservice

 

โŽฎํ”„๋กœ์ ํŠธ ํด๋”์—์„œ react ํ™˜๊ฒฝ์œผ๋กœ client ํด๋” ์ƒ์„ฑ

     > npx create-react-app client

โŽฎํ”„๋กœ์ ํŠธ ํด๋”์—์„œ python๊ฐ€์ƒํ™˜๊ฒฝ์œผ๋กœ serverํด๋” ์ƒ์„ฑ

     > python3 -m venv server

 โŽฎํ”„๋กœ์ ํŠธ ํด๋”์ธ linkservice ์•„๋ž˜์— client์™€ serverํ™˜๊ฒฝ์ด ๊ตฌ์ถ•๋˜์—ˆ๋‹ค. 

 

 ๋‹ค์ŒํŽธ์—๋Š”  Python Flask๋กœ API ์ œ์ž‘์„ ํ•ด๋ณด์ž.

1.    ๊ฐœ๋ฐœ ์ค€๋น„

1.1. ์‚ฌ์ „ ์ค€๋น„ ์ž‘์—…

๋ฐฑ์—”๋“œ(BACK-END) : Python, Flask, SQLAlchemy์„ ํ†ตํ•ด RESTful API์ œ์ž‘,

ํ”„๋ก ํŠธ์—”๋“œ(FRONT-END) : React, Bootstrap, material ui ์„ ์‚ฌ์šฉํ•˜์—ฌ page ์ œ์ž‘

๋ฐ์ดํƒ€๋ฒ ์ด์Šค(DB) : PostgreSQL

  

1.2. ์„ค์น˜ ํ”„๋กœ๊ทธ๋žจ

์„ค์น˜๋ฐฉ๋ฒ•์€ ๋ณ„๋„ ์„ค๋ช…ํ•˜์ง€ ์•Š์œผ๋ฉฐ, ํ•„์š”์‹œ ๊ฒ€์ƒ‰ํ•˜์‹œ๋ฉด ๋งŽ์€ ์ž๋ฃŒ๋“ค์ด ๋‚˜์™€ ์žˆ๋‹ค.

 

๐Ÿ‘€ ๋ฐฑ์—”๋“œ(BACK-END)

ยท Python3.6.X ( ์šด์˜์ฒด์ œ์— ๋งž๊ฒŒ ์„ค์น˜ )

๋‹ค์šด๋กœ๋“œ ์‚ฌ์ดํŠธ : https://www.python.org/downloads/

 

ยท POSTMAN

๋‹ค์šด๋กœ๋“œ ์‚ฌ์ดํŠธ: https://www.getpostman.com/products

 

ยท PostgreSQL ์ตœ์‹ ๋ฒ„์ „( ์šด์˜์ฒด์ œ์— ๋งž๊ฒŒ ์„ค์น˜ )

๋‹ค์šด๋กœ๋“œ ์‚ฌ์ดํŠธ: https://www.enterprisedb.com/downloads/postgres-postgresql-downloads

 

ยท DBeaver Community ๋ฒ„์ „( ์šด์˜์ฒด์ œ์— ๋งž๊ฒŒ ์„ค์น˜ )

๋‹ค์šด๋กœ๋“œ ์‚ฌ์ดํŠธ: https://dbeaver.io/download/

๏ƒ  DBeaver๋Š” DBํˆด์ด๋ฏ€๋กœ ๋‹ค๋ฅธ DBํˆด์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด ๋ณ„๋„ ์„ค์น˜ ์•ˆ ํ•ด๋„ ๋œ๋‹ค.

 

๐Ÿ‘€ ํ”„๋ก ํŠธ์—”๋“œ(FRONT-END)

ยท Node.js ์™€ NPM

๋‹ค์šด๋กœ๋“œ ์‚ฌ์ดํŠธ : https://nodejs.org/ko/download/

ยท NPX ์„ค์น˜ : ๋ช…๋ น ํ”„๋กฌํ”„ํŠธ์—์„œ ์‹คํ–‰> npm install npx -g

ยท Yarn ์„ค์น˜ : ๋ช…๋ น ํ”„๋กฌํ”„ํŠธ์—์„œ ์‹คํ–‰> npm install yarn -g

1. ๊ธฐ๋ณธ ์„ค๊ณ„

ํ™”๋ฉด
ํ™”๋ฉด ๋‚ด์šฉ๊ณผ DB ๋ฐ API ์ •์˜

๊ฐ„๋‹จํ•œ ํ”„๋กœ๊ทธ๋žจ์ด์ง€๋งŒ, ํ”„๋กœ์ ํŠธ ๋งค๋‹ˆ์ €๋‚˜ ๊ธฐํš์ž์ฒ˜๋Ÿผ, ๊ฐœ๋ฐœ ์ด์ „์— ์–ด๋Š์ •๋„ ์„ค๊ณ„๊ฐ€ ๋˜์–ด์•ผ ๊ฐœ๋ฐœ์˜ ์ผ๊ด€์„ฑ์ด ์ƒ๊ธด๋‹ค.

ํ˜ผ์ž์„œ ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์„ ํ•˜๊ฒŒ ๋˜์–ด ์‹ค์ œ ๋‚ด์šฉ์ด ์–ด์„คํ”„๋”๋ผ๋„ ์–‘ํ•ดํ•ด์ฃผ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

 

ํ™”๋ฉด์€ ๋””์ž์ธ์ด ๋˜์—ˆ์ง€๋งŒ, ์‚ฌ์‹ค ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ํผ๋ธ”๋ฆฌ์‹ฑ์„ ํ–ˆ๊ณ , ๊ทธ ๋‹จ๊ณ„ ๋‹จ๊ณ„๋ฅผ ์•ž์œผ๋กœ ๋ณด์—ฌ์ค„ ์˜ˆ์ •์ด๋‹ค.

 

IT๊ธฐ์—…์„ ๋‹ค๋‹ ๋•Œ๋Š” ์ด ๋ชจ๋“  ๊ฒƒ์„ ์‚ฐ์ถœ๋ฌผ ํ˜•ํƒœ๋กœ ํŒŒ์›Œํฌ์ธํŠธ์™€ ์—‘์…€๋กœ ์ž‘์—…์„ ํ–ˆ์ง€๋งŒ, ์š”์ฆ˜์€ ์Šค์ผ€์น˜(Sketch), ํ”ผ๊ทธ๋งˆ(Figma), XD์™€ ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค ๋””์ž์ธ์„ ์œ„ํ•œ ํ˜‘์—… ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋“ฑ์ด ๋งŽ์ง€๋งŒ, ๊ธฐ ์‚ฌ์šฉํ•ด๋ณธ Figma์„ ํ†ตํ•ด ๊ฐ„๋‹จํžˆ UI์„ค๊ณ„๋ฅผ ์ง„ํ–‰ ํ–ˆ๋‹ค. UI๋ถ€๋ฌธ๋„ ๋ณดํ†ต ๊ธฐ์—…์—์„œ๋Š” ๋””์ž์ธํŒ€์—์„œ ์ œ์ž‘ํ•˜์—ฌ ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœ์‹œ์— ๋ถ€๋‹ด์ด ๋œ ํ•  ์ˆ˜ ์žˆ์œผ๋‚˜, ๋””์ž์ธ์ด ์•ฝํ•œ ๋‚˜๋Š” CSS์—์„œ ๋งŽ์€ ์‹œ๊ฐ„์„ ํ—ˆ๋น„ํ–ˆ๋‹ค.

์—ฌ๋Ÿฌ ์‚ฌ์ดํŠธ์˜ CSS์„ ์ฐธ๊ณ ํ•˜์—ฌ ๋‚˜๋ฆ„๋Œ€๋กœ ๋งŒ๋“  ๊ฒƒ์œผ๋กœ, ํผ๋ธ”๋ฆฌ์‹ฑ์— ๋Šฅํ•œ ๋ถ„์ด๋ผ๊ณ  ๋‚˜๋ฆ„ ์ˆ˜์ •ํ•˜์…”์„œ ์‚ฌ์šฉํ•ด๋„ ๋ฌด๋ฐฉํ•˜๋‹ค

 

1.1. DB ์„ค๊ณ„

UI ์„ค๊ณ„๋œ ๊ธฐ์ค€์œผ๋กœ DB ์„ค๊ณ„๋ฅผ ํ•ด๋ณด์ž. ๋˜ํ•œ ๊ธฐ๋ณธ์ ์ธ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ํ…Œ์ด๋ธ”๋„ ๊ตฌ์„ฑํ•œ๋‹ค.

  1) Link์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ํ…Œ์ด๋ธ” ( links )

  2) ์›Œ๋“œ ํด๋ผ์šฐ๋“œ๋ฅผ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•œ ํ…Œ์ด๋ธ”( tagcloud )

       โ–ท ์›Œํฌ ํด๋ผ์šฐ๋“œ๋Š” ๋ณ„๋„ ๊ตฌํ˜„ ์•ˆ ํ•ด๋„ ๋˜๋ฉฐ, ํ–ฅํ›„ ํ•„์š”์‹œ ์†Œ์Šค๋งŒ ์ฐธ๊ณ ํ•˜๊ธฐ ๋ฐ”๋ž€๋‹ค.

3) ์ผ์ •์„ ๋“ฑ๋ก( ํ–‰์‚ฌ์˜คํ”ˆ์ผ์ • ๋“ฑ )์„ ์œ„ํ•œ ํ…Œ์ด๋ธ” ( plans )

       โ–ท ํ™”๋ฉด ์ปค๋ฒ„ ์ด๋ฏธ์ง€์— ์ผ์ •์ด ํ‘œ์‹œ๋  ์˜ˆ์ •์ด๋‹ค.

4) ๋กœ๊ทธ์ธ์„ ์œ„ํ•œ ์œ ์ €์ •๋ณด ํ…Œ์ด๋ธ” ( user )

 

1.2. API์ •์˜

๊ฐ DB ํ…Œ์ด๋ธ”์˜ ๊ธฐ๋ณธ CRUD์„ API๋กœ ์ •์˜ํ•˜๊ณ , ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ, ํšŒ์›๊ฐ€์ž…์ฒ˜๋ฆฌ, ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๊ธฐ๋ณธ API์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

 

๋ชจ๋“  API์„ ๋ฏธ๋ฆฌ ๊ธฐ๋กํ•ด๋‘๊ณ  ์‹ถ์ง€๋งŒ, ์„ค๋ช…์„ ์œ„ํ•ด์„œ ์—ฌ๊ธฐ์„œ ์ •์˜๋˜์ง€ ์•Š์€ API ๋Š” ๊ฐœ๋ฐœ ๊ณผ์ •์—์„œ ์ถ”๊ฐ€ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

 


๋‹ค์ŒํŽธ์— ๊ณ„์†........

 

1.    ๊ฐœ๋ฐœ ๊ฐœ์š”

 

IT๊ธฐ์—…์„ ํ‡ด์‚ฌ ํ›„ ๊ฐœ๋ฐœ ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ•˜๋ฉด์„œ ์–ด๋–ค ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ฐฐ์šธ๊นŒ ๊ณ ๋ฏผํ•˜๋ฉด์„œ ์˜ˆ์ „์— ์ž ๊น ๊ณต๋ถ€ํ–ˆ๋˜ Angularjs์„ ๋‹ค์‹œ ํ•ด๋ณผ๊นŒ ํ–ˆ์œผ๋‚˜, ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ฐฐ์šฐ๊ธฐ๋กœ ๋งˆ์Œ ๋จน์œผ๋ฉด์„œReact์™€ Python ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ–ˆ๋‹ค.

 

๋‹ค๋‹ˆ๋˜ ํšŒ์‚ฌ๋Š” JAVA์˜ ์œ„์ฃผ์˜ MSA, ์ž์ฒด ํ”„๋ ˆ์ž„์›Œํฌ ์†”๋ฅ˜์…˜๋“ฑ ์‚ฌ์šฉํ•˜์—ฌ, ์ตœ์‹  ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ฐฐ์šธ ์‹œ๊ฐ„๋„ ์—†์—ˆ๊ณ , ๊ณผ์žฅ๊ธ‰ ์ดํ›„ ๋ถ€ํ„ฐ๋Š” ๊ฐœ๋ฐœ๋ณด๋‹ค๋Š” BA ์—ญํ• ๋งŒ ํ•˜๋‹ค ๋ณด๋‹ˆ, ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ƒˆ๋กญ๊ฒŒ ๊ณต๋ถ€ํ•˜๋Š”๊ฒƒ์ด ์–ด๋ ค์›€์ด ์žˆ์—ˆ๋‹ค.

 

๋ณธ ๋‚ด์šฉ์€ ์•ฝ 2๋‹ฌ๊ฐ„ React์™€ Python์„ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ๊ตฌ์ถ•ํ•œ ๋‚ด์šฉ์˜ ์†Œ์Šค๋ฅผ ๊ฐœ๋ฐœ ๋‹จ๊ณ„๋ถ€ํ„ฐ ํ•˜๋‚˜ํ•˜๋‚˜ ๋”ฐ๋ผ ํ• ์ˆ˜ ์žˆ๋„๋ก ๊ณต์œ ํ•˜์—ฌ ๋งŽ์€ ๋ถ„๋“ค๊ณผ ๋‚˜๋ˆ„๊ณ ์ž ํ•œ๋‹ค.

 

๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๋‹ค๋ณด๋‹ˆ, ์ดˆ๋ณด ํ˜น์€ ์ฒซ ํ”„๋กœ์ ํŠธ ์‹ ์ž…์€ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ ๋‹ค.

์†Œ์Šค ์œ„์ฃผ์˜ ๋‚ด์šฉ์ด๋ฏ€๋กœ, ์†Œ์Šค๋‚ด์— ์ฃผ์„์ฒ˜๋ฆฌ๋ฅผ ํ–ˆ๋‹ค๊ณ  ํ–ˆ์œผ๋‚˜, ๋งŽ์ด ๋ถ€์กฑํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ, ๊ธฐ๋ณธ์ ์ธ ๊ฐœ๋…์€ ์•Œ๊ณ  ์žˆ๋‹ค๋Š” ๊ฐ€์ •ํ•˜์— ์ง„ํ–‰๋˜๋ฏ€๋กœ, ํ•„์š”์‹œ ๊ฒ€์ƒ‰์„ ํ†ตํ•ด ์ถ”๊ฐ€์ ์œผ๋กœ ๊ณต๋ถ€๋ฅผ ํ•˜์‹œ๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.

 

๊ฐœ๋ฐœํ•  ๋•Œ ๊ฐœ๋…์ ์ธ ์„ค๋ช…๋งŒ ํ•˜๋Š” ์ž๋ฃŒ๊ฐ€ ๋งŽ์•„, ์‹ค์ œ ์šด์˜๋˜๋Š” ์ฐธ๊ณ ์†Œ์Šค๋ฅผ ์ฐพ๊ธฐ๊ฐ€ ์–ด๋ ค์šด ๊ฒฝํ—˜์ด ์žˆ์—ˆ๊ณ , ์ด๋Ÿฐ ๊ฒฝํ—˜์„ ์ดˆ๋ณด ๊ฐœ๋ฐœ์ž๋“ค์—๊ฒŒ ์กฐ๊ธˆ์ด๋‚˜๋งˆ ๋„์›€์„ ์ฃผ๊ณ ์ž ๋ชจ๋“  ์†Œ์Šค๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š”๊ฒƒ์„ ๋”ฐ๋ผํ•˜๋ฉด์„œ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์„ ์ตํžˆ๊ธฐ ๋ฐ”๋ผ๋Š” ๋งˆ์Œ์— ์•ž์œผ๋กœ ๊ณ„์† ์—ฌ๊ธฐ์— ๊ธฐ๋ก์„ ๋‚จ๊ธฐ๋ฉด์„œ ์ง„ํ–‰ํ•  ์˜ˆ์ •์ด๋‹ค.

 

   โ€ป ์ตœ์ข… ์†Œ์Šค๋Š” ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„  or ์ค‘๊ฐ„๋‹จ๊ณ„์— git์œผ๋กœ ๊ณต์œ ํ•  ์˜ˆ์ •์ด๋‹ค.

 

1.1. ๋ฌด์—‡์„ ๋งŒ๋“ค ๊ฒƒ์ธ๊ฐ€?

๊ฐœ๋ฐœ ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ•˜๋ฉด์„œ ๋ฌด์ž‘์ • ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค ์–ด๋–ค ๊ฒƒ์„ ๋งŒ๋“ค์ง€ ๋ชฉํ‘œ๋ฅผ ์ •ํ•ด์„œ ๊ณต๋ถ€๋ฅผ ํ•˜๋ฉด ์ข‹์„ ๋“ฏ ํ•˜๋‹ค.

 

์š”์ฆ˜์€ ๋งŽ์€ ์ธํ”Œ๋ฃจ์–ธ์Šค๋‚˜ ์œ ํˆฌ๋ฒ„ ๋“ฑ ํฌ๋ฆฌ์—์ดํ„ฐ ๋ถ„๋“ค์ด ๋‹ค์–‘ํ•œ ์ฝ˜ํ…์ธ ๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๋ฉ€ํ‹ฐ๋งํฌ ์‚ฌ์ดํŠธ๋“ค์ด ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค.

๋ฉ€ํ‹ฐ ๋งํฌ ์„œ๋น„์Šค๋Š” ์ธ์Šคํƒ€๊ทธ๋žจ, ๋ธ”๋กœ๊ทธ, ๋งˆ์ผ“ ๋“ฑ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋งํฌ๋ฅผ ํ•œ๊ณณ์— ๋“ฑ๋กํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค

 

     ์˜ˆ) ๋งํฌํŠธ๋ฆฌ(Linktree), ์ธํฌํฌ๋งํฌ(Inpock link), ๋งํฌ๋ฏน์Šค(Link Mix), ๋ฆฌํ‹€๋ฆฌ(litt.ly), ๋งํฌ์˜จ(Linkon), ๋ฆฌํŠธ๋งํฌ(Lit.Link) ๋“ฑ๋“ฑ

           ์•ฝ 20์—ฌ๊ฐœ๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์•Œ๊ณ  ์žˆ๋‹ค.

 

๊ฐ„๋‹จํ•œ ์„œ๋น„์Šค์ธ ๋งŒํผ ์‚ฌ์—… ๋ชฉ์ ์œผ๋กœ ๊ฐœ๋ฐœ์ด ์•„๋‹ˆ๋ฏ€๋กœ, ๋ฉ€ํ‹ฐ์œ ์ €๋‚˜ ๋ฉ€ํ‹ฐ์ปดํผ๋‹ˆ ๊ฐ™์€ ์„œ๋น„์Šค๋Š” ์ œ์™ธํ•˜๊ณ , ๊ธฐ๋ณธ ๊ธฐ๋Šฅ๊ณผ ์‚ฌ์ดํŠธ์— ์šด์˜์— ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ๊ณจ๋ผ ๋งํฌ์„œ๋น„์Šค๋ฅผ ๊ตฌํ˜„ํ•ด ๋ณด๊ณ ์ž ํ•œ๋‹ค.

 


๋‹ค์ŒํŽธ์€ ๊ฐ„๋‹จํ•œ ์„ค๊ณ„๋ฅผ ์ง„ํ–‰ํ•˜๊ฒ ๋‹ค.

 

โ€ป ๋ณธ ํฌ์ŠคํŒ…์€ ๊ณ„์† ์ˆ˜์ •๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

+ Recent posts