2.4 Creating a Client
As mentioned previously, Micronaut includes both an HTTP server and an HTTP client. A low-level HTTP client is provided out of the box which you can use to test the HelloController
created in the previous section.
import io.micronaut.context.annotation.Property;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.client.HttpClient;
import io.micronaut.http.client.annotation.Client;
import io.micronaut.runtime.server.EmbeddedServer;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import static org.junit.jupiter.api.Assertions.assertEquals;
@MicronautTest
public class HelloControllerSpec {
@Inject
EmbeddedServer server; (1)
@Inject
@Client("/")
HttpClient client; (2)
@Test
void testHelloWorldResponse() {
String response = client.toBlocking() (3)
.retrieve(HttpRequest.GET("/hello"));
assertEquals("Hello World", response); //) (4)
}
}
import io.micronaut.http.HttpRequest
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.runtime.server.EmbeddedServer
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import spock.lang.Specification
import javax.inject.Inject
@MicronautTest
class HelloControllerSpec extends Specification {
@Inject
EmbeddedServer embeddedServer (1)
@Inject
@Client("/")
HttpClient client (2)
void "test hello world response"() {
expect:
client.toBlocking() (3)
.retrieve(HttpRequest.GET('/hello')) == "Hello World" (4)
}
}
import io.micronaut.context.annotation.Property
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.runtime.server.EmbeddedServer
import io.micronaut.test.annotation.MicronautTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import javax.inject.Inject
@MicronautTest
class HelloControllerSpec {
@Inject
lateinit var server: EmbeddedServer (1)
@Inject
@field:Client("/")
lateinit var client: HttpClient (2)
@Test
fun testHelloWorldResponse() {
val rsp: String = client.toBlocking() (3)
.retrieve("/hello")
assertEquals("Hello World", rsp) (4)
}
}
1 | The EmbeddedServer is configured as a shared test field |
2 | A HttpClient instance shared field is also defined |
3 | The test using the toBlocking() method to make a blocking call |
4 | The retrieve method returns the response of the controller as a String |
In addition to a low-level client, Micronaut features a declarative, compile-time HTTP client, powered by the Client annotation.
To create a client, simply create an interface annotated with @Client
. For example:
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.client.annotation.Client;
import io.reactivex.Single;
@Client("/hello") (1)
public interface HelloClient {
@Get(consumes = MediaType.TEXT_PLAIN) (2)
Single<String> hello(); (3)
}
import io.micronaut.http.annotation.Get
import io.micronaut.http.client.annotation.Client
import io.reactivex.Single
@Client("/hello") (1)
interface HelloClient {
@Get(consumes = MediaType.TEXT_PLAIN) (2)
Single<String> hello() (3)
}
import io.micronaut.http.MediaType
import io.micronaut.http.annotation.Get
import io.micronaut.http.client.annotation.Client
import io.reactivex.Single
@Client("/hello") (1)
interface HelloClient {
@Get(consumes = [MediaType.TEXT_PLAIN]) (2)
fun hello(): Single<String> (3)
}
1 | The @Client annotation is used with value that is a relative path to the current server |
2 | The same @Get annotation used on the server is used to define the client mapping |
3 | A RxJava Single is returned with the value read from the server |
To test the HelloClient
simply retrieve it from the ApplicationContext associated with the server:
import io.micronaut.test.annotation.MicronautTest;
import javax.inject.Inject;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@MicronautTest (1)
public class HelloClientSpec {
@Inject
HelloClient client; (2)
@Test
public void testHelloWorldResponse(){
assertEquals("Hello World", client.hello().blockingGet());(3)
}
}
import io.micronaut.test.annotation.MicronautTest
import spock.lang.Specification
import javax.inject.Inject
@MicronautTest (1)
class HelloClientSpec extends Specification {
@Inject HelloClient client (2)
void "test hello world response"() {
expect:
client.hello().blockingGet() == "Hello World" (3)
}
}
import io.micronaut.context.annotation.Property
import io.micronaut.test.annotation.MicronautTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import javax.inject.Inject
@MicronautTest (1)
class HelloClientSpec {
@Inject
lateinit var client: HelloClient (2)
@Test
fun testHelloWorldResponse() {
assertEquals("Hello World", client.hello().blockingGet())(3)
}
}
1 | The @MicronautTest annotation is used to define the test |
2 | The HelloClient is injected from the ApplicationContext |
3 | The client is invoked using RxJava’s blockingGet method |
The Client annotation produces an implementation automatically for you at compile time without the need to use proxies or runtime reflection.
The Client annotation is very flexible. See the section on the Micronaut HTTP Client for more information.