I realized that I need to learn more on Spring Boot/Spring REST and integration testing stuff. Here it goes!
Let us remember:
Spring Boot project aims at making it easier to build Spring applications by eliminating the need for extensive configuration. With default settings, you can feel magic tricks like implementing your interface behind the scenes etc.
About
REST: Have you ever worked with SOAP? How did it feel? For me, it always felt like something wrong was going on. Something simpler is needed. Then I was able to see in practice that REST services offer cleaner solutions and with the great capabilities of Java platform and Spring, you have a far better structure.
HTTP is the Platform
You describe the relationships using URIs. For example, you access the Bookmark's of a User with:
/alice/bookmarks
Clients and services agree upon a mutually understood data representation. So we send HTTP GET/POST/DELETE requests. There is usually a
status code about the result of the operation.
Example: Status code 404: Your request is incorrect.
With Spring, you implement a rest controller:
@RestController
@RequestMapping("/{userId}/bookmarks")
class BookmarkRestController {
private final BookmarkRepository bookmarkRepository;
private final AccountRepository accountRepository;
@Autowired
BookmarkRestController(BookmarkRepository bookmarkRepository,
AccountRepository accountRepository) {
this.bookmarkRepository = bookmarkRepository;
this.accountRepository = accountRepository;
}
@RequestMapping(method = RequestMethod.GET)
Collection readBookmarks(@PathVariable String userId) {
this.validateUser(userId);
return this.bookmarkRepository.findByAccountUsername(userId);
}
...
}
@RestController exposes the annotated bean’s methods as HTTP endpoints
Controller methods return simple POJOs - Collection, and Bookmark, etc. When an HTTP request comes in that specifies an Accept header, Spring MVC loops through the configured HttpMessageConverter until it finds one that can convert from the POJO domain model types into the content-type specified in the Accept header, if so configured. Spring Boot automatically wires up an HttpMessageConverter that can convert generic Object s to JSON, absent any more specific converter. HttpMessageConverter s work in both directions: incoming requests bodies are converted to Java objects, and Java objects are converted into HTTP response bodies.
Testing a REST Service
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@WebAppConfiguration
public class BookmarkRestControllerTest {
private MockMvc mockMvc;
private Account account;
private List bookmarkList = new ArrayList<>();
@Autowired
private BookmarkRepository bookmarkRepository;
@Autowired
private WebApplicationContext webApplicationContext;
@Autowired
private AccountRepository accountRepository;
@Test
public void userNotFound() throws Exception {
mockMvc.perform(post("/george/bookmarks/")
.content(this.json(new Bookmark()))
.contentType(contentType))
.andExpect(status().isNotFound());
}
@Test
public void readSingleBookmark() throws Exception {
mockMvc.perform(get("/" + userName + "/bookmarks/"
+ this.bookmarkList.get(0).getId()))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.id", is(this.bookmarkList.get(0).getId().intValue())))
.andExpect(jsonPath("$.uri", is("http://bookmark.com/1/" + userName)))
.andExpect(jsonPath("$.description", is("A description")));
}
...
}
Using Spring REST with Vaadin
@Theme("valo")
@SpringUIpublic class MyVaadinSpringUI extends UI {
@Autowired MyRestController myRestController;
@Override protected void init(VaadinRequest vaadinRequest) {
VerticalLayout verticalLayout = new VerticalLayout();
Button button = new Button("Invoke controller");
button.addClickListener(new Button.ClickListener() {
@Override public void buttonClick(Button.ClickEvent clickEvent) {
int result = myRestController.readBookmarks();
Notification.show("");
Notification notification = new Notification(String.valueOf(result));
notification.setDelayMsec(40000);
notification.show(Page.getCurrent());
}
});
verticalLayout.addComponent(button);
setContent(verticalLayout);
}
@WebListener public static class SpringContextLoaderListener extends ContextLoaderListener {
}
@Configuration @EnableVaadin @EnableVaadinNavigation public static class SpringConfiguration {
}
@WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
@VaadinServletConfiguration(ui = MyVaadinSpringUI.class, productionMode = false)
public static class MyUIServlet extends SpringVaadinServlet {
}
}
@RestController@RequestMapping("/hello")
class MyRestController {
@RequestMapping(method = RequestMethod.GET)
int readMyNumber() {
return 100;
}
Comments