Making your API easy to document with Spring REST Docs 

http://gmind7.github.io

Java Softeware Developer

9

Test

Document

"테스트 작성은 어렵지 않다. 단지 좋아하지 않을 뿐이다."

"잘 작성되고 설명이 풍부하면서 동시에 간결한 문서 작성하기"

http://www.itworld.co.kr/slideshow/85296

*.adoc

*.adoc

*.html

more

Request

Response

index.adoc

*.adoc

index.adoc

*.adoc

index.adoc

index.adoc

....................

.......................................................

spring rest docs.......

curl http://127......................

RESTful API Docuemtns

*.adoc

mvc test

auto

Appointment RESTful API Documents

/doctors

/patients

/schedules

 /

{
  "timestamp": "2015-10-296 10:49:34",
  "status": 404,
  "error": "Not Found",
  "message": "No message available",
  "path": "/"
}

 /doctors

{
  "doctors": [
    {
      "id": 1,
      "name": "doctor_name_1"        
    },
    {
      "id": 2,
      "name": "doctor_name_2"        
    },
    ..................
    ]
}

http://stateless.co/hal_specification.html

HATEOAS

Hypermedia as the Engine of Application State

 /

{
  "_links": {
    "doctors": {
      "href": "http://localhost:8080/doctors"
    },
    "patient": {
      "href": "http://localhost:8080/patients"
    },
    "schedule": {
      "href": "http://localhost:8080/schedules"
    }
  }
}

 /doctors

{
    "_links": {
        "self": {
            "href": "http://localhost:8080/doctors{?page,size,sort}",
            "templated": true
        },
        "next": {
            "href": "http://localhost:8080/doctors?page=1&size=10{&sort}",
            "templated": true
        }
    },
    "_embedded": {
        "doctors": [
          {
            "id": 1,
            "name": "doctor_name_1",
            "_links": {
              "self": {
                "href": "http://127.0.0.1:8080/doctors/1"
              },
              "doctor_schedules": {
                "href": "http://127.0.0.1:8080/doctors/1/schedules"
              }
            }
          },
          {
            "id": 2,
            "name": "doctor_name_2",
            "_links": {
              "self": {
                "href": "http://127.0.0.1:8080/doctors/2"
              },
              "doctor_schedules": {
                "href": "http://127.0.0.1:8080/doctors/2/schedules"
              }
            }
          },
          ........
        ]
    },
    "page": {
        "size": 10,
        "totalElements": 29,
        "totalPages": 3,
        "number": 0
    }
}

 Richardson  Maturity Model

http://martinfowler.com/articles/richardsonMaturityModel.html

plugins { 
    id "org.asciidoctor.convert" version "1.5.2"
}
dependencies { 
    testCompile 'org.springframework.restdocs:spring-restdocs-mockmvc:1.0.0.RELEASE'
}
ext { 
    snippetsDir = file('build/generated-snippets')
}
test { 
    outputs.dir snippetsDir
}
asciidoctor { 
    attributes 'snippets': snippetsDir 
    inputs.dir snippetsDir 
    dependsOn test 
}
jar {
    dependsOn asciidoctor
    from ("${asciidoctor.outputDir}/html5") {
        into 'static/docs'
    }
}
@Rule
public final RestDocumentation restDocumentation = 
    new RestDocumentation("build/generated-snippets");

@Autowired
private WebApplicationContext context;

public RestDocumentationResultHandler document;

public MockMvc mockMvc;

@Before
public void setUp() {
    this.document = document("{method-name}");
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
            .apply(documentationConfiguration(this.restDocumentation)
                    .uris().withScheme("http").withHost("root-endpoint"))
            .alwaysDo(this.document)
            .build();
}
@Test
public void doctorsShowAll() throws Exception {
    this.mockMvc.perform(get("/doctors").param("page","2").param("size","10"))
        .andExpect(status().isOk())
        .andDo(this.document.snippets(
            links(
                linkWithRel("next").optional().description("다음페이지"),
                linkWithRel("prev").optional().description("이전페이지"),
                linkWithRel("self").description("현재페이지")),
            requestParameters(
                parameterWithName("page").description("페이지 번호"),
                parameterWithName("size").description("리스트 사이즈")),
            responseFields(
                fieldWithPath("_links").type(JsonFieldType.OBJECT).description("<<resources-doctors-show-all-links,Doctors>> Resources"),
                fieldWithPath("_embedded.doctors").type(JsonFieldType.OBJECT).description("<<resources-doctors-show-one, Doctor>> Resource").optional(),
                fieldWithPath("page").type(JsonFieldType.OBJECT).description("Information On <<overview-pagination, Pagination>>"))));
}

:test

:asciidoctor

:jar

index.adoc

....................

.......................................................

spring rest docs.......

curl http://127......................

RESTful API Docuemtns

*.adoc

overview.adoc

resources.adoc

overview-current.adoc

..........*.adoc

.....*.adoc

resources-doctors.adoc

..........*.adoc

.....*.adoc

index.adoc

C:\spring-rest-docs-seminar
\src\main\asciidoc>tree /F

C:.
│  index.adoc
│
├─overview
│      overview-current-version.adoc
│      overview-schema.adoc
│      overview-parameters.adoc
│      overview-root-endpoint.adoc
│      ...........
│      .......
│      ..
│
├─resources
│      resources-doctors.adoc
│      resources-index.adoc
│      resources-patients.adoc
│      resources-schedules.adoc
C:\spring-rest-docs-seminar
\build\generated-snippets>tree /F

C:.
├─doctors-show-all
│      curl-request.adoc
│      http-request.adoc
│      http-response.adoc
│      links.adoc
│      request-parameters.adoc
│      response-fields.adoc
│
└─doctors-show-one
        curl-request.adoc
        http-request.adoc
        http-response.adoc
        links.adoc
        path-parameters.adoc
        response-fields.adoc
..........
........
......
....
..
C:.
├─doctors-show-all
│      curl-request.adoc
│      http-request.adoc
│      http-response.adoc
│      links.adoc
│      request-parameters.adoc
│      response-fields.adoc
C:\spring-rest-docs-seminar
\src\main\asciidoc>tree /F

C:.
│  index.adoc
│
├─overview
│      overview-current-version.adoc
│      overview-schema.adoc
│      overview-parameters.adoc
│      overview-root-endpoint.adoc
│      ...........
│      .......
│      ..
│
├─resources
│      resources-doctors.adoc
│      resources-index.adoc
│      resources-patients.adoc
│      resources-schedules.adoc

mvc test

auto

overview.html

resources.html

overview-current.html

..........*.html

.....*.html

resources-doctors.html

..........*.html

.....*.html

index.html

build/asciidoc

         /generated-sn~

src/main/asciidoc

src/main/resources/static/docs

http://gmind7.github.io/docs.html

build.gradle || pom.xml

Spring MVC TEST

  .andDo(Spring REST Docs)

index.adoc 

   include::resources-*.adoc

         include::**-restdocs.adoc

index.html

https://github.com/gmind7

/spring-rest-docs-seminar

Making your API easy to document with Spring REST Docs 

The End.

spring-rest-docs-seminar

By daesungkim

spring-rest-docs-seminar

RESTful API를 제공 하면서 API 문서를 항상 만들었습니다. 시간이 지남에 따라 제공된 API의 기능들은 추가 되거나 변경/삭제 되어 갔지만, 그에 반해 API 문서는 관리 소홀로 결국에는 불일치(API!=DOC)되면서 겪게 되는 API 문서 관리의 어려움을 우리는 자주 만나고 있습니다. 현재 한참 개발이 진행중인 스프링 프로젝트 중 Spring REST Docs를 사용해 API 문서를 손쉽게 자동으로 생성하고, 테스트까지 함께 할 수 있는 지에 대한 경험을 공유하고자 합니다. Swagger를 넘어 이제는 Spring REST Docs으로... 이 세션에서는 Spring REST Docs + MVC Test 두 마리 토끼를 한번에 잡을 수 있는 방법을 살펴보고자 합니다.

  • 2,457