BAEL-6751 - reactive apis with micronaut (#14824)
* BAEL-6751 - reactive apis with micronaut * BAEL-6751 - reactive apis with micronaut * BAEL-6751 - added error handling * BAEL-6751 - removed unused property * BAEL-6751 - formatting changes * BAEL-6751 - added missing class * BAEL-6751 - moving module to parent pom * BAEL-6751 - moving version number to property
This commit is contained in:
+10
@@ -0,0 +1,10 @@
|
||||
package com.baeldung.micronautreactive;
|
||||
|
||||
import io.micronaut.runtime.Micronaut;
|
||||
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Micronaut.run(Application.class, args);
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package com.baeldung.micronautreactive.controller;
|
||||
|
||||
import com.baeldung.micronautreactive.dtos.BookNotFoundException;
|
||||
import com.baeldung.micronautreactive.entity.Book;
|
||||
import com.baeldung.micronautreactive.service.BookService;
|
||||
import io.micronaut.core.annotation.Nullable;
|
||||
import io.micronaut.http.HttpResponse;
|
||||
import io.micronaut.http.MutableHttpResponse;
|
||||
import io.micronaut.http.annotation.Error;
|
||||
import io.micronaut.http.annotation.*;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import jakarta.validation.Valid;
|
||||
import org.bson.types.ObjectId;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
@Controller("/books")
|
||||
public class BookController {
|
||||
|
||||
private final BookService bookService;
|
||||
|
||||
public BookController(BookService bookService) {
|
||||
this.bookService = bookService;
|
||||
}
|
||||
|
||||
@Post
|
||||
public String createBook(@Valid @Body Book book) {
|
||||
@Nullable ObjectId bookId = bookService.save(book);
|
||||
if (null == bookId) {
|
||||
return "Book not created";
|
||||
} else {
|
||||
return "Book created with id: " + bookId;
|
||||
}
|
||||
}
|
||||
|
||||
@Put
|
||||
public String updateBook(@Valid @Body Book book) {
|
||||
@Nullable ObjectId bookId = bookService.update(book);
|
||||
if (null == bookId) {
|
||||
return "Book not updated";
|
||||
} else {
|
||||
return "Book updated with id: " + bookId;
|
||||
}
|
||||
}
|
||||
|
||||
@Delete("/{id}")
|
||||
public String deleteBook(String id) throws BookNotFoundException {
|
||||
Long bookId = bookService.deleteById(id);
|
||||
if (1 == bookId) {
|
||||
return "Book deleted";
|
||||
} else {
|
||||
throw new BookNotFoundException(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Get("/{id}")
|
||||
public Book findById(@PathVariable("id") String identifier) throws BookNotFoundException {
|
||||
Book book = bookService.findById(identifier);
|
||||
if (null == book) {
|
||||
throw new BookNotFoundException(identifier);
|
||||
} else {
|
||||
return book;
|
||||
}
|
||||
}
|
||||
|
||||
@Get("/published-after")
|
||||
public Flux<Book> findByYearGreaterThan(@QueryValue(value = "year") int year) {
|
||||
return bookService.findByYearGreaterThan(year);
|
||||
}
|
||||
|
||||
@Error(exception = ConstraintViolationException.class)
|
||||
public MutableHttpResponse<String> onSavedFailed(ConstraintViolationException ex) {
|
||||
return HttpResponse.badRequest(ex.getConstraintViolations().stream()
|
||||
.map(cv -> cv.getPropertyPath() + " " + cv.getMessage())
|
||||
.toList().toString());
|
||||
}
|
||||
|
||||
@Error(exception = BookNotFoundException.class)
|
||||
public HttpResponse<String> onSavedFailed(BookNotFoundException ex) {
|
||||
return HttpResponse.notFound(ex.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.baeldung.micronautreactive.dtos;
|
||||
|
||||
public class BookNotFoundException extends Exception {
|
||||
public BookNotFoundException(String id) {
|
||||
super("Book with id " + id + " not found");
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.baeldung.micronautreactive.entity;
|
||||
|
||||
import io.micronaut.core.annotation.Introspected;
|
||||
import io.micronaut.serde.annotation.Serdeable;
|
||||
|
||||
@Serdeable
|
||||
public class Author {
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
|
||||
public Author() {
|
||||
}
|
||||
|
||||
public Author(String firstName, String lastName) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.baeldung.micronautreactive.entity;
|
||||
|
||||
import io.micronaut.core.annotation.Generated;
|
||||
import io.micronaut.core.annotation.Nullable;
|
||||
import io.micronaut.data.annotation.Id;
|
||||
import io.micronaut.data.annotation.MappedEntity;
|
||||
import io.micronaut.serde.annotation.Serdeable;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
@Serdeable
|
||||
@MappedEntity
|
||||
public class Book {
|
||||
@Id
|
||||
@Generated
|
||||
private @Nullable ObjectId id;
|
||||
@NotBlank
|
||||
private String title;
|
||||
|
||||
@NotNull
|
||||
private Author author;
|
||||
private int year;
|
||||
|
||||
public Book() {
|
||||
}
|
||||
|
||||
public Book(@Nullable ObjectId id, String title, Author author, int year) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.year = year;
|
||||
}
|
||||
|
||||
public Book(String title, Author author, int year) {
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.year = year;
|
||||
}
|
||||
|
||||
public @Nullable ObjectId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(@Nullable ObjectId id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Author getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(Author author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public int getYear() {
|
||||
return year;
|
||||
}
|
||||
|
||||
public void setYear(int year) {
|
||||
this.year = year;
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.baeldung.micronautreactive.repository;
|
||||
|
||||
import com.baeldung.micronautreactive.entity.Book;
|
||||
import io.micronaut.context.annotation.Parameter;
|
||||
import io.micronaut.core.async.annotation.SingleResult;
|
||||
import io.micronaut.data.mongodb.annotation.MongoFindQuery;
|
||||
import io.micronaut.data.mongodb.annotation.MongoRepository;
|
||||
import io.micronaut.data.repository.reactive.ReactorCrudRepository;
|
||||
import org.bson.types.ObjectId;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
@MongoRepository
|
||||
public interface BookRepository extends ReactorCrudRepository<Book, ObjectId> {
|
||||
|
||||
@MongoFindQuery("{year: {$gt: :year}}")
|
||||
Flux<Book> findByYearGreaterThan(int year);
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.baeldung.micronautreactive.service;
|
||||
|
||||
import com.baeldung.micronautreactive.entity.Book;
|
||||
import com.baeldung.micronautreactive.repository.BookRepository;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.bson.types.ObjectId;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
@Singleton
|
||||
public class BookService {
|
||||
private final BookRepository bookRepository;
|
||||
|
||||
public BookService(BookRepository bookRepository) {
|
||||
this.bookRepository = bookRepository;
|
||||
}
|
||||
|
||||
public ObjectId save(Book book) {
|
||||
Book savedBook = bookRepository.save(book).block();
|
||||
return null != savedBook ? savedBook.getId() : null;
|
||||
}
|
||||
|
||||
public ObjectId update(Book book) {
|
||||
Book updatedBook = bookRepository.update(book).block();
|
||||
return null != updatedBook ? updatedBook.getId() : null;
|
||||
}
|
||||
|
||||
public Long deleteById(String id) {
|
||||
return bookRepository.deleteById(new ObjectId(id)).block();
|
||||
}
|
||||
|
||||
public Flux<Book> findByYearGreaterThan(int year) {
|
||||
return bookRepository.findByYearGreaterThan(year);
|
||||
}
|
||||
|
||||
public Book findById(String id) {
|
||||
return bookRepository.findById(new ObjectId(id)).block();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#Sun Aug 27 12:03:55 GMT 2023
|
||||
micronaut.application.name=micronaut-reactive
|
||||
mongodb.uri: mongodb://${MONGO_HOST:localhost}:${MONGO_PORT:27017}/someDb
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<!-- encoders are assigned the type
|
||||
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.micronautreactive;
|
||||
|
||||
import io.micronaut.runtime.EmbeddedApplication;
|
||||
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@MicronautTest(transactional = false)
|
||||
class MicronautReactiveTest {
|
||||
|
||||
@Inject
|
||||
EmbeddedApplication<?> application;
|
||||
|
||||
@Test
|
||||
void testItWorks() {
|
||||
Assertions.assertTrue(application.isRunning());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user