Controllers and routes
A controller is a class that accepts HTTP requests and returns responses. Each of its methods serves one route: a combination of an HTTP method (GET, POST, DELETE…) and an address. Micronaut finds controllers by itself: the annotation processor records all routes at compile time, so no registration is needed.
The first controller
Create the file by hand or with mn create-controller com.example.Hello (it also creates a test stub):
// src/main/java/com/example/HelloController.java
package com.example;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Produces;
@Controller("/hello")
public class HelloController {
@Get
@Produces(MediaType.TEXT_PLAIN)
public String index() {
return "Hello, Micronaut!";
}
}@Controller("/hello") sets the class's base address, and @Get without an argument is a route on that address itself. @Produces(MediaType.TEXT_PLAIN) says the response is plain text: by default Micronaut answers in JSON.
curl -i http://localhost:8080/helloHTTP/1.1 200 OK
content-type: text/plain
Hello, Micronaut!Parts of the address
A fragment in curly braces is a path variable. Its value arrives in the method parameter with the same name:
// src/main/java/com/example/HelloController.java
@Get("/{name}")
@Produces(MediaType.TEXT_PLAIN)
public String greet(String name) {
return "Hello, " + name + "!";
}The request curl http://localhost:8080/hello/Anna returns Hello, Anna!.
The article controller
Let's start the blog's main controller. For now it returns text; data arrives in the next lessons:
// src/main/java/com/example/ArticleController.java
package com.example;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Delete;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Produces;
@Controller("/articles")
@Produces(MediaType.TEXT_PLAIN)
public class ArticleController {
@Get
public String list() {
return "All articles";
}
@Get("/{id}")
public String show(Long id) {
return "Article " + id;
}
@Delete("/{id}")
public HttpResponse<Void> delete(Long id) {
return HttpResponse.noContent();
}
}@Produces on the class applies to all methods. HttpResponse.noContent() returns an empty response with status 204. Check it:
curl http://localhost:8080/articles/5
curl -i -X DELETE http://localhost:8080/articles/5The first command prints Article 5, the second prints HTTP/1.1 204 No Content.
Method annotations
| Annotation | HTTP method | Typical action |
|---|---|---|
@Get | GET | Read data |
@Post | POST | Create a record |
@Put | PUT | Replace a record |
@Patch | PATCH | Change part of a record |
@Delete | DELETE | Delete a record |
They all live in the io.micronaut.http.annotation package.
Common mistake
If you send a request with a method that has no route, Micronaut answers 405 and tells you which methods are allowed:
curl -i -X POST http://localhost:8080/articlesHTTP/1.1 405 Method Not Allowed
allow: HEAD,GET
{"_links":{"self":[{"href":"/articles","templated":false}]},"_embedded":{"errors":[{"message":"Method [POST] not allowed for URI [/articles]. Allowed methods: [HEAD, GET]"}]},"message":"Method Not Allowed"}Check that the method carries the right HTTP method annotation, and that the address in @Controller plus the one in the method annotation add up to the path you are calling.