카테고리 없음

API 문서

건우정 2024. 9. 23. 10:04

스프링부트에 json 데이터만을 요청하는 경우에는 /api/*로 시작하는게 리액트 페이지이동과 구분이 쉽다.
ex) /api/users/5

위의 규칙을 만드는 사람이 마음대로 정하기 나름이지만
혼자 개발할게 아니기 때문에 REST API 설계 원칙을 따르는 것이 좋을 것이다.

리액트에서 라우팅하는 URL은 rest API 설계 원칙을 그대로 따르긴 어렵다.
적당히 알아서 네이밍해야한다.

Rest API 설계시 네이밍과 기본규칙

Rest API 설계시 네이밍과 기본규칙

RestfulAPI 네이밍과 기본규칙 Restful API설계를 위한 네이밍규칙 Restful API는 URI를 통해 리소스를 식별합니다. 통합 자원 식별자(Uniform Resource Identifier, URI)는 인터넷에 있는 자원을 나타내는 유일한

choiblog.tistory.com


간단히 요약하면

1. URL,URI 경로에는 동사를 쓰지말고 HTTP Method를 통해서 구분하자.
 

 
2. 리소스가 여러개이면 복수형을 쓰자
/user/1 이 아니라 /users/1
 
3. 자원을 계층형으로 나타내자
/api/qnas/{qnaId}/answers/{answerId}
qnaId로 qna를 특정하고 , 그 하위에 answerId로 answer을 특정한다.


Path variable(경로 변수)와 Query String(쿼리스트링) 쓰임새 차이
둘다 리소스를 식별하기 위해서 쓰지만,
경로 변수는 주로 특정 자원을 유일하게 식별 가능할 때 쓰인다. (유저 id(로그인할 때 id가 아니라 PK값), 글번호 등)
=> /users/123 
 
쿼리스트링은 주로 여러 개 중에 일부를 가져올 때 쓴다 필터링, 정렬 등
=> /users?gender=women


회원 가입 HTML 페이지(수민)

  • URL : /join
  • Method : GET
  • Description : 회원 가입 HTML 페이지를 로드합니다.
  • Request Body :
  • 회원 가입 HTML 콘텐츠
  •  
  • Response Code :
  • -
  • Response Body :
  • -

로그인 HTML 페이지(민선)

  • URL : /login
  • Method : GET
  • Description : 로그인 HTML 페이지를 로드합니다.
  • Request Body :
  • 로그인 HTML 페이지
  •  
  • Response Code : -
  • Response Body : -

로그인 요청 (login) (민선)

  • URL : /api/auth/login
  • Method : POST
  • Description : 로그인 요청을 합니다. 성공 시 세션에 로그인이 유지됩니다.
  • 아이디 혹은 비밀번호가 모두 일치하지 않으면 로그인을 거절합니다.
  • Request Body :
  • {
  • "user_id" : "입력한 아이디값 ",
  • "password" : "입력한 비밀번호 값"
  • }
  • Response Code :
  • 200 OK : 로그인 성공
  • 401 Unauthorized : 로그인 실패
  • Response Body : 


아이디 중복 체크 (idCheck) (수민)

  • URL : /api/users/idcheck
  • Method : POST(보안상 URL에 id 노출하지않으려고)
  • Description : 아이디 중복 체크를 합니다.
  • Request Body :
  • {
  • "user_id" : “아이디”
  • }
  • Response Code :
  • 200 OK : 아이디가 사용 가능합니다.
  • 409 Conflict : 중복된 아이디입니다.
  • Response Body : - 

회원가입 요청 (join) (수민)

  • URL :  /api/users/join
  • Method : POST
  • Description : 입력한 회원 정보를 바탕으로 회원 가입을 요청합니다.
  • Request Body :
  • {
  • "name" : "John Doe",
  • "user_id" : "johndoe123",
  • "email": "john.doe@example.com",
  • "phone_number": "010-1234-5678",
  • "password": "password123",
  • "role": "USER"
  • Response Code :
  • 201 CREATED : 회원 가입에 성공
  • 400 Bad Request : 회원 가입에 실패
  • 409 Conflict : 중복된 아이디입니다.
  • Response Body : -

 

마이페이지 HTML (mypage) (수민)

  • URL :  /mypage
  • Method : GET
  • Description : 마이페이지 HTML 페이지를 로드합니다. 로그인이 안되어있으면 로그인 페이지로 리다이렉트합니다.
  • Request Body :-
  • Response Code : - 
  • Response Body : -
  • 마이페이지 HTML 콘텐츠

회원 탈퇴 (delete) (민선)

  • URL :  /api/users/{id}
  • Method : DELETE
  • Description : 회원탈퇴 합니다.
  • Request Body :
  • {
  • "user_id" : "입력한 아이디값 ",
  • "password" : "입력한 비밀번호 값"
  • }
  • Response Code :
  • 200 OK : 회원 탈퇴에 성공
  • 400 Bad Request : 회원 탈퇴에 실패
  • 401 Unauthorized : 비로그인입니다. 혹은 아이디 비밀 번호가 일치하지않습니다.
  • Response Body : -

회원 정보 불러오기(MyPage) (민선)

  • URL :  /api/users/{id}
  • Method : GET
  • Description : 로그인한 회원의 정보를 불러옵니다. 비밀번호는 불러오지 않습니다.
  • Request Body :
  • -
  • Response Code :
  • 200 OK : 회원 정보 조회에 성공
  • 401 Unauthorized : 비로그인입니다. 회원 정보 조회 권한이 없습니다.
  • 404 Not Found : 사용자를 찾을 수 없습니다.
  • Response Body : 
  • {
  • "name" : "John Doe",
  • "user_id" "johndoe123",
  • "email": "john.doe@example.com",
  • "phone_number": "010-1234-5678",
  • "role": "USER"

회원 정보 수정(update) (수민)

  • URL :  /api/users/{id}
  • Method : PUT
  • Description : 로그인한 회원의 정보를 수정합니다. 로그인이 안되어있으면 요청을 거절합니다.
  • Request Body :
  • {
  • "name" : "John Doe",
  • "user_id" "johndoe123",
  • "email": "john.doe@example.com",
  • "phone_number": "010-1234-5678",
  • "password": "password123",
  • "role": "USER"
  • Response Code :
  • 200 OK : 회원 변경에 성공
  • 400 Bad Request : 회원 정보 수정에 실패하였습니다. 
  • 401 Unauthorized : 비로그인 혹은 비밀 번호가 일치하지 않습니다. 회원 정보 수정 권한이 없습니다.
  • Response Body : -

 

index페이지에서 로그인 여부 (isLogin) (수민)

  • URL :  /api/users/isLogin
  • Method : GET
  • Description : 로그인 여부를 반환합니다.
  • Request Body :
  • -
  • Response Code :
  • 200 OK : 로그인 된 상태입니다.
  • 401 Unauthorized : 비로그인입니다.
  • Response Body : -

 

로그 아웃 요청 (logout) (민선)

  • URL :  /api/users/logout
  • Method : DELETE
  • Description : 로그 아웃 합니다.
  • Request Body :
  • -
  • Response Code :
  • 200 OK : 로그아웃되었습니다.
  • Response Body : -

QnA 게시판 HTML (mypage) (수민)

  • URL :  /qnas
  • Method : GET
  • Description : qna HTML 페이지를 로드합니다. 
  • Request Body :-
  • Response Code : - 
  • Response Body : -
  • qna 게시판 HTML 콘텐츠

 
Q&A 작성 페이지 HTML 불러오기 
 

  • URL : /qnas/write
  • Method : GET
  • Description : Q&A 작성 페이지를 요청합니다. 세션에 로그인된 사용자만 페이지 접근이 가능합니다.
  • Request Body :-
  • Response Code : 비로그인시 - 로그인 페이지로 리다이렉션
  • Response Body : -
  • Q&A 작성페이지 HTML 콘텐츠

Q&A 작성 요청

      • URL : /api/qnas
      • Method : POST
      • Description : Q&A를 작성합니다. 세션에 로그인된 사용자만 Q&A 작성이 가능합니다.
        세션에 로그인 된 사용자의 아이디도 함께 DB에 저장됩니다.
      • Request Body : 
        {     
         "title": " Q&A 제목",         
        "content": "Q&A 내용"  
        }
      • Response Code :
        Q&A 작성 성공 시 : 201 Created    
        Q&A 작성 실패 시 : 400 Bad Request 
        비로그인 - 401 Unauthorized
      • Response Body : -

Q&A 상세 페이지 HTML 불러오기 

  • URL : /qnas/{id}
  • Method : GET
  • Description : Q&A의 상세 페이지 HTML 페이지를 보여줍니다. 게시글 데이터는 아직 요청하기 전입니다.
  • Request Body : - 없음(**GET 요청**)
  • Response Code : 
  • Response Body : -
  • 해당 페이지 HTML 콘텐츠

 

Q&A 상세 페이지 데이터 불러오기 

  • URL :  /api/qnas/{id}
  • Method : GET
  • Description : Q&A의 데이터를 불러옵니다. 해당 회원이 쓴 게시글인지 여부를 가져옵니다.
  • 추가로 관리자이지 확인을 통해 댓글을 달 수 있는 영역이 보이게 할 것입니다.
  • Request Body : - 없음(**GET 요청**)
  • Response Code :
  • 200 OK : 정상 조회
  • 404 Not Found : 해당 게시물이 존재하지 않습니다.
  • Response Body : -
  •  {
  •   "isWriter": true, (or false)
  •   "isAdmin": true, (or false)
  •   "qna_id": "1",
  •   "title ": "첫 번째 Q&A",
  •   "content ": "첫 번째 Q&A 내용 ",
  •   "name": "건우",
  •   "created_date ": "2024-09-25 10:00:00",
  •   "is_viewed ": "1"
  • }

 

QnA 게시판 목록 데이터 불러오기

  • URL : /api/qnas
  • Method : GET
  • Description : 서버에 QnA 게시판 목록을 요청합니다. 글번호 내림차순으로 모든 글 목록을 불러옵니다.
  • Request Body : -
  • Response Code : 
  • 200 OK 조회 성공 Q&A가 1개 이상 존재합니다.
  • 204 No Content: 조회에 성공하였지만, 등록된 Q&A 목록이 없습니다.
  • Response Body : 
  •  [
  •     {
  •         "qna_id": 3,
  •         "title ": "세 번째 Q&A",
  •         "content ": "세 번째 Q&A 내용 ",
  •         "name": "sumin",
  •         "created_date ": "2024-09-25 10:00:00",
  •         "is_viewed ": "0"
  •     },
  •     {
  •         "qna_id": 2,
  •         "title ": "두 번째 Q&A",
  •         "content ": "두 번째 Q&A 내용 ",
  •         "name": "sumin",
  •         "created_date ": "2024-09-25 10:00:00",
  •         "is_viewed ": "1"
  •     },
  •     {
  •         "qna_id": 1,
  •         "title ": "첫 번째 Q&A",
  •         "content ": "첫 번째 Q&A 내용 ",
  •         "name": "sumin",
  •         "created_date ": "2024-09-25 10:00:00",
  •         "is_viewed ": "1"
  •     },
  • ]

 

Q&A 수정 페이지 HTML 불러오기 (건우)

  • URL : /qnas/{id}/update
  • Method : GET
  • Description : Q&A의 수정 페이지 HTML을 불러옵니다. QnA 데이터는 아직 요청하기 전입니다.
  • Request Body : - 없음(**GET 요청**)
  • Response Code : -
  • Response Body : -

Q&A 수정하기 

  • URL : /api/qnas/{id}
  • Method : PUT
  • Description : Q&A의 데이터를 수정합니다. 해당 글은 작성한 회원이 아니면 수정 요청을 거절합니다.
  • Request Body : 
  •  {      
  • "title": " Q&A 제목",
  • "content": "Q&A 내용"
  • }
  • Response Code : 
  • 200 OK : 정상 수정
  • 400 Bad Request : 수정 실패
  • 403 Forbidden : 수정 권한이 없습니다.
  • 404 Not Found : 해당 게시물이 존재하지 않습니다.
  • Response Body : -

Q&A 삭제 (listDelete)

    • URL :  /api/qnas/{id}
    • Method : DELETE
    • Description : 게시글의 데이터를 삭제합니다. 해당 글은 작성한 회원이 아니면 삭제 요청을 거절합니다.
    • Request Body : 
      - 없음(** DELETE 요청**)
    • Response Code : 
      200 OK : 정상 수정
      400 Bad Request : 삭제 실패
      403 Forbidden : 삭제 권한이 없습니다.
      404 Not Found : 해당 게시물이 존재하지 않습니다.

    • Response Body : -


Q&A 관리자 댓글 등록 (answerEnroll)

  • URL : /api/answers
  • Method : POST
  • Description : 관리자가 댓글을 등록합니다. 관리자가 아니라면 거절합니다.
  • Request Body : 
  • {
  • "qna_id" : "3" // 글번호,
  • "content" : "댓글내용"
  • }
  • Response Code : 
  • 201 CREATED : 등록 성공
  • 400 Bad Request : 삭제 실패
  • 401 Unauthorized : 관리자가 아닙니다.
  • Response Body : -

Q&A 관리자 댓글 삭제 (answerDelete)

  • URL : /api/answers/{id}
  • Method : DELETE
  • Description : 관리자 댓글을 삭제합니다. 관리자가 아니라면 거절합니다.
  • Request Body : 
  • -
  • Response Code : 
  • 200 OK : 삭제 성공
  • 400 Bad Request : 삭제 실패
  • 403 Forbidden : 본인이 아닙니다.
  • Response Body : -

Q&A 댓글 불러오기 (answerList)

  • URL : /api/qnas/{id}/answers
  • Method : GET
  • Description : 글에 작성된 댓글 목록을 불러옵니다.
  • Request Body : 
  • -
  • Response Code : 
  • 200 OK : 삭제 성공
  • 204 No Content : 댓글이 없음
  • Response Body : 
  • [
  •     {
  •         "answer_id" : 1,
  •         "user_seq" : 1,
  •         "content" : "This is the first answer to question 101.",
  •         "created_date" : "날짜"
  •     },
  •     {
  •         "answer_id" : 1,
  •         "user_seq" : 1,
  •         "content" : "This is the first answer to question 101.",
  •         "created_date" : "날짜"
  •     },
  •     {
  •         "answer_id" : 1,
  •         "user_seq" : 1,
  •         "content" : "This is the first answer to question 101.",
  •         "created_date" : "날짜"
  •     }
  • ]
  • SpringBoot에서 응답 본문(ResponseBody) 내용 구성하는 코드
@Getter
@Setter
@AllArgsConstructor
public class ApiResponse<T> {
    private int status;
    private String message;
    private T data;
}

 
 
이렇게 body에는 응답코드, 메시지, data를 담는 객체를 하나 만들어두고
(status는 Response 헤더에 어차피 들어가므로 빼도 상관없다.)

@GetMapping("/{id}")
public ResponseEntity<ApiResponse<Qna>> getQna(@PathVariable Long id) {
    Qna qna = qnaService.getQnaById(id);

    if (qna == null) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ApiResponse<>(404, "Q&A not found", null));
    }

    return ResponseEntity.status(HttpStatus.OK).body(new ApiResponse<>(200, "Q&A retrieved successfully", qna));
}

 
 
이렇게 해주면 ResponseEntity.status(HttpStatus.NOT_FOUND) 여기서 헤더에 응답 코드 404를 설정해주고
 
여기서 .body(new ApiResponse<>(404, "Q&A not found", null));
바디에도 ApiResponse에
1. 응답 코드 2. 응답 코드 관련 문자열 메시지 3. 보낼 데이터 
이렇게 보내면 json으로 
 

{
    "status": 404,
    "message": "Q&A not found",
    "data": null
}

 

{
    "status": 200,
    "message": "Q&A retrieved successfully",
    "data": {
        "qna_id": 1,
        "title": "Q&A 제목",
        "content": "Q&A 내용",
        "created_date": "2024-11-08T12:00:00",
        "is_viewed": 1,
        "author": "John Doe"
    }
}

 
이렇게 간다.
 
리액트에서는 응답코드 int 값을 꺼내서 조회해서 예외처리하면 된다.

axios.get('/qnas/{id}')
  .then((response) => {
    // 응답 성공 시 처리
    setQna(response.data.data);
  })
  .catch((err) => {
    if (err.response) {
      // 서버에서 오류 응답을 받았을 때
      console.log('Error Status:', err.response.status);  // 404, 500 등
      console.log('Error Message:', err.response.data.message);  // "Q&A not found", "An error occurred..."
      
      if (err.response.status === 404) {
        setError('Q&A not found');
      } else {
        setError('An error occurred while fetching the Q&A.');
      }
    } else {
      // 서버 응답이 없거나 네트워크 오류 발생 시
      setError('Network error or server is unreachable.');
    }
  });