Skip to content

Commit 4e07cb1

Browse files
wistefanclaudeclaude
authored
Implement list issuers (#25)
* feat(api): add GET /issuer endpoint for paginated listing of issuer DIDs Extends the OpenAPI spec with a new GET /issuer endpoint that returns a paginated list of all trusted issuer DIDs. Adds PageSize and Page query parameters and a TrustedIssuersListResponse schema. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(api): implement GET /issuer endpoint for paginated listing of DIDs Adds the getIssuers method to TrustedIssuersListController that returns a paginated, sorted list of all trusted issuer DIDs. Includes tests for default pagination, custom page size, second page, empty results, and invalid page size rejection. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: claude <claude@gitea.com>
1 parent a0d00e9 commit 4e07cb1

3 files changed

Lines changed: 162 additions & 0 deletions

File tree

api/trusted-issuers-list.yaml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@ tags:
88
- name: issuer
99
paths:
1010
/issuer:
11+
get:
12+
tags:
13+
- issuer
14+
operationId: getIssuers
15+
summary: Get the DIDs of all trusted issuers
16+
description: Returns a paginated list of DIDs of all trusted issuers.
17+
parameters:
18+
- $ref: '#/components/parameters/PageSize'
19+
- $ref: '#/components/parameters/Page'
20+
responses:
21+
'200':
22+
description: Successfully retrieved the list of issuer DIDs.
23+
content:
24+
application/json:
25+
schema:
26+
$ref: '#/components/schemas/TrustedIssuersListResponse'
1127
post:
1228
tags:
1329
- issuer
@@ -110,7 +126,49 @@ components:
110126
schema:
111127
type: string
112128
example: did:elsi:happypets
129+
PageSize:
130+
name: pageSize
131+
in: query
132+
required: false
133+
description: Maximum number of items to return per page.
134+
schema:
135+
type: integer
136+
minimum: 1
137+
maximum: 100
138+
default: 10
139+
example: 10
140+
Page:
141+
name: page
142+
in: query
143+
required: false
144+
description: The page number to retrieve (zero-based).
145+
schema:
146+
type: integer
147+
minimum: 0
148+
default: 0
149+
example: 0
113150
schemas:
151+
TrustedIssuersListResponse:
152+
type: object
153+
properties:
154+
total:
155+
type: integer
156+
description: Total number of trusted issuers.
157+
example: 42
158+
pageSize:
159+
type: integer
160+
description: Number of items per page.
161+
example: 10
162+
page:
163+
type: integer
164+
description: Current page number (zero-based).
165+
example: 0
166+
items:
167+
type: array
168+
description: List of issuer DIDs on this page.
169+
items:
170+
type: string
171+
example: did:elsi:happypets
114172
TimeRange:
115173
type: object
116174
properties:

src/main/java/org/fiware/iam/rest/TrustedIssuersListController.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package org.fiware.iam.rest;
22

33
import io.micronaut.core.annotation.Introspected;
4+
import io.micronaut.core.annotation.Nullable;
5+
import io.micronaut.data.model.Page;
6+
import io.micronaut.data.model.Pageable;
7+
import io.micronaut.data.model.Sort;
48
import io.micronaut.http.HttpResponse;
59
import io.micronaut.http.annotation.Controller;
610
import jakarta.transaction.Transactional;
@@ -14,9 +18,11 @@
1418
import org.fiware.iam.repository.TrustedIssuerRepository;
1519
import org.fiware.iam.til.api.IssuerApi;
1620
import org.fiware.iam.til.model.TrustedIssuerVO;
21+
import org.fiware.iam.til.model.TrustedIssuersListResponseVO;
1722

1823
import java.net.URI;
1924
import java.util.Collection;
25+
import java.util.List;
2026
import java.util.Optional;
2127

2228
/**
@@ -30,10 +36,46 @@ public class TrustedIssuersListController implements IssuerApi {
3036

3137
public static final String HREF_TEMPLATE = "/v4/issuers/%s";
3238

39+
private static final int DEFAULT_PAGE_SIZE = 10;
40+
private static final int MIN_PAGE_SIZE = 1;
41+
private static final int MAX_PAGE_SIZE = 100;
42+
private static final String SORT_FIELD = "did";
43+
3344
private final TrustedIssuerRepository trustedIssuerRepository;
3445
private final CredentialRepository credentialRepository;
3546
private final TILMapper trustedIssuerMapper;
3647

48+
/**
49+
* Returns a paginated list of DIDs of all trusted issuers, sorted alphabetically.
50+
*
51+
* @param pageSize maximum number of items per page (1-100, defaults to 10)
52+
* @param page zero-based page number (defaults to 0)
53+
* @return paginated response containing the issuer DIDs
54+
*/
55+
@Override
56+
public HttpResponse<TrustedIssuersListResponseVO> getIssuers(@Nullable Integer pageSize, @Nullable Integer page) {
57+
pageSize = Optional.ofNullable(pageSize).orElse(DEFAULT_PAGE_SIZE);
58+
page = Optional.ofNullable(page).orElse(0);
59+
60+
if (pageSize < MIN_PAGE_SIZE || pageSize > MAX_PAGE_SIZE) {
61+
throw new IllegalArgumentException("The requested page size is not supported.");
62+
}
63+
64+
Sort didSort = Sort.unsorted().order(SORT_FIELD);
65+
Pageable pagination = Pageable.from(page, pageSize, didSort);
66+
Page<TrustedIssuer> result = trustedIssuerRepository.findAll(pagination);
67+
68+
List<String> dids = result.getContent().stream()
69+
.map(TrustedIssuer::getDid)
70+
.toList();
71+
72+
return HttpResponse.ok(new TrustedIssuersListResponseVO()
73+
.total((int) result.getTotalSize())
74+
.pageSize(result.getNumberOfElements())
75+
.page(page)
76+
.items(dids));
77+
}
78+
3779
@Transactional
3880
@Override
3981
public HttpResponse<Object> createTrustedIssuer(TrustedIssuerVO trustedIssuerVO) {

src/test/java/org/fiware/iam/rest/TrustedIssuersListControllerTest.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.junit.jupiter.params.provider.Arguments;
1717
import org.junit.jupiter.params.provider.MethodSource;
1818

19+
import java.util.ArrayList;
1920
import java.util.List;
2021
import java.util.Optional;
2122
import java.util.stream.Stream;
@@ -147,6 +148,67 @@ public void getIssuer404() throws Exception {
147148
assertEquals(HttpStatus.NOT_FOUND, getResponse.getStatus(), "No issuer should have been found");
148149
}
149150

151+
@Test
152+
@Override
153+
public void getIssuers200() throws Exception {
154+
List<TrustedIssuerVO> issuers = new ArrayList<>();
155+
for (int i = 10; i < 30; i++) {
156+
TrustedIssuerVO issuer = TrustedIssuerVOTestExample.build()
157+
.did(String.format("did:elsi:%s", i));
158+
testClient.createTrustedIssuer(issuer);
159+
issuers.add(issuer);
160+
}
161+
162+
// default pagination: page 0, size 10
163+
HttpResponse<TrustedIssuersListResponseVO> response = testClient.getIssuers(null, null);
164+
assertEquals(HttpStatus.OK, response.getStatus(), "The issuers should have been returned.");
165+
TrustedIssuersListResponseVO body = response.body();
166+
assertEquals(20, body.getTotal(), "Total count should include all issuers.");
167+
assertEquals(10, body.getPageSize(), "Default page size should be 10.");
168+
assertEquals(0, body.getPage(), "Default page should be 0.");
169+
assertEquals(10, body.getItems().size(), "First page should contain 10 items.");
170+
assertEquals("did:elsi:10", body.getItems().get(0), "Items should be sorted by DID.");
171+
172+
// custom page size
173+
response = testClient.getIssuers(20, null);
174+
assertEquals(HttpStatus.OK, response.getStatus(), "The issuers should have been returned.");
175+
body = response.body();
176+
assertEquals(20, body.getTotal(), "Total count should include all issuers.");
177+
assertEquals(20, body.getPageSize(), "Requested page size should be applied.");
178+
assertEquals(20, body.getItems().size(), "All issuers should be returned in one page.");
179+
180+
// second page
181+
response = testClient.getIssuers(10, 1);
182+
assertEquals(HttpStatus.OK, response.getStatus(), "The issuers should have been returned.");
183+
body = response.body();
184+
assertEquals(20, body.getTotal(), "Total count should include all issuers.");
185+
assertEquals(10, body.getPageSize(), "Page size should be 10.");
186+
assertEquals(1, body.getPage(), "Page number should be 1.");
187+
assertEquals("did:elsi:20", body.getItems().get(0),
188+
"Second page should start after first page items.");
189+
}
190+
191+
@Test
192+
public void getIssuersEmpty200() throws Exception {
193+
HttpResponse<TrustedIssuersListResponseVO> response = testClient.getIssuers(null, null);
194+
assertEquals(HttpStatus.OK, response.getStatus(), "An empty list should still return 200.");
195+
TrustedIssuersListResponseVO body = response.body();
196+
assertEquals(0, body.getTotal(), "Total should be 0 for an empty list.");
197+
assertTrue(body.getItems().isEmpty(), "Items should be empty.");
198+
}
199+
200+
@Test
201+
public void getIssuersInvalidPageSize400() throws Exception {
202+
try {
203+
testClient.getIssuers(0, null);
204+
} catch (HttpClientResponseException e) {
205+
assertEquals(HttpStatus.BAD_REQUEST, e.getStatus(),
206+
"A page size below the minimum should be rejected.");
207+
return;
208+
}
209+
fail("A page size of 0 should be rejected.");
210+
}
211+
150212
@Override
151213
public void updateIssuer200() throws Exception {
152214
assertEquals(HttpStatus.CREATED, testClient.createTrustedIssuer(issuerUpdate.initialIssuer).getStatus(),

0 commit comments

Comments
 (0)