본문 바로가기
인터페이스 개발/DOM, OpenApi, Ajax

REST 서비스

by cooluk 2020. 10. 8.

REST 서비스

다른 머신의 데이터를 조작

 

REST 서비스

 

REST(Representational State Transfer)

  • 자원을 이름(자원의 표현)으로 구분하여 해당 자원의 상태(정보)를 주고 받는 모든 것을 의미
  • 즉, 자원(resource)의 표현(representation)에 의한 상태 젂달
  • 자원(resource)의 표현(representation)
    • 자원: 해당 소프트웨어가 관리하는 모든 것
      • Ex) 문서, 그림, 데이터, 해당 소프트웨어 자체 등
    • 자원의 표현: 그 자원을 표현하기 위한 이름
      • Ex) DB의 학생 정보가 자원일 때, ‘students’를 자원의 표현으로 정한다.
    • 상태(정보)
      • 전달데이터가 요청되어지는 시점에서 자원의 상태(정보)를 전달
      • JSON 혹은 XML를 통해 데이터를 주고 받는 것이 일반적
  • 네트워크 상에서 Client와 Server 사이의 통신 방식 중 하나

 

REST 구성 요소

  • 자원(Resource) URI
    • 모든 자원에 고유핚 ID가 존재, 이 자원은 Server에 존재
    • 자원을 구별하는 ID는 '/groups/:group_id'와 같은 HTTP URI
    • Client는 URI를 이용해서 자원을 지정하고 해당 자원의 상태(정보)에 대핚 조작 을 Server에 요청
  • 행위(Verb)
    • HTTP MethodHTTP 프로토콜의 Method를 사용
      • GET, POST, PUT, DELETE 등
  • 표현(Representation of Resource)
    • Client가 자원의 상태(정보)에 대해 조작 요청시 Server는 이에 적젃핚 응답 (Representation)을 내보냄
    • 표현 방식
      • JSON, XML, TEXT, RSS 등
    • JSON을 통해 데이터를 주고 받는 것이 일반적임

 

REST 표현 방식

  • 자원명 : bookmark
    • 기본 URL: /api/bookmark
    • 목록 요청: GET /api/bookmark
    • 단일 항목 요청: GET /api/bookmark/2
    • 생성: POST /api/bookmark
    • 수정: PUT /api/bookmark/2
    • 삭제: DELETE /api/bookmark/2

CRUD를 http 프로토콜의 메서드 이용

 

REST API

  • REST기반으로 서비스 API를 구현핚 것
    • REST URI(Verbose)를 처리하는 View에서 REST 표현을 해석하고 처리
    • 응답 시 Json으로 응답
  • OpenAPI(구글 맵, 공공 데이터 등) 제공시 REST API를 제공



Django로 rest api 만들기

api 앱 생성

  • python mange.py startapp api

 

mysite/settings.py

INSTALLED_APPS = [
    :
    'api.apps.ApiConfig'
]

 

api/models.py

from django.db import models

class OpenBookmark(models.Model):
    title = models.CharField('TITLE', max_length=100, blank=True)
    url = models.URLField('URL', unique=True)

    def __str__(self):
        return self.title

migrate

 

api/views.py

from django.views.generic import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from django.http import JsonResponse
from django.forms.models import model_to_dict
import json

from api.models import OpenBookmark

class BaseApiView(View):
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

class BookmarkApi(BaseApiView):
    def get(self, request, id=None):
        if id : # 단일 항목 요청
            bookmark = OpenBookmark.objects.get(id=id)
            data = model_to_dict(bookmark)
            return JsonResponse(data)
        else : # 목록 요청
            datas = list(map(model_to_dict, OpenBookmark.objects.all()))
            return JsonResponse({"datas" : datas})
    def post(self, request):
        json_data = json.loads(request.body.decode("utf-8"))
        print(json_data)
        bookmark = OpenBookmark(**json_data)
        bookmark.save()
        data = model_to_dict(bookmark)
        return JsonResponse(data)

    def put(self, request, id):
        bookmark = OpenBookmark.objects.get(id=id)
        json_data = json.loads(request.body.decode("utf-8"))
        bookmark.title = json_data["title"]
        bookmark.url = json_data["url"]
        bookmark.save()
        data = model_to_dict(bookmark)
        return JsonResponse(data)

    def delete(self, request, id):
        bookmark = OpenBookmark.objects.get(id=id)
        bookmark.delete()
        return JsonResponse({"result": "OK"})

 

api/urls.py

from django.urls import path, re_path
from api.views import *

urlpatterns = [
    path('bookmark', BookmarkApi.as_view()),
    path('bookmark/<int:id>', BookmarkApi.as_view()),
]

 

mysite/urls.py

urlpatterns = [
    :
    path('api/', include('api.urls')),
]

 

httpie로 rest api 호출하기

  • http [flags] [METHOD] URL [ITEM [ITEM]]

    • ITEM

      • 이름==값
        쿼리 파라미터로 URL뒤에 ?로 연결
      • 이름=값
        POST/PUT의 파라미터로 BODY에 저장되어 전달
        값 부분이 따움표로 묶임
      • 이름:=값
        값 부분을 따움표로 묶지 않음
    • 디폴트로 Json 형식으로 요청

      • --json 이 디폴트
-   목록 요청

    -   http -v GET http://127.0.0.1:8000/api/bookmark

-   단일 항목 요청

    -   http -v GET http://127.0.0.1:8000/api/bookmark/1

-   생성

    -   http -v POST http://127.0.0.1:8000/api/bookmark title="test" url="http://daum2.net" owner:=1

-   수정

    -   http -v PUT http://127.0.0.1:8000/api/bookmark/13 title="test2" url="http://daum2.net"

-   삭제

    -   http -v DELETE http://127.0.0.1:8000/api/bookmark/13



Javascript로 rest api 호출

Ajax 기술로 Rest api 호출

image-20201007152838039

  • axios 라이브러리 활용
  • CDN
  • 주요 메서드
    • axios.request(config)
    • axios.get(url[, config])
    • axios.delete(url[, config])
    • axios.head(url[, config])
    • axios.options(url[, config])
    • axios.post(url[, data[, config]])
    • axios.put(url[, data[, config]])
    • axios.patch(url[, data[, config]])

 

axios 메서드 형식

  • axios.메서드()
.then(res=>{ // 호출 성공 시 호출핛 함수
 // res.data에 서버 응답 내용이 저장되어 있음
})
.catch(e=>{ // 호출 실패 시 실행핛 함수
});

 

static/openbookmark.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" >
</head>

<body>
<div>
    <h1>Open Bookmark</h1>
    <div class="w-75 mx-auto">
        <form id="frm">
            <input type="hidden" name="id" id="item-id">
            <div class="row">
                <div class="col-sm-2">타이틀</div>
                <div class="col-sm-8">
                    <input type="text" name="title" class="w-100">
                </div>
            </div>
            <div class="row">
                <div class="col-sm-2">url</div>
                <div class="col-sm-8">
                    <input type="text" name="url" class="w-100">
                </div>
            </div>
            <div class="row">
                <div class="col-sm-2"></div>
                <div class="col-sm-8">
                    <input type="button" id="submit-btn" value="확인">
                    <input type="button" id="reset-btn" value="취소">
                </div>
            </div>
        </form>
        <div class="my-5">
            <h4>bookmark 목록</h4>
            <ul id="bookmark-list"></ul>
        </div>
    </div>
</div>
</body>

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="/static/js/common.js"></script>
<script src="/static/js/openbookmark.js"></script>
</html>

 

static/js/common.js

// 이벤트 처리 위임
HTMLElement.prototype.on = function (eventName, selector, handler){
    let self = this;
    self.addEventListener(eventName, function(e){
        elements = self.querySelectorAll(selector);
        let target = e.target;
        elements.forEach(item=>{
            if(item == target) {
                handler.call(target, e);
            }
        });
    });
}

 

static/js/openbookmark.js

// 전역변수

// form
let frm = document.forms["frm"];
// 버튼들
let addBtn = document.getElementById("submit-btn");
let resetBtn = document.getElementById("reset-btn");
// 북마크 리스트
let bookmarkList = document.getElementById("bookmark-list");
// form reset
function reset() {
    frm.elements.namedItem("id").value = ''
    frm.elements.namedItem("title").value = '';
    frm.elements.namedItem("url").value = '';
}
// 취소 버튼 핸들러 등록
resetBtn.addEventListener("click", reset);


// 초기 목록 구축

// DOM에 새로운 bookmark 정보 추가
function addItem(bookmark) {
    let templ = '
        <a href="${bookmark.url}" class="bookmark-link">${bookmark.title}</a>
        [<a href="#" class="edit-btn">수정</a>]
        [<a href="#" class="delete-btn">삭제</a>]
    ';
    let el = document.createElement('li');
    el.dataset.itemId = bookmark.id;
    el.classList.add("list-item");
    el.innerHTML = templ;
    bookmarkList.appendChild(el);
}
// 초기 목록 얻기
axios.get("http://127.0.0.1:8000/api/bookmark")
.then(res=>{
    res.data.datas.forEach(item=>addItem(item));
}).catch(e=>console.log(e));


// 추가하기

// 폼 입력 확인
function check_frm() {
    let title = frm.elements.namedItem("title").value;
    if(!title) return alert("title을 입력하세요");
    let url = frm.elements.namedItem("url").value;
    if(!url) return alert("url을 입력하세요");
    return { title, url };
}

// 확인 버튼 핸들러 등록: itemId가 없으면 추가, 있으면 수정
addBtn.addEventListener("click", event=>{
    let itemId = frm.elements.namedItem("id").value.trim();
    data = check_frm();
    if(!data) return;
    if(!itemId) {// 추가
        axios.post("http://127.0.0.1:8000/api/bookmark", data)
            .then(res=>{
            addItem(res.data);
            reset();
        }).catch(e=>console.log(e));
    } else { // 수정
        // 추후 구현
    }
});


// 수정

// 수정 - 클릭핚 아이템을 수정 화면으로 설정
bookmarkList.on("click", ".edit-btn", function(e){
    let el = this.closest(".list-item");
    let itemId = el.dataset.itemId;
    let bookmark = el.getElementsByClassName("bookmark-link")[0];
    let title = bookmark.innerHTML;
    let url = bookmark.href;
    frm.elements.namedItem("id").value = itemId
    frm.elements.namedItem("title").value = title;
    frm.elements.namedItem("url").value = url;
});
// 지정한 bookmark id의 <a> 엘리턴트를 찾아 리턴
function findItem(id) {
    let items = bookmarkList.getElementsByClassName("bookmark-link");
    let length = items.length;
    for(let i = 0; i<length; i++) {
        if( items[i].parentNode.dataset.itemId == id)
            return items[i];
    }
}
// 수신한 수정된 bookmark 정보 갱신
function updateItem(bookmark){
    let el = findItem(bookmark.id);
    if(el) {
        el.href = bookmark.url;
        el.innerHTML = bookmark.title;
    }
}
// 확인 버튼 핸들러 등록: itemId가 없으면 추가, 있으면 수정
addBtn.addEventListener("click", event=>{
    let itemId = frm.elements.namedItem("id").value.trim();
    data = check_frm();
    if(!data) return;
    if(!itemId) {// 추가
        axios.post("http://127.0.0.1:8000/api/bookmark", data)
        .then(res=>{
            addItem(res.data);
            reset();
        }).catch(e=>console.log(e));
    } else { // 수정
        axios.put('http://127.0.0.1:8000/api/bookmark/${itemId}', data)
        .then(res=>{
            updateItem(res.data);
            reset();
        }).catch(e=>console.log(e));
    } else {}
});


// 삭제

// bookmark 삭제
bookmarkList.on("click", ".delete-btn", function(e){
    if(!confirm("삭제하겠습니까?")) return;

    let el = this.closest(".list-item");
    let itemId = el.dataset.itemId;

    axios.delete('http://127.0.0.1:8000/api/bookmark/${itemId}')
    .then(res=>el.remove())
    .catch(e=>console.log(e));
});

 

'인터페이스 개발 > DOM, OpenApi, Ajax' 카테고리의 다른 글

Ajax  (0) 2020.10.08
이미지 검색 API  (0) 2020.10.08
Requests  (0) 2020.10.08
JSON  (0) 2020.10.08
DOM 이벤트  (0) 2020.10.08

댓글