Skip to content

Commit 564bcc8

Browse files
feat: Add Swagger UI with OpenAPI annotations
- Add OpenApiConfig with API metadata (title, description, version, license) - Add OpenAPI annotations (@operation, @parameter, @apiresponse, @tag) to all API endpoints in ApiEndpoint.java - Configure springdoc Swagger UI and API docs paths in application.yml The springdoc-openapi-starter-webmvc-ui dependency was already present in pom.xml. Swagger UI will be available at /swagger-ui.html when the application is running. Closes #4 Signed-off-by: Ankit <asp45624@gmail.com>
1 parent 2a25e3a commit 564bcc8

3 files changed

Lines changed: 70 additions & 2 deletions

File tree

src/main/java/com/openelements/issues/ApiEndpoint.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
import com.openelements.issues.data.Contributor;
44
import com.openelements.issues.data.Issue;
55
import com.openelements.issues.services.GitHubCache;
6+
import io.swagger.v3.oas.annotations.Operation;
7+
import io.swagger.v3.oas.annotations.Parameter;
8+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
9+
import io.swagger.v3.oas.annotations.tags.Tag;
610
import java.util.Objects;
711
import java.util.Set;
812
import java.util.stream.Collectors;
@@ -13,6 +17,7 @@
1317
import org.springframework.web.bind.annotation.RestController;
1418

1519
@RestController
20+
@Tag(name = "Good First Issue API", description = "Endpoints for querying good first issues, contributors, and repository statistics")
1621
public class ApiEndpoint {
1722

1823
private final static Logger log = org.slf4j.LoggerFactory.getLogger(ApiEndpoint.class);
@@ -23,25 +28,39 @@ public ApiEndpoint(@NonNull final GitHubCache issueCache) {
2328
this.issueCache = Objects.requireNonNull(issueCache, "issueCache must not be null");
2429
}
2530

26-
31+
@Operation(summary = "Get all contributors",
32+
description = "Returns a set of all contributors across the configured repositories")
33+
@ApiResponse(responseCode = "200", description = "Successfully retrieved the list of contributors")
2734
@GetMapping("/api/v2/contributors")
2835
public Set<Contributor> getContributors() {
2936
log.info("Getting contributors");
3037
return issueCache.getContributors();
3138
}
3239

40+
@Operation(summary = "Get contributor count",
41+
description = "Returns the total number of contributors across all configured repositories")
42+
@ApiResponse(responseCode = "200", description = "Successfully retrieved the contributor count")
3343
@GetMapping("/api/v2/contributors/count")
3444
public long getContributorCount() {
3545
log.info("Getting contributors count");
3646
return issueCache.getContributors().size();
3747
}
3848

49+
@Operation(summary = "Get issues",
50+
description = "Returns a filtered set of issues from configured repositories. "
51+
+ "Supports filtering by assignment status, closed status, labels, and programming languages.")
52+
@ApiResponse(responseCode = "200", description = "Successfully retrieved the list of issues")
3953
@GetMapping("/api/v2/issues")
4054
public Set<Issue> getIssues(
55+
@Parameter(description = "Filter by assignment status (true = assigned, false = unassigned)")
4156
@RequestParam(name = "isAssigned", required = false) Boolean isAssigned,
57+
@Parameter(description = "Filter by closed status (true = closed, false = open)")
4258
@RequestParam(name = "isClosed", required = false) Boolean isClosed,
59+
@Parameter(description = "Filter issues that contain all of the specified labels")
4360
@RequestParam(name = "filteredLabels", required = false) Set<String> filteredLabels,
61+
@Parameter(description = "Exclude issues that contain any of the specified labels")
4462
@RequestParam(name = "excludedLabels", required = false) Set<String> excludedLabels,
63+
@Parameter(description = "Filter issues by repository programming languages")
4564
@RequestParam(name = "filteredLanguages", required = false) Set<String> filteredLanguages) {
4665
log.info(
4766
"Getting issues with filters - isAssigned: {}, isClosed: {}, filteredLabels: {}, excludedLabels: {}, filteredLanguages: {}",
@@ -58,21 +77,35 @@ public Set<Issue> getIssues(
5877
.collect(Collectors.toUnmodifiableSet());
5978
}
6079

80+
@Operation(summary = "Get issue count",
81+
description = "Returns the total count of issues matching the specified filters")
82+
@ApiResponse(responseCode = "200", description = "Successfully retrieved the issue count")
6183
@GetMapping("/api/v2/issues/count")
6284
public long getIssuesCount(
85+
@Parameter(description = "Filter by assignment status (true = assigned, false = unassigned)")
6386
@RequestParam(name = "isAssigned", required = false) Boolean isAssigned,
87+
@Parameter(description = "Filter by closed status (true = closed, false = open)")
6488
@RequestParam(name = "isClosed", required = false) Boolean isClosed,
89+
@Parameter(description = "Filter issues that contain all of the specified labels")
6590
@RequestParam(name = "filteredLabels", required = false) Set<String> filteredLabels,
91+
@Parameter(description = "Exclude issues that contain any of the specified labels")
6692
@RequestParam(name = "excludedLabels", required = false) Set<String> excludedLabels,
93+
@Parameter(description = "Filter issues by repository programming languages")
6794
@RequestParam(name = "filteredLanguages", required = false) Set<String> filteredLanguages) {
6895
return getIssues(isAssigned, isClosed, filteredLabels, excludedLabels, filteredLanguages).size();
6996
}
7097

98+
@Operation(summary = "Get total stars count",
99+
description = "Returns the sum of stars across all configured repositories")
100+
@ApiResponse(responseCode = "200", description = "Successfully retrieved the total stars count")
71101
@GetMapping("/api/v2/repositories/stars")
72102
public long getStarsCount() {
73103
return issueCache.getRepositories().stream().mapToLong(repo -> repo.stars()).sum();
74104
}
75105

106+
@Operation(summary = "Get repository count",
107+
description = "Returns the total number of configured repositories")
108+
@ApiResponse(responseCode = "200", description = "Successfully retrieved the repository count")
76109
@GetMapping("/api/v2/repositories/count")
77110
public long getRepositoryCount() {
78111
return issueCache.getRepositories().size();
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.openelements.issues.config;
2+
3+
import io.swagger.v3.oas.models.OpenAPI;
4+
import io.swagger.v3.oas.models.info.Contact;
5+
import io.swagger.v3.oas.models.info.Info;
6+
import io.swagger.v3.oas.models.info.License;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.context.annotation.Configuration;
9+
10+
@Configuration
11+
public class OpenApiConfig {
12+
13+
@Bean
14+
public OpenAPI goodFirstIssueOpenAPI() {
15+
return new OpenAPI()
16+
.info(new Info()
17+
.title("Good First Issue Provider API")
18+
.description("REST API for discovering good first issues from open-source projects on GitHub. "
19+
+ "This service aggregates issues labeled as 'good first issue' from configured repositories "
20+
+ "and provides endpoints to query issues, contributors, and repository statistics.")
21+
.version("2.0.0")
22+
.contact(new Contact()
23+
.name("Open Elements")
24+
.url("https://github.com/OpenElements/good-first-issue-provider"))
25+
.license(new License()
26+
.name("Apache 2.0")
27+
.url("https://www.apache.org/licenses/LICENSE-2.0")));
28+
}
29+
}

src/main/resources/application.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,10 @@ management:
1616
exposure:
1717
include:
1818
- health
19-
- prometheus
19+
- prometheus
20+
springdoc:
21+
swagger-ui:
22+
path: /swagger-ui.html
23+
enabled: true
24+
api-docs:
25+
path: /v3/api-docs

0 commit comments

Comments
 (0)