0. 접속하기/요청 URL계정(Tip)헤더에 토큰넣기1. 계정1.1 구매자 계정 만들기(POST)1.2 계정 만들기(판매자,POST)1.3 아이디 검증하기1.4 사업자등록번호 검증하기2. 로그인/로그아웃2.1 로그인2.1.1 로그인 요청하기2.1.2 refresh token으로 새 access token 요청하기2.2 로그아웃3. 상품3.1 상품 전체 불러오기(GET)3.1.1) 상품 전체 불러오기(GET)3.1.2) 판매자 상품 불러오기(GET)3.2 상품 등록하기(POST)3.3 상품 디테일(GET)3.4 상품 수정하기(PUT)3.5 상품 삭제하기(DELETE)3.6 상품 제목 검색하기(GET)4. 장바구니4.1 장바구니 목록 보기(GET)4.2 장바구니에 물건 넣기(POST)4.3 장바구니 디테일(GET)4.4 장바구니 수량 수정하기(PUT)4.5 장바구니 개별 삭제하기(DELETE)4.6 장바구니 전부 삭제하기(DELETE)5. 주문하기5.1. 주문 생성하기(POST)5.1.1. direct_order로 주문 생성하기(POST)5.1.2. cart_order로 주문 생성하기(POST)5.2. 주문 목록 가져오기(GET)5.3. 개별 주문 가져오기(GET)5.4 주문 수정하기5.5 주문 삭제하기
0. 접속하기/요청 URL
계정
- 구매자(buyer)
- ID : buyer1 PW: weniv1234
- ID : buyer2 PW: weniv1234
- ID : buyer3 PW: weniv1234
- 판매자(seller)
- ID : seller1 PW : weniv1234
- ID : seller2 PW : weniv1234
- ID : seller3 PW : weniv1234
(Tip)헤더에 토큰넣기
// Authorization를 이용하며 Bearer를 접두사로 사용합니다. fetch('주소', { method: 'GET', headers: { 'Authorization': `Bearer ${jwt}`, 'Content-Type': 'application/json' } })
// 토큰이 없을 경우 발생하는 오류 { "detail": "자격 인증데이터(authentication credentials)가 제공되지 않았습니다." } // 토큰이 만료되었을 경우 발생하는 오류 { "detail": "Given token not valid for any token type", "code": "token_not_valid", "messages": [ { "token_class": "AccessToken", "token_type": "access", "message": "Token is invalid or expired" } ] }
1. 계정
1.1 구매자 계정 만들기(POST)
- API
POST /accounts/buyer/signup/
- Req
{ "username": String, // 아이디 "password": String, "name": String, // 이름 "phone_number": String, // 전화번호는 010으로 시작하는 10~11자리 숫자 }
- 모든 필드는 필수로 작성해야 합니다.
- 비밀번호는 8자 이상, 영소문자를 포함해야 합니다.
- 핸드폰 번호는 010으로 시작하는 10~11자리 숫자로만 이루어져 있습니다.
- 이름(name)은 중복될 수 있습니다.
- Res
// SUCCESS { "username": String, "name": String, "phone_number": String, "user_type": "BUYER", } // FAIL // username, password, name, phone_number 중 하나라도 작성하지 않을 경우 이 필드는 필수 항목입니다. // password를 8자 이상 입력하지 않을 경우 비밀번호는 8자 이상이어야 합니다. // password에 영소문자가 없을 경우 비밀번호는 한개 이상의 영소문자가 필수적으로 들어가야 합니다. // password에 숫자가 없을 경우 비밀번호는 한개 이상의 숫자가 필수적으로 들어가야 합니다. // 가입된 username일 경우 해당 사용자 아이디는 이미 존재합니다. // username에 지정된 문자 이외의 문자가 들어갈 경우 ID는 20자 이내의 영어 소문자, 대문자, 숫자만 가능합니다. // 가입된 phone_number일 경우 해당 사용자 전화번호는 이미 존재합니다. // 핸드폰번호가 양식에 맞지 않을 경우 핸드폰번호는 01*으로 시작해야 하는 10~11자리 숫자여야 합니다.
- LLM 프롬프트
`https://api.wenivops.co.kr/services/open-market/` 여기가 우리 회사가 지원하는 API 서버야. 구매자 계정 request는 아래와 같이 json으로 날리라고 하는데 코드를 어떻게 작성하면 될까? console에서 실습할 수 있게 fetch 코드로 작성해줘. URL : POST /accounts/buyer/signup/ req : ``` { "username": String, // 아이디 "password": String, "name": String, // 이름 "phone_number": String, // 전화번호는 010으로 시작하는 10~11자리 숫자 } ```
1.2 계정 만들기(판매자,POST)
- API
POST /accounts/seller/signup/
- Req
// SUCCESS { "username": String, // 아이디 "password": String, "name": String, // 이름 "phone_number": String, "company_registration_number": String, "store_name": String, }
- 모든 필드는 필수로 작성해야 합니다.
- 이름(name)은 중복될 수 있습니다.
- 비밀번호는 8자 이상, 영소문자를 포함해야 합니다.
- 핸드폰 번호는 010으로 시작하는 10~11자리 숫자로만 이루어져 있습니다.
- 사업자등록번호는 10자리로 이루어진 숫자입니다.
- 스토어이름(store_name)은 중복될 수 없습니다.
- Res
// SUCCESS { "username": String, "name": String, "phone_number": String, "user_type": "SELLER", "company_registration_number": String, "store_name": String, } // FAIL // username, password, name, phone_number 중 하나라도 작성하지 않을 경우 이 필드는 blank일 수 없습니다. // password를 8자 이상 입력하지 않을 경우 비밀번호는 8자 이상이어야 합니다. // password에 영소문자가 없을 경우 비밀번호는 한개 이상의 영소문자가 필수적으로 들어가야 합니다. // password에 숫자가 없을 경우 비밀번호는 한개 이상의 숫자가 필수적으로 들어가야 합니다. // 가입된 username일 경우 해당 사용자 아이디는 이미 존재합니다. // username에 지정된 문자 이외의 문자가 들어갈 경우 ID는 20자 이내의 영어 소문자, 대문자, 숫자만 가능합니다. // 가입된 phone_number일 경우 해당 사용자 전화번호는 이미 존재합니다. // 핸드폰번호가 양식에 맞지 않을 경우 핸드폰번호는 01*으로 시작해야 하는 10~11자리 숫자여야 합니다. // 사업자등록번호가 이미 있을 경우 해당 사업자등록번호는 이미 존재합니다. // 스토어 이름이 이미 있을 경우 해당 스토어이름은 이미 존재합니다.
1.3 아이디 검증하기
- API
POST /accounts/validate-username/
- Req
{ "username": String }
- Res
// username 필드를 입력하지 않았거나 비어있을 경우 "error": "username 필드를 추가해주세요." // 중복아이디가 있을 경우 "error": "이미 사용 중인 아이디입니다." // 사용 가능한 아이디 일 경우 "message": "사용 가능한 아이디입니다."
1.4 사업자등록번호 검증하기
- API
POST /accounts/seller/validate-registration-number/
- Req
{ "company_registration_number": String }
- Res
// 필드를 입력하지 않았거나 비어있을 경우 "error": "company_registration_number 필드를 추가해주세요." // 10자리 숫자로 입력하지 않았을 경우 "error": "사업자등록번호는 10자리 숫자여야 합니다." // 사업자 등록번호가 이미 등록되었을 경우 "error": "이미 등록된 사업자등록번호입니다." // 사용 가능할 경우 "message": "사용 가능한 사업자등록번호입니다."
2. 로그인/로그아웃
2.1 로그인
2.1.1 로그인 요청하기
- API
POST /accounts/login/
- Req
{ "username": String, "password": String }
- Res
// SUCCESS { "access": token, "refresh": token, "user": { "username": string, "name": string, "phone_number": string, "user_type": "BUYER" | "SELLER" } } // 아이디 비밀번호가 없거나 유효하지 않을 경우 { "error": "아이디 또는 비밀번호가 올바르지 않습니다." }
- 인증은 JWT를 사용합니다.
- 토큰 수명
- access: 5분
- refresh: 1일
2.1.2 refresh token으로 새 access token 요청하기
- API
POST /accounts/token/refresh/
- Req
{ "refresh": 로그인 시 받아온 refresh 토큰 }
- Res
{ "access": token }
2.2 로그아웃
- JWT는 stateless하기 때문에 서버에 로그아웃을 요청할 수 없습니다.
- 클라이언트 측에서 토큰을 삭제하거나 애플리케이션 상태를 초기화하는 등의 구현해주셔야 합니다.
3. 상품
3.1 상품 전체 불러오기(GET)
3.1.1) 상품 전체 불러오기(GET)
- API
GET /products/
- Res
// SUCCESS { "count": Int, "next": URL, "previous": URL, "results": [ { "id": Int, "name": String, "info": String, "image": URL, "price": Int, "shipping_method": "PARCEL" | "DELIVERY" "shipping_fee": Int, "stock": Int, "seller": { "username": String, "name": String, "phone_number": String, "user_type": "SELLER", "company_registration_number": String, "store_name": String }, "created_at": Time, "updated_at": Time }] } // product가 없을 경우 { "count": 0, "next": null, "previous": null, "results": [] }
shipping_method
- PARCEL : 택배, 소포, 등기
- DELIVERY: 직접배송(화물배달)
3.1.2) 판매자 상품 불러오기(GET)
- API
GET /<str:seller_name>/products/
seller_name
은 판매자의 name
을 가져와야 합니다.- Res
// SUCCESS { "count": Int, "next": URL, "previous": URL, "results": [ { "id": Int, "name": String, "info": String, "image": URL, "price": Int, "shipping_method": "PARCEL" | "DELIVERY" "shipping_fee": Int, "stock": Int, "seller": { "username": String, "name": String, "phone_number": String, "user_type": "SELLER", "company_registration_number": String, "store_name": String }, "created_at": Time, "updated_at": Time }] } // product가 없을 경우 { "count": 0, "next": null, "previous": null, "results": [] } // 일치하는 seller가 없을 경우 "detail": "No User matches the given query." // 해당 user가 seller가 아닐 경우 "detail": "이 사용자는 판매자가 아닙니다."
3.2 상품 등록하기(POST)
seller
만 요청을 보낼 수 있습니다.- API
POST /products/
- Req
{ "name": String, "info": String, "image": 이미지 파일(*.jpg, *.gif, *.png), "price": Int, "shipping_method": "PARCEL"|"DELIVERY" "shipping_fee": Int, "stock": Int, }
shipping method
- PARCEL : 택배,소포,등기
- DELIVERY: 직접배송(화물배달)
- Res
// SUCCESS { "id": Int, "name": String, "info": String, "image": URL, "price": Int, "shipping_method": "PARCEL" | "DELIVERY" "shipping_fee": Int, "stock": Int, "seller": { "username": String, "name": String, "phone_number": String, "user_type": "SELLER", "company_registration_number": String, "store_name": String }, "created_at": Time, "updated_at": Time } // buyer가 요청할 경우 "detail": "이 작업을 수행할 권한(permission)이 없습니다." // 필드가 비었을 경우 (400 Bad Request) "name": ["이 필드는 필수 항목입니다."], "info": ["이 필드는 필수 항목입니다."], "image": ["파일이 제출되지 않았습니다."], "price": ["이 필드는 필수 항목입니다."], "shipping_method": ["이 필드는 필수 항목입니다."], "shipping_fee": ["이 필드는 필수 항목입니다."], "stock": ["이 필드는 필수 항목입니다."] // shipping_fee, stock, price가 정수가 아닐 경우 (400 Bad Request) "유효한 정수(integer)를 넣어주세요."
3.3 상품 디테일(GET)
- API
GET /products/<int:product_id>/
- Res
// SUCCESS { "id": Int, "name": String, "info": String, "image": URL, "price": Int, "shipping_method": "PARCEL" | "DELIVERY" "shipping_fee": Int, "stock": Int, "seller": { "username": String, "name": String, "phone_number": String, "user_type": "SELLER", "company_registration_number": String, "store_name": String }, "created_at": Time, "updated_at": Time } // FAIL { "detail": "No Product matches the given query." }
3.4 상품 수정하기(PUT)
- API
PUT /products/<int:product_id>/
- Req
- 수정이 필요한 값들만 넣어주면 됩니다. 값을 넣지 않을경우 이전에 저장된 값들이 그대로 저장됩니다.
- id, seller, created_at, updated_at은 수정할 수 없습니다.
3.5 상품 삭제하기(DELETE)
- API
DELETE /products/<int:product_id>/
- Res
// SUCCESS "detail": "상품이 삭제되었습니다." // FAIL // 내 상품이 아닐 경우 "detail": "이 작업을 수행할 권한(permission)이 없습니다." // 없는 상품일 경우 "detail": "찾을 수 없습니다."
3.6 상품 제목 검색하기(GET)
- API
GET /products/?search=입력값
입력값 필드에 원하는 값을 넣으면 됩니다.
4. 장바구니
- 장바구니는
user_type
이BUYER
일 경우만 접근이 가능합니다.
4.1 장바구니 목록 보기(GET)
- API
GET /cart/
- Res
// SUCCESS { "count": Int, "next": URL, "previous": URL, "results": [ { "id": Int, "product": Product, "quantity": Int, "added_at": Time } ] } // 장바구니에 상품이 없을 경우 { "count": 0, "next": null, "previous": null, "results": [] }
4.2 장바구니에 물건 넣기(POST)
- API
POST /cart/
- Req
{ "product_id": Int, //product의 id 값을 넣어주면 됩니다. "quantity": Int }
- Res
{ "detail": "장바구니에 상품이 담겼습니다." }
- 장바구니에 이미 있는 경우에도 POST 요청으로 보내줍니다.
- 장바구니에 이미 있을 경우는 수량만큼 더하기가 됩니다.
4.3 장바구니 디테일(GET)
- API
GET /cart/<int:cart_item_id>/
- Res
// SUCCESS { "id": Int, "product": Product, "quantity": Int, "added_at": Time } // FAIL // buyer가 아니거나 token이 없을 경우 "detail": "자격 인증데이터(authentication credentials)가 제공되지 않았습니다." // user가 다를 경우 "detail": "접근권한이 없습니다." // 해당 pk값이 없을 경우 "detail": "찾을 수 없습니다." "detail": "No CartItem matches the given query."
4.4 장바구니 수량 수정하기(PUT)
- API
PUT /cart/<int:cart_item_id>/
- Req
{ "quantity": Int, }
- Res
{ "id": Int, "product": Product, "quantity": Int, "created_at": Time, "updated_at": Time }
4.5 장바구니 개별 삭제하기(DELETE)
- API
DELETE /cart/<int:cart_item_id>/
- Res
{ "detail": "장바구니에 담긴 상품이 삭제되었습니다." }
4.6 장바구니 전부 삭제하기(DELETE)
- API
DELETE /cart/
- Res
// SUCCESS { "detail": "장바구니에 담긴 {수량}개의 상품이 삭제되었습니다." }
5. 주문하기
주문하기는 두가지 방법으로 나뉩니다.
direct_order
바로 주문하기: 상품 상세페이지에서 주문하는 경우
cart_order
카트에서 주문하기: 장바구니에 담긴 제품 주문
이 세가지 분기를 처리해주기 위해서
order_type
을 서버에 보내주셔야 합니다.direct_order
cart_order
5.1. 주문 생성하기(POST)
5.1.1. direct_order로 주문 생성하기(POST)
- API
POST /order/
- Req
{ "order_kind" : "direct_order", "product": Int, "quantity" : Int, "total_price": Int "reciever": String, "reciever_phone_number": String, "address": String, "address_message": String | null, "payment_method": "card"|"deposit"|"phone"|"naverpay"|"kakaopay", }
payment_method
- card : 신용/체크카드
- deposit : 무통장 입금
- phone : 휴대폰 결제
- naverpay : 네이버페이
- kakaopay : 카카오페이
- Res
// SUCCESS { "id": Int, "order_number": String, "payment_method": "card"|"deposit"|"phone"|"naverpay"|"kakaopay", "order_status": "payment_pending"|"payment_complete"|"preparing"|"shipping"|"delivered"|"cancled", "order_type": "direct_order" "total_price": Int, "created_at": Time, "order_items": [ { "product": Product, "ordered_quantity": Int, // 주문 수량 "ordered_unit_price": Int, // 주문 당시 가격 "ordered_shipping_fee": Int, // 주문 당시 배송비 "item_total_price": Int // 해당 product의 가격*수량+배송비 } ] "receiver": String, "receiver_phone_number": String, "address": String, "delivery_message": String | null, "created_at": Time } // FAIL // 필수 필드가 입력되지 않았을 때 "receiver": ["이 필드는 필수 항목입니다."] "receiver_phone_number": ["이 필드는 필수 항목입니다."] "address": ["이 필드는 필수 항목입니다."] "payment_method": ["이 필드는 필수 항목입니다."] "order_type": ["이 필드는 필수 항목입니다."] // payment_method가 유효한 선택이 아닐 때 "payment_method": [ "\"___\"이 유효하지 않은 선택(choice)입니다." ] // 총 금액이 계산한 것과 다를 때 "non_field_errors": "total_price가 맞지 않습니다. 계산 금액은 ___원입니다.(배송비 포함)"
delivery_status
- payment_pending : 결제 대기 중(결제 생성 시 오류가 발생했을 경우)
- payment_complete : 결제 완료
- preparing : 상품 준비 중
- shipping : 배송 중
- delivered : 배송 완료
- cancelled : 주문취소
- 총 금액 계산 방법
(product가격 * 주문수량) + product배송비
- 배송비는 한번만 부과됩니다.
5.1.2. cart_order로 주문 생성하기(POST)
- API
POST /order/
- Req
{ "order_type":"cart_order", "cart_items": List, // cartitem에 담긴 product의 id를 리스트 형태로 보내야합니다. "total_price": Int "reciever": String, "reciever_phone_number": String, "address": String, "address_message": String | null, "payment_method": "card"|"deposit"|"phone"|"naverpay"|"kakaopay", }
cart_order는 장바구니에 담긴 수량을 그대로 사용하기 때문에 quantity를 보내지 않습니다.
- Res
// SUCCESS { "id": Int, "order_number": String, "payment_method": "card"|"deposit"|"phone"|"naverpay"|"kakaopay", "order_status": "payment_pending"|"payment_complete"|"preparing"|"shipping"|"delivered"|"cancled", "order_type": "cart_order" "total_price": Int, "order_items": [ { "product": Product, "ordered_quantity": Int, // 주문 수량 "ordered_unit_price": Int, // 주문 당시 가격 "ordered_shipping_fee": Int, // 주문 당시 배송비 "item_total_price": Int // 해당 product의 가격*수량+배송비 }, { "product": Product, "ordered_quantity": Int, // 주문 수량 "ordered_unit_price": Int, // 주문 당시 가격 "ordered_shipping_fee": Int, // 주문 당시 배송비 "item_total_price": Int // 해당 product의 가격*수량+배송비 }, ... ] "receiver": String, "receiver_phone_number": String, "address": String, "delivery_message": String | null, "created_at": Time } // FAIL // 필수 필드가 입력되지 않았을 때 "이 필드는 필수 항목입니다." // 총 금액이 계산한 것과 다를 때 "non_field_errors": "total_price가 맞지 않습니다. 계산 금액은 ___원입니다.(배송비 포함)" // 카트에 담기지 않은 상품을 주문할 경우 "non_field_errors": ["다음 카트 아이템이 유효하지 않습니다: 상품명(pk)"] // 존재하지 않는 상품을 주문할 경우 "유효하지 않은 pk \"{pk}\" - 객체가 존재하지 않습니다." // 재고가 부족하여 주문할 수 없을 경우 "non_field_errors": ["<상품명(pk)>의 재고가 부족하여 주문할 수 없습니다."]
5.2. 주문 목록 가져오기(GET)
구매자만 요청할 수 있습니다.
- API
GET /order/
- Res
// SUCCESS { "count": Int, "next": URL, "previous": URL, "results": [ { "id": Int, "order_number": String, "payment_method": "card"|"deposit"|"phone"|"naverpay"|"kakaopay", "order_status": "payment_pending"|"payment_complete"|"preparing"|"shipping"|"delivered"|"cancled", "order_type": "direct_order"|"cart_order" "total_price": Int, "order_items": [ { "product": Product, "ordered_quantity": Int, // 주문 수량 "ordered_unit_price": Int, // 주문 당시 가격 "ordered_shipping_fee": Int, // 주문 당시 배송비 "item_total_price": Int // 해당 product의 가격*수량+배송비 }, { "product": Product, "ordered_quantity": Int, // 주문 수량 "ordered_unit_price": Int, // 주문 당시 가격 "ordered_shipping_fee": Int, // 주문 당시 배송비 "item_total_price": Int // 해당 product의 가격*수량+배송비 }, ... ] "receiver": String, "receiver_phone_number": String, "address": String, "delivery_message": String | null, "created_at": Time },... ] } // 값이 없을 때 { "count": 0, "next": null, "previous": null, "results": [] }
5.3. 개별 주문 가져오기(GET)
구매자만 요청할 수 있습니다.
- API
GET /order/<int:order_pk>/
- Res
// SUCCESS { "id": Int, "order_number": String, "payment_method": "card"|"deposit"|"phone"|"naverpay"|"kakaopay", "order_status": "payment_pending"|"payment_complete"|"preparing"|"shipping"|"delivered"|"cancled", "order_type": "direct_order" "total_price": Int, "order_items": [ { "product": Product, "ordered_quantity": Int, // 주문 수량 "ordered_unit_price": Int, // 주문 당시 가격 "ordered_shipping_fee": Int, // 주문 당시 배송비 "item_total_price": Int // 해당 product의 가격*수량+배송비 }, { "product": Product, "ordered_quantity": Int, // 주문 수량 "ordered_unit_price": Int, // 주문 당시 가격 "ordered_shipping_fee": Int, // 주문 당시 배송비 "item_total_price": Int // 해당 product의 가격*수량+배송비 }, ... ] "receiver": String, "receiver_phone_number": String, "address": String, "delivery_message": String | null, "created_at": Time } // 다른 유저의 order나 값이 없을 때 "detail": "No Order matches the given query."
5.4 주문 수정하기
- 실제 서비스들을 보면 주문은 생성 즉시 seller와 계약되는 형태라 buyer가 주문을 수정할 수 없습니다.
5.5 주문 삭제하기
주문 삭제 시 실제 객체가 삭제되는 것이 아니라
order_status
가 cancelled로 변경됩니다.- API
DELETE /order/<int:order_pk>/
- Res
// SUCESS "detail": "주문이 성공적으로 취소되었습니다." // FAIL // 해당 주문이 내 주문이 아니거나 없을 경우 "detail": "No Order matches the given query."