/*
* Copyright 2015 the original author or authors.
*
* Licensed 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
*
* http://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.
*/
package ratpack.retrofit;
import com.google.common.base.Preconditions;
import ratpack.func.Action;
import ratpack.http.client.HttpClient;
import ratpack.retrofit.internal.RatpackCallAdapterFactory;
import ratpack.retrofit.internal.RatpackCallFactory;
import ratpack.retrofit.internal.ReceivedResponseConverterFactory;
import ratpack.util.Exceptions;
import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory;
import java.net.URI;
/**
* Builder for providing integration of Retrofit2 with Ratpack's {@link HttpClient}.
* <p>
* This class allows for creating declarative type-safe interfaces that represent remote HTTP APIs.
* Using this adapter allows for defining the interfaces to return {@link ratpack.exec.Promise} types which will be fulfilled by Ratpack's http client.
*
* <pre class="java">{@code
* import ratpack.exec.Promise;
* import ratpack.retrofit.RatpackRetrofit;
* import ratpack.test.embed.EmbeddedApp;
* import retrofit2.http.GET;
*
* import static org.junit.Assert.*;
*
* public class ExampleRetrofitClient {
*
* public interface HelloService {
*
* {@literal @}GET("hello") Promise<String> hello();
* }
*
* public static void main(String... args) throws Exception {
*
* EmbeddedApp api = EmbeddedApp.of(s -> s
* .handlers(chain -> chain
* .get("hello", ctx -> ctx.render("hello"))
* )
* );
* EmbeddedApp.of(s -> s
* .registryOf(r -> r
* .add(HelloService.class,
* RatpackRetrofit.client(api.getAddress()).build(HelloService.class)
* )
* )
* .handlers(chain -> {
* chain.get(ctx -> {
*
* ctx.render(ctx.get(HelloService.class).hello());
* });
* })
* ).test(testHttpClient -> {
* assertEquals("hello", testHttpClient.getText());
* api.close();
* });
* }
* }
* }</pre>
*
* @since 1.4
*/
public abstract class RatpackRetrofit {
/**
* Creates a new builder for creating Retrofit clients.
*
* @param endpoint the endpoint for client implementations.
* @return a client builder
*/
public static Builder client(URI endpoint) {
return new Builder(endpoint);
}
/**
* Creates a new builder for creating Retrofit clients.
*
* @param endpoint the endpoint for client implementations. Converted to {@link URI}.
* @return a client builder
*/
public static Builder client(String endpoint) {
return Exceptions.uncheck(() -> client(new URI(endpoint)));
}
public static class Builder {
private final URI uri;
private Action<? super Retrofit.Builder> builderAction = Action.noop();
private Builder(URI uri) {
Preconditions.checkNotNull(uri, "Must provide the base uri.");
this.uri = uri;
}
/**
* Configure the underlying {@link retrofit2.Retrofit.Builder} instance.
* <p>
* This is used to customize the behavior of Retrofit.
*
* @param builderAction the actions to apply to the Retrofit builder
* @return this
* @see retrofit2.Converter.Factory
* @see retrofit2.CallAdapter.Factory
*/
public Builder configure(Action<? super Retrofit.Builder> builderAction) {
this.builderAction = builderAction;
return this;
}
/**
* Creates the underlying {@link Retrofit} instance and configures it to interface with {@link HttpClient} and {@link ratpack.exec.Promise}.
* <p>
* The resulting Retrofit instance can be re-used to generate multiple client interfaces which share the same base URI.
* @return the Retrofit instance to create client interfaces
*/
public Retrofit retrofit() {
Retrofit.Builder builder = new Retrofit.Builder()
.callFactory(RatpackCallFactory.INSTANCE)
.addCallAdapterFactory(RatpackCallAdapterFactory.INSTANCE)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(ReceivedResponseConverterFactory.INSTANCE);
builder.baseUrl(uri.toString());
Exceptions.uncheck(() -> builderAction.execute(builder));
return builder.build();
}
/**
* Uses this builder to create a Retrofit client implementation.
* <p>
* This is the short form of calling {@code client.retrofit().build(service)}.
*
* @param service the client interface to generate.
* @param <T> the type of the client interface.
* @return a generated instance of the client interface.
*/
public <T> T build(Class<T> service) {
return retrofit().create(service);
}
}
}