Skip to content
Snippets Groups Projects
Commit 52189a24 authored by Martin Slovík's avatar Martin Slovík
Browse files

Adding OpenAPI support + simple example in core module

parent 639c3f45
No related branches found
No related tags found
No related merge requests found
Showing with 646 additions and 27 deletions
......@@ -55,5 +55,4 @@
</plugin>
</plugins>
</build>
</project>
spring:
datasource:
url: jdbc:h2:mem:exampleDb
username: sa
password: password
driverClassName: org.h2.Driver
jpa:
database-platform: org.hibernate.dialect.H2Dialect
......@@ -9,9 +9,9 @@
</parent>
<artifactId>core</artifactId>
<packaging>jar</packaging>
<name>core</name>
<description>Core application for tennis court reservations</description>
<description>Core microservice for Airport Manager</description>
<dependencies>
<dependency>
......@@ -27,19 +27,61 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-models-jakarta</artifactId>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations-jakarta</artifactId>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<!-- for pagination from JPA without actually using JPA -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<!-- for testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
......@@ -48,12 +90,52 @@
</dependencies>
<build>
<defaultGoal>spring-boot:run</defaultGoal>
<!-- name of executable JAR file -->
<finalName>core_generated</finalName>
<plugins>
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/../openapi.yaml</inputSpec>
<generatorName>spring</generatorName>
<apiPackage>cz.muni.fi.pa165.core.api</apiPackage>
<modelPackage>cz.muni.fi.pa165.core.model</modelPackage>
<!-- https://openapi-generator.tech/docs/generators/spring -->
<configOptions>
<basePackage>cz.muni.fi.pa165.core</basePackage>
<configPackage>cz.muni.fi.pa165.core.config</configPackage>
<useSpringBoot3>true</useSpringBoot3>
<useTags>true</useTags>
<delegatePattern>true</delegatePattern>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
<!-- create executable jar -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
<!-- run integration tests in "mvn verify" phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package cz.muni.fi.pa165.core;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CoreApplication {
public static void main(String[] args) {
SpringApplication.run(CoreApplication.class, args);
}
}
package cz.muni.fi.pa165.core.rest;
import cz.muni.fi.pa165.core.api.FlightApiDelegate;
import cz.muni.fi.pa165.core.model.FlightDto;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@RestController
public class FlightController implements FlightApiDelegate {
private final List<FlightDto> flightDtos = new CopyOnWriteArrayList<>();
@Override
public ResponseEntity<List<FlightDto>> getAllFlights() {
flightDtos.add(new FlightDto().id(1L));
return new ResponseEntity<>(flightDtos, HttpStatus.OK);
}
}
package cz.muni.fi.pa165.core.rest;
import cz.muni.fi.pa165.core.api.StewardApiDelegate;
import cz.muni.fi.pa165.core.model.PageStewardDto;
import cz.muni.fi.pa165.core.model.PageableObject;
import cz.muni.fi.pa165.core.model.SortObject;
import cz.muni.fi.pa165.core.model.StewardDto;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@RestController
public class StewardController implements StewardApiDelegate {
private final List<StewardDto> stewardDtos = new CopyOnWriteArrayList<>();
@Override
public ResponseEntity<List<StewardDto>> getAllStewards() {
stewardDtos.add(new StewardDto().id(1L).firstName("John").lastName("Doe"));
return new ResponseEntity<>(stewardDtos, HttpStatus.OK);
}
@Override
public ResponseEntity<StewardDto> getSteward(Long id) {
var stewardDto = stewardDtos
.stream()
.filter(x -> x.getId().equals(id))
.findFirst()
.orElse(null);
return new ResponseEntity<>(stewardDto, stewardDto != null ? HttpStatus.OK : HttpStatus.NOT_FOUND);
}
@Override
public ResponseEntity<PageStewardDto> getStewardsPaged(Integer page, Integer size, List<String> sort) {
var pageRequest = PageRequest.of(page, size);
var stewards = stewardDtos.stream().skip(pageRequest.getOffset()).limit(pageRequest.getPageSize()).toList();
var result = new PageImpl<>(stewards, pageRequest, stewardDtos.size());
var s = new SortObject()
.sorted(pageRequest.getSort().isSorted())
.unsorted(pageRequest.getSort().isUnsorted())
.empty(pageRequest.getSort().isEmpty());
var pageableObject = new PageableObject()
.paged(pageRequest.isPaged())
.unpaged(pageRequest.isUnpaged())
.pageNumber(pageRequest.getPageNumber())
.pageSize(pageRequest.getPageSize())
.sort(s)
.offset(pageRequest.getOffset());
var pageStewardDto = new PageStewardDto()
.content(stewards)
.pageable(pageableObject)
.last(result.isLast())
.first(result.isFirst())
.empty(result.isEmpty())
.totalPages(result.getTotalPages())
.totalElements(result.getTotalElements())
.number(result.getNumber())
.numberOfElements(result.getNumberOfElements())
.size(result.getSize())
.sort(s);
return new ResponseEntity<>(pageStewardDto, HttpStatus.OK);
}
}
......@@ -11,11 +11,96 @@
<artifactId>models</artifactId>
<name>models</name>
<name>domain models</name>
<description>Library for Airport Manager with domain model objects</description>
<properties>
<spring-boot.repackage.skip>true</spring-boot.repackage.skip>
</properties>
<build>
<finalName>models-java-lib</finalName>
<defaultGoal>install</defaultGoal>
<plugins>
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<!-- see https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator-maven-plugin/README.md -->
<inputSpec>${project.basedir}/../openapi.yaml</inputSpec>
<generatorName>java</generatorName>
<apiPackage>cz.muni.fi.pa165.model.api</apiPackage>
<modelPackage>cz.muni.fi.pa165.model.dto.domain</modelPackage>
<invokerPackage>cz.muni.fi.pa165.model.invoker</invokerPackage>
<verbose>false</verbose>
<generateApiTests>false</generateApiTests>
<generateModelTests>false</generateModelTests>
<generateApiDocumentation>true</generateApiDocumentation>
<generateModelDocumentation>true</generateModelDocumentation>
<configOptions>
<annotationLibrary>none</annotationLibrary>
<!-- see https://openapi-generator.tech/docs/generators/java/ -->
<library>native</library>
<hideGenerationTimestamp>true</hideGenerationTimestamp>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
openapi: 3.0.1
info:
title: Airport Manager
description: |
Microservice Application for Airport Manager
contact:
name: Martin Slovik
email: 540485@mail.muni.cz
# insert your information as well
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
version: "1.1"
servers:
- url: "{scheme}://{server}:{port}"
description: my server
variables:
scheme:
default: http
enum:
- http
- https
server:
default: localhost
port:
default: "8080"
tags:
- name: Core
description: microservice for core
paths:
/api/stewards:
get:
tags:
- Steward
summary: Get all stewards
description: |
Returns an array of objects representing stewards, ordered from the newest to the oldest.
Each steward must have an **id**, **firstName** and **lastName**.
operationId: getAllStewards
responses:
"200":
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/StewardDto'
/api/stewards/{id}:
get:
tags:
- Steward
summary: Returns identified steward
description: Looks up a stewards by id.
operationId: getSteward
parameters:
- name: id
in: path
required: true
schema:
type: integer
format: int64
responses:
"200":
$ref: '#/components/responses/SingleStewardDtoResponse'
"404":
description: steward not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorMessage'
/api/stewards/paged:
get:
tags:
- Steward
summary: Paged stewards
description: |
Returns a page of stewards. Stewards are ordered from the newest to the oldest.
The parameter `page` specifies zero-based index of the requested page,
and the parameter `size` specifies the size of the page.
operationId: getStewardsPaged
parameters:
- name: page
in: query
description: Zero-based page index (0..N)
required: false
schema:
minimum: 0
type: integer
default: 0
- name: size
in: query
description: The size of the page to be returned
required: false
schema:
minimum: 1
type: integer
default: 20
- name: sort
in: query
description: "Sorting criteria in the format: property,(asc|desc). Default\
\ sort order is ascending. Multiple sort criteria are supported."
required: false
schema:
type: array
items:
type: string
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/PageStewardDto'
/api/flights:
get:
tags:
- Flight
summary: Get all flights
description: |
Returns an array of objects representing flights, ordered from the newest to the oldest.
Each steward must have an **id**.
operationId: getAllFlights
responses:
"200":
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/FlightDto'
components:
schemas:
DomainEntity:
title: domain entity
description: represents a domain entity
type: object
required:
- id
properties:
id:
type: integer
description: id of domain entity
format: int64
example: 1
discriminator:
propertyName: objectType
ErrorMessage:
allOf:
- $ref: '#/components/schemas/DomainEntity'
title: error message
description: response body for HTML statuses
type: object
properties:
timestamp:
type: string
description: time in ISO format
format: date-time
example: 2022-12-21T18:52:10.757Z
status:
type: integer
description: HTTP status code
format: int32
example: 404
error:
type: string
description: HTTP status text
example: Not Found
message:
type: string
description: reason for error
example: entity not found
path:
type: string
description: URL path
example: /api/stewards/1
StewardDto:
allOf:
- $ref: '#/components/schemas/DomainEntity'
type: object
title: steward
description: represents a steward on a flight
required:
- id
- firstName
- lastName
properties:
firstName:
type: string
description: first name of a steward
example: John
lastName:
type: string
description: last name of a steward
example: Doe
FlightDto:
allOf:
- $ref: '#/components/schemas/DomainEntity'
type: object
title: flight
description: represents a flight
required:
- id
PageableObject:
type: object
properties:
offset:
type: integer
format: int64
sort:
$ref: '#/components/schemas/SortObject'
pageSize:
type: integer
format: int32
pageNumber:
type: integer
format: int32
paged:
type: boolean
unpaged:
type: boolean
SortObject:
type: object
properties:
empty:
type: boolean
sorted:
type: boolean
unsorted:
type: boolean
PageStewardDto:
type: object
properties:
totalPages:
type: integer
format: int32
totalElements:
type: integer
format: int64
first:
type: boolean
last:
type: boolean
size:
type: integer
format: int32
content:
type: array
items:
$ref: '#/components/schemas/StewardDto'
number:
type: integer
format: int32
sort:
$ref: '#/components/schemas/SortObject'
numberOfElements:
type: integer
format: int32
pageable:
$ref: '#/components/schemas/PageableObject'
empty:
type: boolean
responses:
SingleStewardDtoResponse:
description: response containing a single steward
content:
application/json:
schema:
$ref: '#/components/schemas/StewardDto'
links:
link_to_getSteward:
operationId: getSteward
parameters:
id: $response.body#/id
description: |
The `id` value returned in the response can be used as
the `id` parameter in `GET /stewards/{id}`.
\ No newline at end of file
......@@ -7,6 +7,7 @@
<groupId>cz.muni.fi.pa165</groupId>
<artifactId>airport-manager</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>core</module>
<module>model</module>
......@@ -16,6 +17,20 @@
</modules>
<packaging>pom</packaging>
<name>airport manager parent</name>
<description>Airport Manager microservice with OpenAPI description</description>
<organization>
<name>Masaryk University</name>
<url>https://www.muni.cz/</url>
</organization>
<inceptionYear>2023</inceptionYear>
<developers>
<!-- insert your information as well -->
<developer>
<id>540485</id>
<name>Martin Slovik</name>
</developer>
</developers>
<parent>
<groupId>org.springframework.boot</groupId>
......@@ -29,6 +44,7 @@
<maven.compiler.target>17</maven.compiler.target>
<lombok.version>1.18.26</lombok.version>
<org.mapstruct.version>1.5.3.Final</org.mapstruct.version>
<swagger-jakarta-version>2.2.8</swagger-jakarta-version>
<version>1.0-SNAPSHOT</version>
</properties>
......@@ -77,6 +93,60 @@
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.6</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.9</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-models-jakarta</artifactId>
<version>${swagger-jakarta-version}</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations-jakarta</artifactId>
<version>${swagger-jakarta-version}</version>
</dependency>
</dependencies>
</dependencyManagement>
......@@ -126,8 +196,19 @@
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>6.4.0</version>
</plugin>
<plugin>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-maven-plugin</artifactId>
<version>1.4</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
\ No newline at end of file
......@@ -44,5 +44,4 @@
</plugin>
</plugins>
</build>
</project>
......@@ -55,5 +55,4 @@
</plugin>
</plugins>
</build>
</project>
spring:
datasource:
url: jdbc:h2:mem:exampleDb
username: sa
password: password
driverClassName: org.h2.Driver
jpa:
database-platform: org.hibernate.dialect.H2Dialect
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment