Day10. REST API

0ㅑ채
|2024. 1. 26. 17:42

1. 웹 서비스를 구현하는 방식

서버 사이드 랜더링

  • 클라이언트(웹 브라우저)의 요청을 서버가 받아서 처리한 후 서버가 출력하는 코드를 만들어서 클라이언트에게 전송을 하고 클라이언트는 이 코드를 받아서 파싱해서 출력하는 방식
  • 서버 코드 와 클라이언트 코드를 하나의 프로젝트에 전부 작성
  • 서버 코드를 수정할 때 클라이언트 코드가 영향을 받을 수 있고 클라이언트 코드를 수정할 때 서버 코드가 영향을 받을 수 있습니다.
  • 이 방식으로 서비스를 만들려면 템플릿 언어라는 것을 학습을 해야 합니다.
  • 최근에는 이 방식을 선호하지 않습니다.

 

클라이언트 사이드 랜더링

  • 서버는 클라이언트 요청을 받아서 데이터(XML -> JSON)를 응답으로 전송하고 클라이언트는 응답을 받아서 직접 데이터를 해석해서 출력하는 코드를 만들고 화면에 랜더링하는 방식입니다.
  • 이 방식에서는 서버 프로그램(Python의 Django, Java의 Spring, JavaScript의 express.js 등) 과 클라이언트 프로그램(vue.js, react.js->next.js, android-java 나 kotlin, ios-swift, 플로터-dart 등) 을 별도로 작성합니다.
  • 서버 코드 가 클라이언트 코드에 영향을 주지 않고 클라이언트 코드가 서버 코드에 영향을 주지 않습니다.
  • 이렇게 통신만으로 서로 연동되는 경우를 느슨한 결합(loosly coupling)이라고 합니다.
  • 최근에는 프로그램에 유지보수가 자주 발생하므로 이러한 느슨한 결합의 형태로 프로그램을 만들기를 권장합니다.


    프로그래밍 언어에서의 객체
 {name:"아담", age:53} - dict
 
 person = Person()
 person.name = "아담"
 person.age = 53

 

일반 테스트

  • 아담 53
  • 군계일학 47

tsv - 탭으로 구분

  • 아담  53
  • 군계일학  47

csv - 콤마로 구분

  • 이름,나이
  • 아담,53
  • 군계일학,47



XML(eXtensible Markup Language)

  • 데이터를 태그로 표현, 현재는 일부 RSS 서비스에서 사용이되고 설정 파일에서 많이 이용
	<persons>	
		<person>
			<name>아담</name>
			<age v="53" />
		</person>
		<person>
			<name>군계</name>
			<age v="52"></age>
		</person>
	</persons>



JSON(JavaScript Object Notation)

  • 자바스크립트 객체 표현법: 파이썬 과 동일): 최근에 데이터 교환에 가장 많이 사용, 모바일은 거의 대부분 이 방식
#객체:{ }
#배열:[ ]

[{"name":"아담", "age":53}, {"name":"군계", "age":52}]



YAML

  • 이메일 표현 방식을 이용해서 데이터를 표현, 최근에 설정에 많이 이용
person:
name: 아담
age: 53
person:
name: 군계
age: 52



 

 

2. REST 6가지 제약 조건

Representational State Transfer의 약자로 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식

별도의 전송 계층 없이 간단한 인터페이스로 자원을 정의하는 방식

 

1) Client-Server 구조

 

2) Stateless

  • 무상태, 이전에 했던 작업에 대한 내역을 가지고 있지 않다. 
  • 무상태란,
더보기
서버 <----------------> 클라이어트
<- 요청에 대한 응답이 가능한지 요청을 전송
응답 여부를 전송(메타 데이터를 전송) ->
<- 요청 처리
응답 전송 ->
<- 응답에 대한 결과 전송

 

기본적인 통신 방법으로는 한번 로그인한 정보를 계속 기억할 수가 없다. 

그래서 

서버 쪽에는 Session을 두고, 클라이언트 쪽에는 Cookie를 둔다. 

Sesion: 클라이언트의 정보를 서버에 저장, 연결이 끊어지면 자동 소멸

Cookie: 클라이언트의 정보를 클라이언트에 저장한 후 서버에 요청할 때마다 전송 (토큰이라고도 한다.), 연결이 끊어져도 계속 있어서 클라이언트 혹은 서버가 지울 때까지 있음. 

 

무상태란, 이런 Session과 Cookie를 저장하지 않겠다는 뜻!

 

장점: 번거로운 절차가 없다. 

단점: 똑같은 일을 매번 할 때 귀찮다. 그럴 때는 임시 패찰을 준다. 그걸 캐싱이라고 함!

 

3) Cacheable Data

 

4) Layered System

  • 여러 개의 계층으로 나누어서 서비스가 가능
더보기

 

* A/B테스트: 목적은 같지만 구현 방식이 다른 두개를 테스트하여 더 좋은 것을 결정

 

5) A Uniform Interface

  • 인터페이스가 일관성이 있어야 한다.

- 아이템을 가져오는 URL -  http://www,adamsoft.co.kr/item/get

- 아이템을 추가하는 URL -  http://www,adamsoft.co.kr/item/insert

- 아이템을 수정하는 URL -  http://www,adamsoft.co.kr/update    #이런 식이면 안돼욧!

 

6) Code-On-Demand

  • 선택적 사항으로 클라이언트는 서버에 코드를 요청할 수 있고, 서버가 리턴한 코드를 클라이언트에서 실행할 수 있다. 

 

제약조건을 지켜서 만든 서버, RESTful 하네!

 

 

3. django에서 REST API Server를 구현하기 위한 방법

- views에서 JsonResponse를 리턴하는 방식

  • 테스트를 하고자 하면 클라이언트를 구현하거나 테스트 도구를 사용해야 한다.

- djangorestframework라는 패키지를 이용하는 방식: 자체 테스트가 가능

  • 일관성이 없다.

 

1) 프로젝트와 앱을 생성하고 기본 설정 후 테스트

가상환경 생성

python -m venv myvenv
myvenv\Scripts\activate
pip install django djangorestframework, mysqlclient
  • 만약 안되면 앞에 python -m을 붙여보자

 

프로젝트 생성

django-admin startproject apiproject

 

애플리케이션 생성

python manage.py startapp apiapp

 

기본 설정 변경: 프로젝트의 settings.py

INSTALLED_APPS = [
    ...
    "apiapp", #나의 애플리케이션 이름
    "rest_framework", 
]

 

데이터베이스 접속 정보 수정

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
        "USER": "root",
        "PASSWORD":"0000",
        "HOST":"127.0.0.1",
        "PORT":"3306"        
    }
}

 

시간 대역 수정

TIME_ZONE = "Asia/Seoul"

 

변경 내용 데이터베이스에 저장

python manage.py makemigrations
python manage.py migrate

  • 이전에 적용한 내용과 차이가 없다. 오류 아님!!

 

 

 

2) 요청 처리

- 요청을 분할해서 처리

지금까지는 모든 요청 처리를 프로젝트의 urls.py에 작성해서 사용했다.

요청이 많아지면 프로젝트의 urls.py 파일의 내용이 많아지고 한 곳에 내용이 많아지면 소스 코드를 읽기가 어려워지고, 읽기가 어려워지면 유지보수가 어렵고, 여러 명이 동시에 작업하기 어렵다.

 

URL 요청을 분할해서 처리할 때는 프로젝트의 urls.py 파일에 django.urls.include를 import하고 

path("공통url", include("처리할 모듈 이름"))를 추가해주면 된다.

 

 

3) ret api 작업 ㅡ프로젝트 가져오기

레포지토리 주소

myvenv\Scripts\activate
pip install -r requirements.txt 
#혹은 python -m pip install -r requirements.txt
from django.urls import include
  • url의 처리를 다른 모듈에게 위임하고자 할 때 사용하는 패키지를 import
urlpatterns = [
    path("admin/", admin.site.urls),
    path("example/", include("apiapp.urls")),
]
  • example로 시작하는 요청이 오면 apiapp 애플리케이션의 urls.py 파일에 처리를 위임

 

example/hello 라는 요청이 오면 메세지를 출력하는 처리 작성

- apiapp.views.py 파일에 요청이 오면 처리하는 함수를 작성

#화면 안만들어서 render 필요 없음
from rest_framework.response import Response
from rest_framework.decorators import api_view

#GET 요청이 오면 함수를 호출
@api_view(['GET'])
def hello(request):
    return Response("Hello REST API")
  • python에서 @으로 시작하는 단어는 decorator라고 하는데 
  • 실제 함수를 호출하기 전에 특정 내용을 삽입해서 함수를 실행한다. 
  • 그래서 반복적으로 사용하는 내용이나 직접 작성하기 번거로운 내용을 decorator로 만든다.

 

앱(apiapp) 디렉토리에 urls.py 파일을 생성하고 url을 연결하는 코드를 작성

from django.urls import path
from .views import hello

urlpatterns = [
    path("hello/", hello),
]

 

서버를 구동하고 127.0.0.1/example/hello 요청 전송하고 결과 확인

 

 

 

5) 데이터베이스에 테이블을 생성

models.py 파일에 Model 클래스로부터 상속받는 클래스를 생성

 

변경 내용 데이터베이스에 반영

python manage.py makemigrations
python manage.py migrate

 

데이터베이스에서 apiapp_book 테이블 만들어졌는지 확인

show tables;

 

 

 

6) 삽입과 조회

삽입하는 방법

  • 클라이언트가 삽입할 데이터를 매개변수로 전송하면
  • 서버는 매개변수를 각각 읽어서 모델 클래스로 변환한 후
  • save 메서드를 호출
  • rest_framework 에서는 serializer를 정의하면 클라이언트가 전송한 매개변수를 가지고 모델 클래스로 자동 변환이 가능

 

apiapp 디렉토리에 serializers.py 파일을 만들고 클라이언트의 매개변수를 Book

from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        #클라이언트에서 입력할 데이터만 나열
        #아래 나열한 데이터를 입력하면 Book 클래스의 인스턴스를 자동 생성
        fields = ['bid', 'title', 'author', 'publisheddate']

 

데이터 삽입(POST) 처리와 전체 조회(GET)하는 처리를 views.py 파일에 작성

from rest_framework import status
from rest_framework.generics import get_object_or_404
from .models import Book
from .serializers import BookSerializer

@api_view(['GET', 'POST'])
def booksAPI(request):
    #GET 방식의 처리 - 조회를 요청하는 경우
    if request.method == 'GET':
        #테이블의 데이터를 전부 가져오기
        books = Book.objects.all()
        #출력하기 위해서 브라우저의 형식으로 데이터를 변환
        serializer = BookSerializer(books, many=True)
        #출력
        return Response(serializer.data)
        
    #POST 방식의 처리 - 삽입하는 경우
    elif request.method == 'POST':
        serializer = BookSerializer(data = request.data)
        serializer.save()
        return Response(serializer.data)

 

apiapp 디렉토리의 urls.py 파일에 url과 이전에 만든 함수를 연결

from django.urls import path
from .views import hello, booksAPI

urlpatterns = [
    path("hello/", hello),
    path("books/", booksAPI),
]

 

서버를 구동하고 브라우저에 127.0.0.1

 

데이터를 삽입할 때 에러가 발생

rest_framework를 사용할 때는 데이터를 save할 때 is_valid()를 호출해서 유효성 검사에 통과했을 때만 삽입되도록 해야 함. 

 

...
    elif request.method == 'POST':
    
        #클라이언트에서 전송된 데이터를 가지고 Model 인스턴스 생성
        serializer = BookSerializer(data = request.data)
        
        #유효성 검사를 수행해서 통과하면 삽입, 실패하면 이유 출력
        if serializer.is_vallid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors)

  • bid는 프라이머리 키기 떄문에, bid에 똑같은 정보를 입력하면

 

 

 

7) 데이터 1개 가져오기

데이터 1개를 가져오려면 클라이언트에서 기본키 값을 서버에 제공해야 하고 

서버는 이 값을 읽어서 하나의 데이터를 찾아 넘겨줘야 한다.

 

views.py 

@api_view(['GET'])
def oneBookAPI(request, bid):
    #Book 테이블에서 bid 컬럼의 값이 bid인 값을 찾아온다. 
    book = get_object_or_404(Book, bid=bid)
    #출력할 수 있도록 변환
    serializer = BookSerializer(book)
    return Response(serializer.data)

 

 

urls.py

from django.urls import path
from .views import hello, booksAPI, oneBookAPI

urlpatterns = [
    ...
    path("onebook/<int:bid>", oneBookAPI),
]

 

🔍 http://127.0.0.1/example/onebook/1

  • 만약 없는 데이터를 찾으면

 

 

 

 

복습!!

더보기

git url: https://github.com/ggangpae1/djangofirst 

 

1. 프로젝트 clone

2. 가상환경 들어가기

3. 패키지 설치

4. setting 변경

5. 수정한 데이터베이스 내용 변경

6. 서버 실행

7. 내 깃에 업로드

'Python' 카테고리의 다른 글

[Python] Pandas  (1) 2024.02.08
[Python] Numpy  (0) 2024.02.06
Day9. 웹 서버 만들기  (1) 2024.01.24
Day8. 가상환경 만들기  (1) 2024.01.19
Day7. 웹프로그래밍 개요  (1) 2024.01.18