Skip to content

Commit

Permalink
feat: 도메인 링크 목록 조회 api 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
hseong3243 committed Mar 28, 2024
1 parent c9a6a2e commit 92019f0
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 10 deletions.
10 changes: 10 additions & 0 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,13 @@ operation::domain-controller-test/find-domain[snippets='http-request,path-parame
==== response

operation::domain-controller-test/find-domain[snippets='http-response,response-fields']

=== 도메인 링크 목록 조회

==== request

operation::domain-controller-test/find-domain-links[snippets='http-request,path-parameters,query-parameters']

==== response

operation::domain-controller-test/find-domain-links[snippets='http-response,response-fields']
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.seong.shoutlink.domain.domain.controller;

import com.seong.shoutlink.domain.domain.controller.request.FindDomainLinksRequest;
import com.seong.shoutlink.domain.domain.controller.request.FindDomainsRequest;
import com.seong.shoutlink.domain.domain.controller.request.FindRootDomainsRequest;
import com.seong.shoutlink.domain.domain.service.DomainService;
import com.seong.shoutlink.domain.domain.service.request.FindDomainCommand;
import com.seong.shoutlink.domain.domain.service.request.FindDomainLinksCommand;
import com.seong.shoutlink.domain.domain.service.request.FindDomainsCommand;
import com.seong.shoutlink.domain.domain.service.request.FindRootDomainsCommand;
import com.seong.shoutlink.domain.domain.service.response.FindDomainDetailResponse;
import com.seong.shoutlink.domain.domain.service.response.FindDomainLinksResponse;
import com.seong.shoutlink.domain.domain.service.response.FindDomainsResponse;
import com.seong.shoutlink.domain.domain.service.response.FindRootDomainsResponse;
import jakarta.validation.Valid;
Expand Down Expand Up @@ -48,4 +51,13 @@ public ResponseEntity<FindDomainDetailResponse> findDomain(
= domainService.findDomain(new FindDomainCommand(domainId));
return ResponseEntity.ok(response);
}

@GetMapping("/{domainId}/links")
public ResponseEntity<FindDomainLinksResponse> findDomainLinks(
@PathVariable("domainId") Long domainId,
@ModelAttribute @Valid FindDomainLinksRequest request) {
FindDomainLinksResponse response = domainService.findDomainLinks(
new FindDomainLinksCommand(domainId, request.page(), request.size()));
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.seong.shoutlink.domain.domain.controller.request;

import jakarta.validation.constraints.Min;
import java.util.Objects;
import org.hibernate.validator.constraints.Range;

public record FindDomainLinksRequest(
@Min(value = 0, message = "페이지는 음수일 수 없습니다.")
Integer page,
@Range(min = 1, max = 100, message = "사이즈는 1 이상 100 이하여야 합니다.")
Integer size) {

public FindDomainLinksRequest(Integer page, Integer size) {
this.page = Objects.isNull(page) ? 0 : page;
this.size = Objects.isNull(size) ? 10 : size;
}
}
158 changes: 148 additions & 10 deletions src/main/resources/static/docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ <h1>API 문서</h1>
<li><a href="#_루트_도메인_목록_조회">루트 도메인 목록 조회</a></li>
<li><a href="#_도메인_목록_조회">도메인 목록 조회</a></li>
<li><a href="#_도메인_단건_조회">도메인 단건 조회</a></li>
<li><a href="#_도메인_링크_목록_조회">도메인 링크 목록 조회</a></li>
</ul>
</li>
</ul>
Expand Down Expand Up @@ -716,7 +717,7 @@ <h5 id="_request_3_http_request"><a class="link" href="#_request_3_http_request"
<div class="content">
<pre class="highlightjs highlight nowrap"><code class="language-http hljs" data-lang="http">POST /api/link-bundles HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjI2NDM5LCJzdWIiOiIxIiwiZXhwIjoxNzExNjMwMDM5LCJyb2xlIjoiUk9MRV9VU0VSIn0.RiQMc9pgMkFKxG0oZO6q6R_HjPrHZeRMjOTegxbDwAc
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjMxOTM1LCJzdWIiOiIxIiwiZXhwIjoxNzExNjM1NTM1LCJyb2xlIjoiUk9MRV9VU0VSIn0.0V1ZcvM6a1HPSMSbXJ2jVNijQKWJnCNVJrWnQNXG788
Content-Length: 57
Host: localhost:8080

Expand Down Expand Up @@ -832,7 +833,7 @@ <h5 id="_request_4_http_request"><a class="link" href="#_request_4_http_request"
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight nowrap"><code class="language-http hljs" data-lang="http">GET /api/link-bundles HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjI2NDM5LCJzdWIiOiIxIiwiZXhwIjoxNzExNjMwMDM5LCJyb2xlIjoiUk9MRV9VU0VSIn0.RiQMc9pgMkFKxG0oZO6q6R_HjPrHZeRMjOTegxbDwAc
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjMxOTM1LCJzdWIiOiIxIiwiZXhwIjoxNzExNjM1NTM1LCJyb2xlIjoiUk9MRV9VU0VSIn0.0V1ZcvM6a1HPSMSbXJ2jVNijQKWJnCNVJrWnQNXG788
Host: localhost:8080</code></pre>
</div>
</div>
Expand Down Expand Up @@ -937,7 +938,7 @@ <h5 id="_request_5_http_request"><a class="link" href="#_request_5_http_request"
<div class="content">
<pre class="highlightjs highlight nowrap"><code class="language-http hljs" data-lang="http">POST /api/hubs/1/link-bundles HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjI2NDM5LCJzdWIiOiIxIiwiZXhwIjoxNzExNjMwMDM5LCJyb2xlIjoiUk9MRV9VU0VSIn0.RiQMc9pgMkFKxG0oZO6q6R_HjPrHZeRMjOTegxbDwAc
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjMxOTM1LCJzdWIiOiIxIiwiZXhwIjoxNzExNjM1NTM1LCJyb2xlIjoiUk9MRV9VU0VSIn0.0V1ZcvM6a1HPSMSbXJ2jVNijQKWJnCNVJrWnQNXG788
Content-Length: 53
Host: localhost:8080

Expand Down Expand Up @@ -1075,7 +1076,7 @@ <h5 id="_request_6_http_request"><a class="link" href="#_request_6_http_request"
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight nowrap"><code class="language-http hljs" data-lang="http">GET /api/hubs/1/link-bundles HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjI2NDM5LCJzdWIiOiIxIiwiZXhwIjoxNzExNjMwMDM5LCJyb2xlIjoiUk9MRV9VU0VSIn0.RiQMc9pgMkFKxG0oZO6q6R_HjPrHZeRMjOTegxbDwAc
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjMxOTM1LCJzdWIiOiIxIiwiZXhwIjoxNzExNjM1NTM1LCJyb2xlIjoiUk9MRV9VU0VSIn0.0V1ZcvM6a1HPSMSbXJ2jVNijQKWJnCNVJrWnQNXG788
Host: localhost:8080</code></pre>
</div>
</div>
Expand Down Expand Up @@ -1203,7 +1204,7 @@ <h5 id="_request_7_http_request"><a class="link" href="#_request_7_http_request"
<div class="content">
<pre class="highlightjs highlight nowrap"><code class="language-http hljs" data-lang="http">POST /api/links HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjI2NDM5LCJzdWIiOiIxIiwiZXhwIjoxNzExNjMwMDM5LCJyb2xlIjoiUk9MRV9VU0VSIn0.RiQMc9pgMkFKxG0oZO6q6R_HjPrHZeRMjOTegxbDwAc
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjMxOTM1LCJzdWIiOiIxIiwiZXhwIjoxNzExNjM1NTM1LCJyb2xlIjoiUk9MRV9VU0VSIn0.0V1ZcvM6a1HPSMSbXJ2jVNijQKWJnCNVJrWnQNXG788
Content-Length: 100
Host: localhost:8080

Expand Down Expand Up @@ -1325,7 +1326,7 @@ <h5 id="_request_8_http_request"><a class="link" href="#_request_8_http_request"
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight nowrap"><code class="language-http hljs" data-lang="http">GET /api/links?linkBundleId=1&amp;page=0&amp;size=10 HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjI2NDM5LCJzdWIiOiIxIiwiZXhwIjoxNzExNjMwMDM5LCJyb2xlIjoiUk9MRV9VU0VSIn0.RiQMc9pgMkFKxG0oZO6q6R_HjPrHZeRMjOTegxbDwAc
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjMxOTM1LCJzdWIiOiIxIiwiZXhwIjoxNzExNjM1NTM1LCJyb2xlIjoiUk9MRV9VU0VSIn0.0V1ZcvM6a1HPSMSbXJ2jVNijQKWJnCNVJrWnQNXG788
Host: localhost:8080</code></pre>
</div>
</div>
Expand Down Expand Up @@ -1392,7 +1393,7 @@ <h5 id="_request_9_http_request"><a class="link" href="#_request_9_http_request"
<div class="content">
<pre class="highlightjs highlight nowrap"><code class="language-http hljs" data-lang="http">POST /api/hubs/1/links HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjI2NDM5LCJzdWIiOiIxIiwiZXhwIjoxNzExNjMwMDM5LCJyb2xlIjoiUk9MRV9VU0VSIn0.RiQMc9pgMkFKxG0oZO6q6R_HjPrHZeRMjOTegxbDwAc
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjMxOTM1LCJzdWIiOiIxIiwiZXhwIjoxNzExNjM1NTM1LCJyb2xlIjoiUk9MRV9VU0VSIn0.0V1ZcvM6a1HPSMSbXJ2jVNijQKWJnCNVJrWnQNXG788
Content-Length: 69
Host: localhost:8080

Expand Down Expand Up @@ -1536,7 +1537,7 @@ <h5 id="_request_10_http_request"><a class="link" href="#_request_10_http_reques
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight nowrap"><code class="language-http hljs" data-lang="http">GET /api/hubs/1/links?linkBundleId=1&amp;page=0&amp;size=20 HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjI2NDM5LCJzdWIiOiIxIiwiZXhwIjoxNzExNjMwMDM5LCJyb2xlIjoiUk9MRV9VU0VSIn0.RiQMc9pgMkFKxG0oZO6q6R_HjPrHZeRMjOTegxbDwAc
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjMxOTM1LCJzdWIiOiIxIiwiZXhwIjoxNzExNjM1NTM1LCJyb2xlIjoiUk9MRV9VU0VSIn0.0V1ZcvM6a1HPSMSbXJ2jVNijQKWJnCNVJrWnQNXG788
Host: localhost:8080</code></pre>
</div>
</div>
Expand Down Expand Up @@ -1705,7 +1706,7 @@ <h5 id="_request_11_http_request"><a class="link" href="#_request_11_http_reques
<div class="content">
<pre class="highlightjs highlight nowrap"><code class="language-http hljs" data-lang="http">POST /api/hubs HTTP/1.1
Content-Type: application/json;charset=UTF-8
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjI2NDM5LCJzdWIiOiIxIiwiZXhwIjoxNzExNjMwMDM5LCJyb2xlIjoiUk9MRV9VU0VSIn0.RiQMc9pgMkFKxG0oZO6q6R_HjPrHZeRMjOTegxbDwAc
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0ZXN0IiwiaWF0IjoxNzExNjMxOTM1LCJzdWIiOiIxIiwiZXhwIjoxNzExNjM1NTM1LCJyb2xlIjoiUk9MRV9VU0VSIn0.0V1ZcvM6a1HPSMSbXJ2jVNijQKWJnCNVJrWnQNXG788
Content-Length: 88
Host: localhost:8080

Expand Down Expand Up @@ -2297,13 +2298,150 @@ <h5 id="_response_15_response_fields"><a class="link" href="#_response_15_respon
</div>
</div>
</div>
<div class="sect2">
<h3 id="_도메인_링크_목록_조회"><a class="link" href="#_도메인_링크_목록_조회">도메인 링크 목록 조회</a></h3>
<div class="sect3">
<h4 id="_request_17"><a class="link" href="#_request_17">request</a></h4>
<div class="sect4">
<h5 id="_request_17_http_request"><a class="link" href="#_request_17_http_request">HTTP request</a></h5>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight nowrap"><code class="language-http hljs" data-lang="http">GET /api/domains/1/links?page=0&amp;size=10 HTTP/1.1
Host: localhost:8080</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="_request_17_path_parameters"><a class="link" href="#_request_17_path_parameters">Path parameters</a></h5>
<table class="tableblock frame-all grid-all stretch">
<caption class="title">Table 1. /api/domains/{domainId}/links</caption>
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Parameter</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>domainId</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">도메인 ID</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect4">
<h5 id="_request_17_query_parameters"><a class="link" href="#_request_17_query_parameters">Query parameters</a></h5>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Parameter</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>page</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">페이지</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>size</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">사이즈</p></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_response_16"><a class="link" href="#_response_16">response</a></h4>
<div class="sect4">
<h5 id="_response_16_http_response"><a class="link" href="#_response_16_http_response">HTTP response</a></h5>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight nowrap"><code class="language-http hljs" data-lang="http">HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 151

{
"links" : [ {
"linkId" : 1,
"url" : "github.com/hseong3243",
"aggregationCount" : 1
} ],
"totalElements" : 1,
"hasNext" : false
}</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="_response_16_response_fields"><a class="link" href="#_response_16_response_fields">Response fields</a></h5>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Path</th>
<th class="tableblock halign-left valign-top">Type</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>links</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Array</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">링크 목록</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>links[].linkId</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Number</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">링크 ID</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>links[].url</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">링크 url</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>links[].aggregationCount</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Number</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">링크 집계 카운트</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>totalElements</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Number</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">총 요소 개수</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>hasNext</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Boolean</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">다음 페이지 여부</p></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Version 0.0.1-SNAPSHOT<br>
Last updated 2024-03-28 20:48:15 +0900
Last updated 2024-03-28 22:19:59 +0900
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.3/highlight.min.js"></script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

import com.seong.shoutlink.base.BaseControllerTest;
import com.seong.shoutlink.domain.domain.service.response.FindDomainDetailResponse;
import com.seong.shoutlink.domain.domain.service.response.FindDomainLinkResponse;
import com.seong.shoutlink.domain.domain.service.response.FindDomainLinksResponse;
import com.seong.shoutlink.domain.domain.service.response.FindDomainResponse;
import com.seong.shoutlink.domain.domain.service.response.FindDomainsResponse;
import com.seong.shoutlink.domain.domain.service.response.FindRootDomainsResponse;
Expand Down Expand Up @@ -113,4 +115,41 @@ void findDomain() throws Exception {
)
));
}

@Test
@DisplayName("성공: 도메인 링크 목록 조회 api 호출 시")
void findDomainLinks() throws Exception {
//given
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("page", "0");
params.add("size", "10");

FindDomainLinkResponse content = new FindDomainLinkResponse(1L, "github.com/hseong3243", 1);
FindDomainLinksResponse response = new FindDomainLinksResponse(List.of(content), 1L, false);
given(domainService.findDomainLinks(any())).willReturn(response);

//when
ResultActions resultActions = mockMvc.perform(get("/api/domains/{domainId}/links", 1L)
.params(params));

//then
resultActions.andExpect(status().isOk())
.andDo(restDocs.document(
pathParameters(
parameterWithName("domainId").description("도메인 ID")
),
queryParameters(
parameterWithName("page").description("페이지"),
parameterWithName("size").description("사이즈")
),
responseFields(
fieldWithPath("links").type(ARRAY).description("링크 목록"),
fieldWithPath("links[].linkId").type(NUMBER).description("링크 ID"),
fieldWithPath("links[].url").type(STRING).description("링크 url"),
fieldWithPath("links[].aggregationCount").type(NUMBER).description("링크 집계 카운트"),
fieldWithPath("totalElements").type(NUMBER).description("총 요소 개수"),
fieldWithPath("hasNext").type(BOOLEAN).description("다음 페이지 여부")
)
));
}
}

0 comments on commit 92019f0

Please sign in to comment.