[DJANGO]HTTP request & response

miracle-21·2022년 6월 9일
0

DJANGO

목록 보기
5/22
post-thumbnail

✅ Http client?

  Http client(Httpie, Chrome, Postman 등)를 사용해서 직접 client의 입장이 되어보자. 여기서 사용할 Httpie는 백엔드가 프론트의 입장이 되어서 직접 만든 API를 직접 호출해볼 수 있게 해주는 프로그램이다.

  • Server에 요청
  • Django Application 을 통해 요청을 분석(URLconf)
  • 요청을 처리하기 위한 로직(View) 실행시켜 데이터베이스와 통신(Model)
  • 데이터 작업을 수행하고 요청에 맞는 응답을 보낼 수 있는 Backend API를 구현

✅ Client 준비

1. Server에 HTTP request 를 할 수 있는 Httpie 설치

#Ubuntu
sudo apt install httpie

#Mac
brew install httpie

  httpie 는 string type 을 기본으로 전송한다. 자세한 httpie 사용법은 여기를 참고하자.

2. Body에 담아서 보내고 싶은 data

{
    "menu" : "음료",
    "category" : "콜드브루",
    "product" : "맛있는 콜드브루"
}

3. Http 요청 보내기

http -v POST 127.0.0.1:8000/product menu='음료' category='콜드브루' 
product='맛있는 콜드브루'

✅ Model 작성

  앞서 application을 생성하고 디렉토리 안에 models.py 파일이 생성된 것을 보았을 것이다. 그 models 파일을 작성해보자.

  아래 코드 예시는 이전 포스팅에서 만든 westarbucks 프로젝트를 사용한다.

#products/models.py 
from django.db import models

class Menu(models.Model):
    name = models.CharField(max_length=20)

    class Meta:
        db_table = 'menus'

class Category(models.Model):
    name = models.CharField(max_length=20)
    menu = models.ForeignKey('Menu', on_delete=models.CASCADE)

    class Meta:
        db_table = 'categories'

class Product(models.Model):
    name     = models.CharField(max_length=100)
    category = models.ForeignKey('Category', on_delete=models.CASCADE)

    class Meta:
        db_table = 'products'

✅ View 작성

1. Create

  자원(resource)을 생성할 때 Http method 중에 Post를 사용한다. 로그인, 회원가입 등 정보를 요청 할 때도 POST로 요청한다.

#products/views.py
import json    #프론트로부터 받은 json을 백에서 사용할 수 있는 형태로 바꿔준다.

from django.http import JsonResponse    #django가 dict를 json으로 변환한다.
from django.views import View    #view기능을 사용할 수 있게 한다.

from products.models import Menu, Category, Product

class ProductsView(View):    #1번 참조
    def post(self, request): #2번 참조
        data = json.loads(request.body)    #3번 참조 
        menu_name = data['menu']
        category_name = data['category']
        product_name = data['product']
        
        menu     = Menu.objects.create(name=menu_name)    #4번 참조
        category = Category.objects.create(
        name	 = category_name, 
        menu	 = menu
        )
        Product.objects.create(
            name     = product_name,    #프론트에서 받은 'category'키의 value값.
            category = category
        )

    return JsonResponse({'message':'created'}, status=201)
  1. class ProductsView(View)
    • class 하나가 내가 다룰 resource(자원)라고 생각하면 된다.
    • API주소를 설계할 때는 주소 안에 필요한 자원만 넣는다.
    • class 이름을 지을 때에는 어떤 자원에 대한 행위를 할 건지 생각하고 class 이름을 짓는다.
    • class 안의 함수이름(메서드이름)은 http 메서드 이름과 일치해야한다.
  1. def post(self, request)
    • request는 프론트가 주는 request 정보가 들어있다. 이 객체를 인자로 받는다.
  1. data = json.loads(request.body)
    • request 안에있는 body라는 속성에 프론트가 보낸 body정보가 들어있다.
    • 프론트에서 온 json 형태의 body를 파이썬에 맞게 변환해서 변수 data에 담는다.
  1. menu = Menu.objects.create(name=menu_name)
    • menu_name, 즉 data['menu']는 프론트가 준 menu key. key의 이름은 프론트와 백 모두 일치해야한다.

  View 를 작성 한 후에는 클라이언트의 요청을 받아 적절한 view 를 맵핑해주는 urls.py 를 작성해야한다. 앱 디렉토리에 파일을 생성하자.

touch urls.py
vi urls.py 
# products/urls.py
from django.urls import path

from products.views import ProductsView

urlpatterns = [
    path('', ProductsView.as_view()),
]

  처음 클라이언트로 부터 요청을 받기 위해서는 manage.py가 위치하는 main urls.py(메인_폴더명/urls.py) 와 연결해줘야 한다.

# westarbucks/urls.py
from django.urls import path, include

urlpatterns = [
    path('products', include('products.urls')),
]

  이제 httpie(client)로 django server에 요청을 보내보자.

http -v POST 127.0.0.1:8000/product menu='음료' category='콜드브루' product='맛있는 콜드브루'

2. Read

  자원(resource)를 읽어 올 때 http method 중에 GET method를 사용한다. 이 때 url만 사용한다.

#products/views.py
import json

from django.http import JsonResponse
from django.views import View

from products.models import Menu, Category, Product

class ProductsView(View):
	...
    def get(self, request):
        products = Product.objects.all() #Product table과 대응되고 있는 모든 데이터를 QuerySet 형태로 가져온다.
        results  = [] #append용 빈 list

       for product in products: #프론트가 필요한 데이터를 만들어 준다.
           results.append(
               {
	           		#키값 "menu"는 프론트와 이름이 동일해야한다.
                    #이 값이 변한다고 migration을 할 필요는 없다.
                   "menu" : product.category.menu.name, 
                   "category" : product.category.name,
                   "product_name" : product.name
               }
           )
       
        return JsonResponse({'resutls':results}, status=200)
  • products = Product.objects.all() : Product table과 대응되고 있는 모든 데이터를 QuerySet 형태로 가져온다.
  • for product in products: : 프론트가 필요한 데이터를 만들어 준다.
    • product.category.menu.name
      • product : Product class 로 만들어진 객체들이 들어있다.
      • category : Product class 안의 category 속성을 보면 Category class를 가리킨다.
      • menu : Category class 안의 menu 속성을 보면 Menu class를 가리킨다.
      • name : Menu class 안의 name 속성을 가져온다.

✅ URLconf 작성

1. main urls.py

  새로운 View 를 작성 한 후에는 클라이언트의 요청을 받아 적절한 view 를 맵핑해주는 urls.py 를 작성해야 한다(만약 동일한 view class 를 사용하고 http method 만 다르다면 동일한 url을 사용하면 된다).

  main urls.pysettings.py와 같은 경로에 있는 부모 urls.py다. 여기서 작성하는 urls.py는 바로 View로 연결하지 않고 자식 urls.py 파일이 있는 앱까지만 연결시켜준다. 즉, 어느 앱으로 연결해야 하는지만 알려준다.

from django.urls import path, include

urlpatterns = [
	#어디로 보내야 하는지 주소를 작성하면 된다
    path('products', include('products.urls'))
]

  이 경우에 유효한 경로는 127.0.0.1:8000/products가 된다. 여기서 127.0.0.1은 자신의 컴퓨터 경로를 가리킨다. 지금은 실습만 하는 단계이므로 경로 문제는 생각하지 말자.

2. urls.py

  그 다음에는 처음 클라이언트로 부터 요청을 받기 위한 main urls.py와 연결해줘야 한다(위의 설명과 동일하게 이미 연결이 되어 있고, method 만 다르다면 동일한 url 을 사용하면 된다).

  Client 에서 요청이 들어오면 처음에 main에 있는 urls.py의 경로를 탐색하고, 이와 일치하면 app에 있는 urls.py의 경로를 탐색한다.

from django.urls import path

from products.views import ProductsView

urlpatterns = [
    path('', ProductsView.as_view())
]

이 경우에 유효한 경로는 127.0.0.1:8000/products가 된다. 만약 아래의 코드같이 작성한다면 어떻게 될까?

...
urlpatterns = [
    path('/detail', ProductsView.as_view())
]

 이 경우에는 127.0.0.1:8000/products/detail가 된다.

✅ httpie를 이용한 POST/GET

먼저 서버에 접속하는 것을 잊지 말자!

$ python manage.py runserver

POST

http -v POST 127.0.0.1:8000/product menu='음료' category='콜드브루' product='맛있는 콜드브루'

GET

http -v GET 127.0.0.1:8000/products

profile
backend developer 🐌

0개의 댓글