Spring Projcect/날씨 일기 프로젝트

Chapter 10. API document 만들기 (API 문서화)

계란💕 2022. 9. 1. 17:25

10.1 API(Application Interface) document

 

API documentaion(API 문서화)

  • 프론트 개발자에게 문서를 전하기 위해 필요하다.
  • 백엔드 개발자끼리도 공유해야한다.
  • API를 제공하는 웹 사이트는 보통 API document도 함께 제공한다.

 

  API 문서화 방식

  • txt 파일에 정리한다. => 가독성 떨어지고 변경 사항 추적이 어렵다.
  • API 문서화 tool을 많이 이용한다.
    • Swagger
      • 서버로 요청되는 URL 리스트를 HTML 화면으로 문서화 및 테스트할 수 있는 라이브러리이다. 
      • API 문서를 만들면 하나의 URL로서 공유 가능하다. 다른 사람들이 URL을 통해 들어가서 API 호출 가능하다.
    • ReDoc
    • GitBook

 

 

 

10.2 Swagger 적용하기 (1)

 

 Ex) swagger 적용하는 방법

 

  • swagger 라이브러리 추가
<hide/>
implementation 'io.springfox:springfox-boot-starter:3.0.0'
implementation 'io.springfox:springfox-swagger-ui:3.0.0'

 

  • properties - 기존의 스프링 mvc 패턴과 swagger 3.0.0를 매치시키기 위해서 넣는다.
spring.mvc.pathmatch.matching-strategy=ant_path_matcher

 

  • SwaggerConfig - swagger를 설정한다.
    • @EnableSwagger2: swagger를 활성화시킨다.
<hide/>
package zerobase.weather.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2).select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build().apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        String description = "Welcome Log Company";
        return new ApiInfoBuilder()
                .title("SWAGGER TEST")
                .description(description)
                .version("1.0")
                .build();
    }
}

 

  Note) 실행 결과 - http://localhost:8080/swagger-ui/index.html

  • 지금은 로컬 호스트를 쓰는 중이지만 서버를 배포하면 서버를 배포한 장비의 IP를 활용하면 (IP만 바뀐채로) 이 화면을 똑같이 볼 수 있다.
  •  URL을 공유하면 다른 사람들과 같은 화면을 공유 가능하다.

 

 

 

 

 

10.3 Swagger 적용하기 (2)

 

 Ex) Swagger 설정하기

 

  • apiInfo() 를 수정한다.
<hide/>
private ApiInfo apiInfo() {
    return new ApiInfoBuilder()
            .title("날씨 일기 프로젝트 ╰(*°▽°*)╯")
            .description("날씨 일기를 CRUD할 수 있는 백엔드 API입니다.")
            .version("2.0")
            .build();
}

  Note) 실행 결과

  • 위 페이지에 basic-error-controller가 뜬다.
  • 그런데, api 사용자가 에러 요청을 보내지는 않을 것이므로  basic-error-controller는 없애는 게 좋다.
  • 따라서 apis() 메서드 매개변수를 수정한다.
    • apis(): swagger api 문서로 만들기 원하는 basePackage()경로를 넣는다. 
    • RequestHandlerSelectors.any() => RequestHandlerSelectors.basePackage("패키지명")
<hide/>
@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2).select()
            .apis(RequestHandlerSelectors.basePackage("zerobase.weather"))  // 패키지명
            .paths(PathSelectors.any())
            .build().apiInfo(apiInfo());
}

 

  • 그럼 다음과 같이 error-controller가 없어진다.
    • error-controller는 스프링 안에 있는 것이며 basePachage안에 있는 것이 아니다.
    • 그래서 보통 apis() 안에 RequestHandlerSelectors를 basePackage 기준으로 많이 지정한다.

 

 

  • paths(): URL 경로를 지정한다.
    • paths()는 패스 기준으로 swagger에 표시될 api를 정할 수 있는 기능이다.
    • paths() 안에 any()를 넣으면 경로에 대한 기준을 주지 않고 모든 api가 나오도록 하겠다는 의미이다. 따라서 컨트롤러 안에 있는 api가 모두 나온다.
    • 다음과 같이 paths(PathSelectors.none())으로 설정하면?
<hide/>
@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2).select()
            .apis(RequestHandlerSelectors.basePackage("zerobase.weather"))  // 패키지명
            .paths(PathSelectors.none())
            .build().apiInfo(apiInfo());
}

  Note) none() 실행 결과

 

 

  •  .paths(PathSelectors.ant("패턴")를 이용하면 특정 경로만 표시되도록 할 수 있다.
    • read로 시작하는 api만 나오도록 한다.
<hide/>
@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2).select()
            .apis(RequestHandlerSelectors.basePackage("zerobase.weather"))  // 패키지명
            .paths(PathSelectors.ant("/read/**"))
            .build().apiInfo(apiInfo());
}

  Note) ant() 실행 결과

 

 

 

  Ex) @ApiOperation("")

 

 

  • @ApiOperation: 요청 url에 매핑된 api에 대한 설명
  • 클라이언트 용  API, admin용 API (백엔드 개발자만 쓰기 위한 API) 모두 필요하다. 
  • 그럼 swagger를 이용해서 adminCtrl안에 있는 작업은 클라이언트에 보이지 않도록 설정한다.

 

 

  • 다음과 같이 안티 패턴을 any()로 다시 바꾼다.
<hide/>
@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2).select()
            .apis(RequestHandlerSelectors.basePackage("zerobase.weather"))  // 패키지명
            .paths(PathSelectors.any())
            .build().apiInfo(apiInfo());
}

 

  • 컨트롤러  - @ApiOperation() 추가
<hide/>
@ApiOperation("여기에 주석을 달면 어디에 뜰까? ╰(*°▽°*)╯")
@PostMapping("/create/diary")
void createDiary(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, @RequestBody String text){
    diaryService.createDiary(date, text);
}

  Note) 실행 결과

 

 

  Ex)  @ApiOperation(value ="한 줄 설명", note="긴 설명") 

  • note
<hide/>
@ApiOperation(value = "여기에 주석을 달면 어디에 뜰까? ╰(*°▽°*)╯",
              notes = "note ༼ つ ◕_◕ ༽つ ")
@PostMapping("/create/diary")
void createDiary(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, @RequestBody String text){
    diaryService.createDiary(date, text);
}

  Note) 실행 결과

 

 

<hide/>
@ApiOperation(value = "일기 텍스트와 날씨를 이용해서 DB에 일기 저장 ╰(*°▽°*)╯",
              notes = "note ༼ つ ◕_◕ ༽つ ")
@PostMapping("/create/diary")
void createDiary(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, @RequestBody String text){
    diaryService.createDiary(date, text);
}

@ApiOperation(value = "선택한 날짜의 모든 다이어리를 가져옴 ¯|_(ツ)_/¯")
@GetMapping("/read/diary")
List<Diary> readDiary(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date){

    return diaryService.readDiary(date);
}

@ApiOperation(value = "선택한 기간 내에 저장된 모든 다이어리를 가져옴 ¯|_(ツ)_/¯")
@GetMapping("/read/diaries")
List<Diary> readDiaries(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
                        @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate ){
    return diaryService.readDiaries(startDate, endDate);
}

 

  Note) 

 

 

 

  Ex) 파라미터 형식 지정하기 - @ApiParam

 

  • 기존 화면을 보면 다음과 같이 매개변수 형식에 대한 내용이 없다.

 

  • 다음과 같이 @ApiParam을 추가한다. 예제도 example로 넣을 수 있다.
<hide/>
@ApiOperation(value = "선택한 기간 내에 저장된 모든 다이어리를 가져옴 ¯|_(ツ)_/¯")
@GetMapping("/read/diaries")
List<Diary> readDiaries(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) @ApiParam(value="날짜형식: yyyy-MM-dd", example = "2020-02-02") LocalDate startDate,
                        @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate ){
    return diaryService.readDiaries(startDate, endDate);
}

  Note) 실행 결과

 

 

<hide/>
@ApiOperation(value = "선택한 기간 내에 저장된 모든 다이어리를 가져옴 ¯|_(ツ)_/¯")
@GetMapping("/read/diaries")
List<Diary> readDiaries(@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) @ApiParam(value="조회할 기간의 첫 번째 날입니다.", example = "2020-02-02") LocalDate startDate,
                        @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) @ApiParam(value="조회할 기간의 마지막 날입니다.", example = "2020-02-02") LocalDate endDate ){
    return diaryService.readDiaries(startDate, endDate);
}

  Note) 실행 결과

 

 

 

출처 - 제로베이스 백엔드 스쿨 (김조현 강사님)

https://zero-base.co.kr/

 

제로베이스 - 누구나 취업하는 가장 합리적인 취업 스쿨

코딩 부트 캠프 개발자, 데이터 사이언티스트, 마케터, PM, 디자이너 등 제대로 공부하고 확실하게 취업하세요. 당신의 삶의 전환점이 될 제로베이스 스쿨입니다.

zero-base.co.kr