[BAEL-3319] - Documenting a Spring REST API using OpenAPI (#7919)
* [BAEL-3211] Generate Integers within a range in Java * [BAEL-3211] Generate Integers within a range in Java * Moved files from java-numbers to java-numbers-2 * [BAEL-3319] - Documenting a Spring REST API using OpenAPI * [BAEL-3319] Added a new module for springdoc-openapi library * Incorporated feedback - indents, GetMapping et al annotations, package as jar, remove README & spring-webflux change, use of map in BookRepository * Used DeleteMapping instead of RequestMapping * Add the spring-boot-springdoc module to root pom.xml * Remove plain spring boot starter from pom.xml
This commit is contained in:
parent
289c3e4c34
commit
78e23b246c
7
pom.xml
7
pom.xml
|
@ -722,10 +722,11 @@
|
|||
<module>spring-boot-parent</module>
|
||||
<module>spring-boot-property-exp</module>
|
||||
<module>spring-boot-security</module>
|
||||
<module>spring-boot-springdoc</module>
|
||||
<module>spring-boot-testing</module>
|
||||
<module>spring-boot-vue</module>
|
||||
<module>spring-caching</module>
|
||||
<module>spring-boot-libraries</module>
|
||||
<module>spring-boot-libraries</module>
|
||||
|
||||
|
||||
<module>spring-cloud</module>
|
||||
|
@ -922,6 +923,7 @@
|
|||
<module>spring-boot-keycloak</module>
|
||||
<module>spring-boot-mvc</module>
|
||||
<module>spring-boot-property-exp</module>
|
||||
<module>spring-boot-springdoc</module>
|
||||
<module>spring-boot-vue</module>
|
||||
<module>spring-cloud</module>
|
||||
<module>spring-cloud/spring-cloud-archaius/basic-config</module>
|
||||
|
@ -1467,8 +1469,9 @@
|
|||
<module>spring-boot-parent</module>
|
||||
<module>spring-boot-property-exp</module>
|
||||
<module>spring-boot-security</module>
|
||||
<module>spring-boot-springdoc</module>
|
||||
<module>spring-boot-vue</module>
|
||||
<module>spring-caching</module>
|
||||
<module>spring-caching</module>
|
||||
<module>spring-cloud</module>
|
||||
<module>spring-cloud-bus</module>
|
||||
<!-- <module>spring-cloud-cli</module> --> <!-- Not a maven project -->
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>spring-boot-springdoc</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>spring-boot-springdoc</name>
|
||||
<description>Project for Springdoc integration</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringDoc -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-core</artifactId>
|
||||
<version>1.1.45</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-ui</artifactId>
|
||||
<version>1.1.45</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>integration</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>2.1.8.RELEASE</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>pre-integration-test</id>
|
||||
<goals>
|
||||
<goal>start</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>post-integration-test</id>
|
||||
<goals>
|
||||
<goal>stop</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-maven-plugin</artifactId>
|
||||
<version>0.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>integration-test</phase>
|
||||
<goals>
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<apiDocsUrl>http://localhost:8080/api-docs</apiDocsUrl>
|
||||
<outputFileName>openapi.json</outputFileName>
|
||||
<outputDir>${project.build.directory}</outputDir>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
|
||||
</project>
|
|
@ -0,0 +1,13 @@
|
|||
package com.baeldung.springdoc;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringdocApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringdocApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.baeldung.springdoc.controller;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.baeldung.springdoc.exception.BookNotFoundException;
|
||||
import com.baeldung.springdoc.model.Book;
|
||||
import com.baeldung.springdoc.repository.BookRepository;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/book")
|
||||
public class BookController {
|
||||
|
||||
@Autowired
|
||||
private BookRepository repository;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public Book findById(@PathVariable long id) {
|
||||
return repository.findById(id)
|
||||
.orElseThrow(() -> new BookNotFoundException());
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public Collection<Book> findBooks() {
|
||||
return repository.getBooks();
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public Book updateBook(@PathVariable("id") final String id, @RequestBody final Book book) {
|
||||
return book;
|
||||
}
|
||||
|
||||
@PatchMapping("/{id}")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public Book patchBook(@PathVariable("id") final String id, @RequestBody final Book book) {
|
||||
return book;
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
public Book postBook(@NotNull @Valid @RequestBody final Book book) {
|
||||
return book;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.HEAD, value = "/")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public Book headBook() {
|
||||
return new Book();
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public long deleteBook(@PathVariable final long id) {
|
||||
return id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.baeldung.springdoc.exception;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class BookNotFoundException extends RuntimeException {
|
||||
|
||||
public BookNotFoundException() {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.springdoc.exception;
|
||||
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class GlobalControllerExceptionHandler {
|
||||
|
||||
@ExceptionHandler(ConversionFailedException.class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public ResponseEntity<String> handleConnversion(RuntimeException ex) {
|
||||
return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@ExceptionHandler(BookNotFoundException.class)
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
public ResponseEntity<String> handleBookNotFound(RuntimeException ex) {
|
||||
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.baeldung.springdoc.model;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
public class Book {
|
||||
|
||||
private long id;
|
||||
|
||||
@NotBlank
|
||||
@Size(min = 0, max = 20)
|
||||
private String title;
|
||||
|
||||
@NotBlank
|
||||
@Size(min = 0, max = 30)
|
||||
private String author;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.baeldung.springdoc.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.baeldung.springdoc.model.Book;
|
||||
|
||||
@Repository
|
||||
public class BookRepository {
|
||||
|
||||
private Map<Long, Book> books = new HashMap<>();
|
||||
|
||||
public Optional<Book> findById(long id) {
|
||||
return Optional.ofNullable(books.get(id));
|
||||
}
|
||||
|
||||
public void add(Book book) {
|
||||
books.put(book.getId(), book);
|
||||
}
|
||||
|
||||
public Collection<Book> getBooks() {
|
||||
return books.values();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
# custom path for swagger-ui
|
||||
springdoc.swagger-ui.path=/swagger-ui-custom.html
|
||||
|
||||
# custom path for api docs
|
||||
springdoc.api-docs.path=/api-docs
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework" level="DEBUG" />
|
||||
<logger name="org.springframework.transaction" level="WARN" />
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
|
@ -0,0 +1,17 @@
|
|||
package com.baeldung.springdoc;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class SpringContextIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue