본문 바로가기
Flask

Flask - bootstrap·vue(axios)/flask로 REST API 구현

by DGK 2021. 11. 27.

 

Flask 입문 수업을 듣고 중요한 내용을 정리했습니다.
개인 공부 후 자료를 남기기 위한 목적이므로 내용 상에 오류가 있을 수 있습니다.

 

bootstrap·vue·flask로 REST API 구현하기(Python)

bootstrap·vue·flask로 REST API를 구현하고, HTTP 통신을 하는 연습을 하고자 한다.

 

bootstrap·vue·axios code(front-end)

<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />

    <!-- Bootstrap CSS -->
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
      integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
      crossorigin="anonymous"
    />

    <title>Hello, world!</title>
  </head>
  <body>
    <div id="app">
      <br />
      <center>
        <button type="button" class="btn btn-primary" v-on:click="test_get">
          GET
        </button>
        <button type="button" class="btn btn-secondary" v-on:click="test_post">
          POST
        </button>
        <button type="button" class="btn btn-success" v-on:click="test_put">
          PUT
        </button>
        <button type="button" class="btn btn-danger" v-on:click="test_delete">
          DELETE
        </button>
      </center>
    </div>
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script
      src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
      integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
      crossorigin="anonymous"
    ></script>
    <script
      src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
      integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
      crossorigin="anonymous"
    ></script>
    <script
      src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"
      integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI"
      crossorigin="anonymous"
    ></script>

    <!-- Vue Start -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script>
      const app = new Vue({
        el: "#app",
        methods: {
          test_get: () => {
            axios("http://localhost:8082/test", {
              method: "get",
              params: {
                email: "test@test.com",
              },
            })
              .then((response) => {
                console.log(response.data["status"]);
              })
              .catch((error) => {
                console.log(error);
              });
          },
          test_post: () => {
            axios("http://localhost:8082/test", {
              method: "post",
              data: {
                email: "test@test.com",
              },
            })
              .then((response) => {
                console.log(response.data["status"]);
              })
              .catch((error) => {
                console.log(error);
              });
          },
          test_put: () => {
            axios("http://localhost:8082/test", {
              method: "put",
              params: {
                email: "test@test.com",
              },
            })
              .then((response) => {
                console.log(response.data["status"]);
              })
              .catch((error) => {
                console.log(error);
              });
          },
          test_delete: () => {
            axios("http://localhost:8082/test", {
              method: "delete",
              params: {
                email: "test@test.com",
              },
            })
              .then((response) => {
                console.log(response.data["status"]);
              })
              .catch((error) => {
                console.log(error);
              });
          },
        },
      });
    </script>
  </body>
</html>

 

*참고

위의 vue, axios, bootstrap 라이브러리는 모두 CDN 방식을 사용한 것이다.

 

 

Python flask code(back-end)

from flask import Flask, request, make_response, jsonify
from flask_cors import CORS

app = Flask(__name__)
CORS(app)


@app.route("/test", methods=['GET', 'POST', 'PUT', 'DELETE'])
def test():
    if request.method == 'POST':
        print('POST')
        data = request.get_json()
        print(data)
        print(data['email'])
    if request.method == 'GET':
        print('GET')
        user = request.args.get('email')
        print(user)
    if request.method == 'PUT':
        print('PUT')
        user = request.args.get('email')
        print(user)
    if request.method == 'DELETE':
        print('DELETE')
        user = request.args.get('email')
        print(user)

    return make_response(jsonify({'status': True}), 200)


if __name__ == '__main__':
    app.run(host="0.0.0.0", port="8082")

 

*참고

CRUD 메서드(함수)를 모두 실행하는 REST API 구현 코드이다.

특정 url을 요청하면, json 형식으로 파라미터 값을 가져오고 json 형식의 데이터를 반환하도록 만든다.

또한, flask에서는 딕셔너리 데이터를 응답 데이터로 만들고 이를 jsonify() 함수를 통해 JSON 응답 데이터로 만든다.

 

 

bootstrap·vue(axios)/flask로 REST API 구현 및 HTTP 통신 결과

(bootstrap/vue/axios code 결과 : console)

 

(Python flask code 결과 : terminal)

GET
test@test.com
127.0.0.1 - - [27/Nov/2021 11:43:56] "GET /test?email=test%40test.com HTTP/1.1" 200 -
127.0.0.1 - - [27/Nov/2021 11:43:57] "OPTIONS /test HTTP/1.1" 200 -

 

POST
{'email': 'test@test.com'}
test@test.com
127.0.0.1 - - [27/Nov/2021 11:43:57] "POST /test HTTP/1.1" 200 -
127.0.0.1 - - [27/Nov/2021 11:43:57] "OPTIONS /test?email=test%40test.com HTTP/1.1" 200 -

 

PUT
test@test.com
127.0.0.1 - - [27/Nov/2021 11:43:57] "PUT /test?email=test%40test.com HTTP/1.1" 200 -

 

DELETE
test@test.com
127.0.0.1 - - [27/Nov/2021 11:43:58] "DELETE /test?email=test%40test.com HTTP/1.1" 200 -

 

 

이는 bootstrap·vue·axios/flask로 REST API를 구현하여, 해당 HTML 파일을 오픈한 웹 페이지(bootstrap·vue(axios))와 백엔드 서버(flask) 간의 HTTP 통신(요청/응답)한 결과를 보여주고 있다. 

 

*front-end(bootstrap·vue·axios) 관련 주요내용

  1. vue 라이브러리를 사용하면 웹 페이지의 조건에 따라 벡엔드에 요청/응답 없이 해당 웹 페이지의 특정 부분을 변경할 수 있다.
  2. axios 라이브러리는 웹 브라우저와 다른 시스템 간의 HTTP 통신을 가능하도록 만들어주며, HTML 파일에서 back-end의 REST API를 호출할 수 있다.
  3. vue 라이브러리를 통해 HTML 코드에서 제어할 부분을 선택한 후, axios 라이브러리를 통해 해당 부분을 제어할 함수를 정의할 수 있다.
  4. 즉, 해당 HTML 파일이 웹 브라우저에 오픈되면 vue 라이브러리로 선택한 HTML 파일의 특정 부분을 제어할 수 있는 vue 객체가 axios 코드 안에서 생성되고 해당 vue 객체 안에서 선택한 부분(HTML 코드)을 제어할 함수를 정의할 수 있다.
  5. 참고로, 위의 예시코드에서는 button 태그에서 v-on : click이라는 속성을 사용하여 해당 버튼을 눌렀을 때 axios 코드의 함수가 실행되도록 한다.
  6. vue 객체에는 HTML 파일의 특정 부분을 제어하는 인자(id 값 : #app)와 이를 제어할 함수를 정의하는 인자를 넣어준다.
  7. 또한, axios() 함수의 첫 번째 인자로는 back-end 서버 주소를 넣고, 두 번째 인자로는 HTML 파일을 제어할 함수를 넣으며 마지막 인자로 HTTP request로 전달할 파라미터를 넣어준다.
  8. axios 코드의 then 이하 부분에서는 back-end에서 받은 응답 결과(REST API로 형성된 JSON 형태의 데이터)를 인자 response로 할당한 후, console.log() 함수의 인자 값으로 전달해준다.

 

 

*back-end(flask) 관련 주요내용

  1. flask 코드에서 GET, PUT, DELETE 메서드는 코드의 형태가 비슷하지만, POST 메서드는 코드의 형태가 다르다.
  2. 참고로, route() 함수의 인자로 메서드를 지정하지 않으면 기본적으로는 GET 메서드가 해당 라우팅 경로에서 지원된다.
  3. POST 메서드는 request 객체의 get_json() 함수를 사용하여 해당 데이터를 json 형태로 특정 변수에 할당할 수 있다.
  4. 이렇게 할당된 변수에는 딕셔너리 형태와 유사한 json 데이터가 들어 있기 때문에, 딕셔너리 문법(키, 벨류)을 사용하여 해당 데이터의 벨류 값을 가져올 수 있다.
  5. 반면에 GET, PUT, DELETE 메서드는 request 객체의 args.get() 함수를 사용하여, 파라미터의 이름을 인자로 받아 특정 변수에 할당한 후 해당 변수를 활용하여 데이터를 가져올 수 있다.
  6. flask의 make_response() 함수를 사용하면 REST API의 응답 결과와 HTTP status code를 함께 front-end로 보낼 수 있다. (ex. make_response(jsonify({'status': True}), 200))

 

 

참고 내용

  • CORS

일반적으로는 특정 웹페이지에서 타 웹 페이지 혹은 타 서버의 데이터나 이미지를 참조하여 가져올 수 있다.

 

하지만 HTML 코드의 script 태그 안에서는 다른 웹 페이지 혹은 다른 서버의 데이터나 이미지를 참조하여 가져오려고 시도하면 에러를 발생시킨다. 이러한 에러는 same origin policy 때문에 발생하는 것으로 이것이 기본적인 웹 브라우저의 정책이다. 즉, script 태그 안에서는 반드시 동일한 서버에만 HTTP request를 해야한다는 것이다.

 

위의 예시코드에서는 script 태그 안에서 0.0.0.0:5500/ 서버로부터 0.0.0.0:8082/test 서버로 HTTP request를 하고 있기 때문에 기본적으로는 에러를 발생시킨다.

 

이러한 문제(에러)를 해결하기 위해서는 Python 코드에서 flask 객체에 CORS를 지원해야 한다. (flask_cors 라이브러리 활용) 이처럼 flask 객체에 CORS를 지원하도록 하면, HTTP response header에 Access-Control-Allow-Origin 관련 정보가 추가되어 더 이상 해당 웹 브라우저에 same origin policy 정책이 적용되지 않아 script 태그에서도 타 웹 페이지, 타 서버에 HTTP request를 할 수 있다.

 

*flask 객체에 CORS 지원 방법

from flask_cors import CORS

app = Flask(__name__)
CORS(app)

 

flask_cors 라이브러리를 설치(pip install flask_cors)한 후, 해당 라이브러리에서 CORS 클래스를 가져와서(import) 해당 클래스의 인자로 flask의 객체 이름을 넣어주면 된다.

 

이러한 과정을 통해, script 태그에서도 타 웹 페이지, 타 서버의 데이터나 이미지를 참조하여 가져올 수 있다.

(HTTP request 가능)

 

 

  • Request Method in HTML

기본적으로 HTML에서는 GET과 POST 메서드만을 지원한다. 

 

*GET : 정보 읽기(SELECT)

   - 전달이 필요한 파라미터들은 URL을 통해 전달함

 

*POST : 정보 입력(INSERT)

   - 전달이 필요한 파라미터들은 HTTP body에 포함되어 전달됨(사용자가 직접 확인 불가)

 

참고로, POST 방식이 파라미터 정보를 노출하지 않으므로 GET 방식보다는 POST 방식을 선호한다.

 

 

'Flask' 카테고리의 다른 글

Flask - MVC 패턴과 flask blueprint  (0) 2021.11.29
Flask - flask의 다양한 기능  (0) 2021.11.27
Flask - jinja2 template  (1) 2021.11.25
Flask - flask로 정적 웹 페이지 지원  (0) 2021.11.25
Flask - REST API의 이해를 위한 웹 기술  (0) 2021.11.24

댓글