Groovy / Maven

Micronaut HTTP Client

Learn how to use Micronaut low-level HTTP Client. Simplify your code with the declarative HTTP client.

Sergio del Amo, Iván López
On this guide
In this section

Getting Started

In this guide, we will create a Micronaut application written in Groovy to consume the GitHub API with the Micronaut HTTP Client.

What you will need

To complete this guide, you will need the following:

Solution

We recommend that you follow the instructions in the next sections and create the application step by step. However, you can go right to the completed example.

Writing the Application

Create an application using the Micronaut Command Line Interface or with Micronaut Launch.

mn create-app example.micronaut.micronautguide \
    --features=http-client \
    --build=maven \
    --lang=groovy \
    --test=spock
Note
If you don’t specify the --build argument, Gradle with the Kotlin DSL is used as the build tool.
If you don’t specify the --lang argument, Java is used as the language.
If you don’t specify the --test argument, JUnit is used for Java and Kotlin, and Spock is used for Groovy.

The previous command creates a Micronaut application with the default package example.micronaut in a directory named micronautguide.

If you use Micronaut Launch, select Micronaut Application as application type and add http-client features.

Note
If you have an existing Micronaut application and want to add the functionality described here, you can view the dependency and configuration changes from the specified features, and apply those changes to your application.

Dependency

To use the Micronaut HTTP Client based on Netty, add the following dependency:

pom.xml
<dependency>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-http-client</artifactId>
    <scope>compile</scope>
</dependency>

To use the Micronaut HTTP Client based on Java HTTP Client, add the following dependency:

pom.xml
<dependency>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-http-client-jdk</artifactId>
    <scope>compile</scope>
</dependency>

GitHub API

In this guide, you will consume the GitHub API from a Micronaut application.

In this guide, you will fetch Micronaut Core releases via the List releases endpoint.

This returns a list of releases, which does not include regular Git tags that have not been associated with a release.

This API resource can be consumed by both authenticated and anonymous clients. Initially, you will consume it anonymously, later we will discuss authentication.

Create a record to parse the JSON response into an object:

groovy/src/main/groovy/example/micronaut/GithubRelease.groovy
package example.micronaut

import groovy.transform.CompileStatic
import io.micronaut.serde.annotation.Serdeable

@Serdeable
@CompileStatic
class GithubRelease {
    String name
    String url
}

Configuration

Modify src/main/resources/application.properties to create some configuration parameters.

src/main/resources/application.properties
github.organization=micronaut-projects
github.repo=micronaut-core

To encapsulate type-safe configuration retrieval, we use a @ConfigurationProperties object:

groovy/src/main/groovy/example/micronaut/GithubConfiguration.groovy
package example.micronaut

import io.micronaut.context.annotation.ConfigurationProperties
import io.micronaut.context.annotation.Requires
import io.micronaut.core.annotation.Nullable

@ConfigurationProperties(GithubConfiguration.PREFIX)
@Requires(property = GithubConfiguration.PREFIX)
class GithubConfiguration {
    public static final String PREFIX = "github"

    String organization

    String repo

    @Nullable
    String username

    @Nullable
    String token
}

JSON Codec Configuration

Add configuration to treat application/vnd.github.v3+json as JSON.

src/main/resources/application.properties
micronaut.codec.json.additional-types[0]=application/vnd.github.v3+json

HTTP Client Service Configuration

Add configuration to associate a service identifier to the GitHub API URL.

src/main/resources/application.properties
micronaut.http.services.github.url=https://api.github.com

Low Level Client

Initially, you will create a Bean which uses the low-level Client API.

Create GithubLowLevelClient:

groovy/src/main/groovy/example/micronaut/GithubLowLevelClient.groovy

Declarative Client

It is time to take a look at support for declarative clients via the Client annotation.

Create GithubApiClient which clearly illustrates how a declarative Micronaut HTTP Client, which is generated at compile-time, simplifies our code.

groovy/src/main/groovy/example/micronaut/GithubApiClient.groovy

Controller

Create a Controller. It uses both (low-level and declarative clients). The Micronaut framework supports Reactive Streams implementations such as RxJava or Project Reactor. Thus, you can efficiently compose multiple HTTP client calls without blocking (which will limit the throughput and scalability of your application).

groovy/src/main/groovy/example/micronaut/GithubController.groovy

Tests

We will mock the GitHub API with some releases

Note
Here we only show a single release. You can add more entries to the file if you want to test with multiple releases.
src/test/resources/single-release.json
[{"url":"https://api.github.com/repos/micronaut-projects/micronaut-core/releases/91622014","assets_url":"https://api.github.com/repos/micronaut-projects/micronaut-core/releases/91622014/assets","upload_url":"https://uploads.github.com/repos/micronaut-projects/micronaut-core/releases/91622014/assets{?name,label}","html_url":"https://github.com/micronaut-projects/micronaut-core/releases/tag/v3.8.4","id":91622014,"author":{"login":"sdelamo","id":864788,"node_id":"MDQ6VXNlcjg2NDc4OA==","avatar_url":"https://avatars.githubusercontent.com/u/864788?v=4","gravatar_id":"","url":"https://api.github.com/users/sdelamo","html_url":"https://github.com/sdelamo","followers_url":"https://api.github.com/users/sdelamo/followers","following_url":"https://api.github.com/users/sdelamo/following{/other_user}","gists_url":"https://api.github.com/users/sdelamo/gists{/gist_id}","starred_url":"https://api.github.com/users/sdelamo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sdelamo/subscriptions","organizations_url":"https://api.github.com/users/sdelamo/orgs","repos_url":"https://api.github.com/users/sdelamo/repos","events_url":"https://api.github.com/users/sdelamo/events{/privacy}","received_events_url":"https://api.github.com/users/sdelamo/received_events","type":"User","site_admin":false},"node_id":"RE_kwDOB2eaPM4Fdgp-","tag_name":"v3.8.4","target_commitish":"3.8.x","name":"Micronaut Framework 3.8.4","draft":false,"prerelease":false,"created_at":"2023-02-07T15:53:03Z","published_at":"2023-02-07T15:53:05Z","assets":[{"url":"https://api.github.com/repos/micronaut-projects/micronaut-core/releases/assets/94667997","id":94667997,"node_id":"RA_kwDOB2eaPM4FpITd","name":"artifacts.zip","label":"","uploader":{"login":"github-actions[bot]","id":41898282,"node_id":"MDM6Qm90NDE4OTgyODI=","avatar_url":"https://avatars.githubusercontent.com/in/15368?v=4","gravatar_id":"","url":"https://api.github.com/users/github-actions%5Bbot%5D","html_url":"https://github.com/apps/github-actions","followers_url":"https://api.github.com/users/github-actions%5Bbot%5D/followers","following_url":"https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github-actions%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/github-actions%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/github-actions%5Bbot%5D/repos","events_url":"https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/github-actions%5Bbot%5D/received_events","type":"Bot","site_admin":false},"content_type":"application/zip","state":"uploaded","size":28063979,"download_count":33,"created_at":"2023-02-07T16:18:05Z","updated_at":"2023-02-07T16:18:06Z","browser_download_url":"https://github.com/micronaut-projects/micronaut-core/releases/download/v3.8.4/artifacts.zip"},{"url":"https://api.github.com/repos/micronaut-projects/micronaut-core/releases/assets/94669478","id":94669478,"node_id":"RA_kwDOB2eaPM4FpIqm","name":"multiple.intoto.jsonl","label":"","uploader":{"login":"github-actions[bot]","id":41898282,"node_id":"MDM6Qm90NDE4OTgyODI=","avatar_url":"https://avatars.githubusercontent.com/in/15368?v=4","gravatar_id":"","url":"https://api.github.com/users/github-actions%5Bbot%5D","html_url":"https://github.com/apps/github-actions","followers_url":"https://api.github.com/users/github-actions%5Bbot%5D/followers","following_url":"https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}","gists_url":"https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}","starred_url":"https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/github-actions%5Bbot%5D/subscriptions","organizations_url":"https://api.github.com/users/github-actions%5Bbot%5D/orgs","repos_url":"https://api.github.com/users/github-actions%5Bbot%5D/repos","events_url":"https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}","received_events_url":"https://api.github.com/users/github-actions%5Bbot%5D/received_events","type":"Bot","site_admin":false},"content_type":"application/octet-stream","state":"uploaded","size":65612,"download_count":34,"created_at":"2023-02-07T16:32:49Z","updated_at":"2023-02-07T16:32:49Z","browser_download_url":"https://github.com/micronaut-projects/micronaut-core/releases/download/v3.8.4/multiple.intoto.jsonl"}],"tarball_url":"https://api.github.com/repos/micronaut-projects/micronaut-core/tarball/v3.8.4","zipball_url":"https://api.github.com/repos/micronaut-projects/micronaut-core/zipball/v3.8.4","body":"<!-- Release notes generated using configuration in .github/release.yml at 3.8.x -->\r\n\r\n\r\n## What's Changed\r\n\r\n### Bugs 🐛\r\n* Allow programmatic logback config if xml config is absent (#8674)\r\n* Tweak uri to account for WebLogic/Windows URIs by @mattmoss in https://github.com/micronaut-projects/micronaut-core/pull/8704\r\n\r\n### Docs 📖\r\n* Docs on self-signed cert setup (#8684)\r\n\r\n### Dependency Upgrades 🚀\r\n\r\n* Micronaut Test to 3.8.2 (#8728)\r\n* Micronaut OpenAPI to 4.8.3 (#8724)\r\n* Micronaut Data to 3.9.6 (#8711)\r\n* Micronaut Rabbit to 3.4.1 (#8709)\r\n* Micronaut Azure to 3.7.1 (#8682)\r\n* Micronaut Micrometer to 4.7.2 (#8681)\r\n\r\n### Tests ✅\r\n\r\n* Require docker for test (#8698)\r\n* Add octet stream serialization to the TCK (#8712)\r\n\r\n**Full Changelog**: https://github.com/micronaut-projects/micronaut-core/compare/v3.8.3...v3.8.4","mentions_count":1}]

Create a test to verify that both clients work as expected, and the controller echoes the output of the GitHub API in a Reactive way.

groovy/src/test/groovy/example/micronaut/GithubControllerSpec.groovy

Testing the Application

To run the tests:

./mvnw test

HTTP Client Filter

Often, you need to include the same HTTP headers or URL parameters in a set of requests against a third-party API or when calling another Microservice. To simplify this, the Micronaut framework includes the ability to define HttpClientFilter classes that are applied to all matching HTTP clients.

For a real world example, let us provide GitHub Authentication via an HttpClientFilter. Follow the steps in to create your own Personal Token. Then you can use those credentials to access the GitHub API using Basic Auth.

Create a Filter:

groovy/src/main/groovy/example/micronaut/GithubFilter.groovy

Configuration Parameters

Add your GitHub username and token to src/main/resources/application.properties

github.organization=micronaut-projects
github.repo=micronaut-core
github.username=yourgithubusername
github.token=xxxxxxxxxxxx

Add a logger to src/main/resources/logback.xml to see the HTTP client output.

<logger name="io.micronaut.http.client" level="TRACE"/>

If you run again the tests, you will see the that the Filter is invoked and HTTP Basic Auth is used against GitHub API.

13:09:56.662 [default-nioEventLoopGroup-1-4] DEBUG i.m.h.client.netty.DefaultHttpClient - Sending HTTP GET to https://api.github.com/repos/micronaut-projects/micronaut-core/releases
13:09:56.663 [default-nioEventLoopGroup-1-4] TRACE i.m.h.client.netty.DefaultHttpClient - User-Agent: Micronaut HTTP Client
13:09:56.663 [default-nioEventLoopGroup-1-4] TRACE i.m.h.client.netty.DefaultHttpClient - Accept: application/json
13:09:56.663 [default-nioEventLoopGroup-1-4] TRACE i.m.h.client.netty.DefaultHttpClient - Authorization: MASKED
13:09:56.664 [default-nioEventLoopGroup-1-4] TRACE i.m.h.client.netty.DefaultHttpClient - host: api.github.com

Next Steps

Help with the Micronaut Framework

The Micronaut Foundation sponsored the creation of this Guide. A variety of consulting and support services are available.

License

Note
All guides are released with an Apache License 2.0 for the code and a Creative Commons Attribution 4.0 license for the writing and media (images).