////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
////

Calling Grails REST services - as well as third-party services - is very straightforward using the https://docs.micronaut.io/latest/guide/index.html#httpClient[Micronaut HTTP Client]. This HTTP client has both a low-level API and a higher level AOP-driven API, making it useful for both simple requests as well as building declarative, type-safe API layers.

To use the Micronaut HTTP client you must have the `micronaut-http-client` and `micronaut-serde-jackson` dependencies on your classpath. Add the following dependency to your `build.gradle` file.

.build.gradle
[source,groovy]
----
implementation "io.micronaut:micronaut-http-client:4.6.6"
implementation "io.micronaut.serde:micronaut-serde-jackson:2.11.0"
----

==== Low-level API

The https://docs.micronaut.io/latest/api/io/micronaut/http/client/HttpClient.html[HttpClient] interface forms the basis for the low-level API. This interfaces declares methods to help ease executing HTTP requests and receive responses.

The majority of the methods in the `HttpClient` interface returns Reactive Streams Publisher instances, and a sub-interface called RxHttpClient is included that provides a variation of the HttpClient interface that returns RxJava Flowable types. When using `HttpClient` in a blocking flow, you may wish to call `toBlocking()` to return an instance of https://docs.micronaut.io/latest/api/io/micronaut/http/client/BlockingHttpClient.html[BlockingHttpClient].

There are a few ways by which you can obtain a reference to a https://docs.micronaut.io/latest/api/io/micronaut/http/client/HttpClient.html[HttpClient]. The most simple way is using the https://docs.micronaut.io/latest/api/io/micronaut/http/client/HttpClient.html#create-java.net.URL-[create] method

.Creating an HTTP client
[source, groovy]
----
    List<Album> searchWithApi(String searchTerm) {
        String baseUrl = "https://itunes.apple.com/"

        BlockingHttpClient client = HttpClient.create(baseUrl.toURL()).toBlocking() //<1>

        HttpRequest request = HttpRequest.GET("/search?limit=25&media=music&entity=album&term=${searchTerm}")
        HttpResponse<String> resp = client.exchange(request, String)
        client.close() //<2>

        String json = resp.body()
        ObjectMapper objectMapper = new ObjectMapper() //<3>
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        SearchResult searchResult = objectMapper.readValue(json, SearchResult)
        searchResult.results
    }
----
<1> Create a new instance of `HttpClient` with the `create` method, and convert to an instance of `BlockingHttpClient` with `toBlocking()`,
<2> The client should be closed using the `close` method to prevent thread leaking.
<3> Jackson's https://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/ObjectMapper.html[ObjectMapper] API can be used to map the raw JSON to POGOs, in this case `SearchResult`

Consult the https://docs.micronaut.io/latest/guide/index.html#lowLevelHttpClient[Http Client section] of the https://docs.micronaut.io/latest/guide/index.html[Micronaut user guide] for more information on using the `HttpClient` low-level API.

==== Declarative API

A declarative HTTP client can be written by adding the https://docs.micronaut.io/latest/api/io/micronaut/http/client/annotation/Client.html[`@Client`] annotation to any interface or abstract class. Using Micronaut's AOP support (see the Micronaut user guide section on https://docs.micronaut.io/latest/guide/index.html#introductionAdvice[Introduction Advice]), the abstract or interface methods will be implemented for you at compilation time as HTTP calls. Declarative clients can return data-bound POGOs (or POJOs) without requiring special handling from the calling code.

[source,groovy]
----
package example.grails

import io.micronaut.http.annotation.Get
import io.micronaut.http.client.annotation.Client


@Client("https://start.grails.org")
interface GrailsAppForgeClient {

    @Get("/{version}/profiles")
    List<Map> profiles(String version)
}

----

Note that HTTP client methods are annotated with the appropriate HTTP method, such as `@Get` or `@Post`.

To use a client like the one in the above example, simply inject an instance of the client into any bean using the `@Autowired` annotation.

[source,groovy]
----
  @Autowired GrailsAppForgeClient appForgeClient

    List<Map> profiles(String grailsVersion) {
        respond appForgeClient.profiles(grailsVersion)
    }
----

For more details on writing and using declarative clients, consult the https://docs.micronaut.io/latest/guide/index.html#clientAnnotation[Http Client section] of the https://docs.micronaut.io/latest/guide/index.html[Micronaut user guide].

==== Spring HTTP Interface Client

Spring Framework 7 can create an HTTP client from an interface annotated with `@HttpExchange` and `@GetExchange`. This is a Spring API, not a Grails DSL or a controller contract.

[source,java]
----
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.annotation.HttpExchange;

@HttpExchange("/books")
public interface BookClient {

    @GetExchange("/{id}")
    Book findById(@PathVariable Long id);
}
----

For a synchronous client, create a proxy with `RestClient`:

[source,java]
----
import org.springframework.web.client.RestClient;
import org.springframework.web.client.support.RestClientAdapter;
import org.springframework.web.service.invoker.HttpServiceProxyFactory;

RestClient restClient = RestClient.builder()
        .baseUrl("https://example.com")
        .build();
BookClient bookClient = HttpServiceProxyFactory
        .builderFor(RestClientAdapter.create(restClient))
        .build()
        .createClient(BookClient.class);
----

Spring 7 can also register the proxy as a bean. Group related interfaces and configure their shared `RestClient` builder:

[source,java]
----
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer;
import org.springframework.web.service.registry.HttpServiceGroup.ClientType;
import org.springframework.web.service.registry.ImportHttpServices;

@Configuration
@ImportHttpServices(group = "books", types = BookClient.class,
        clientType = ClientType.REST_CLIENT)
class BookClientConfiguration {

    @Bean
    RestClientHttpServiceGroupConfigurer bookClientConfigurer() {
        return groups -> groups.filterByName("books")
                .forEachClient((group, builder) -> builder.baseUrl("https://example.com"));
    }
}
----

The registered `BookClient` can then be constructor-injected into an application bean and called like any other interface. Synchronous methods can return a decoded body, `HttpHeaders`, or `ResponseEntity`.

For `Mono` or `Flux` return values, add Spring WebFlux to the classpath and use `WebClient` instead. Register the group with `clientType = ClientType.WEB_CLIENT` and configure it through `WebClientHttpServiceGroupConfigurer`; reactive applications also need Reactor types on the classpath.

HTTP interface parameters cannot be `null` unless the parameter is optional. By default, 4xx and 5xx responses raise an exception. Configure status handling on the underlying `RestClient` or `WebClient` when an API requires different behavior.
