Skip to content

Commit

Permalink
Merge pull request #35 from the-gigi/main
Browse files Browse the repository at this point in the history
urlBase -> baseUrl + make some fields final
  • Loading branch information
sashirestela authored Jan 29, 2024
2 parents 65c2c8d + f1822e9 commit c71af09
Show file tree
Hide file tree
Showing 12 changed files with 115 additions and 89 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public interface PostService {

// Use CleverClient to call the API
var cleverClient = CleverClient.builder()
.urlBase("https://jsonplaceholder.typicode.com/")
.baseUrl("https://jsonplaceholder.typicode.com/")
.build();

var postService = cleverClient.create(PostService.class);
Expand Down Expand Up @@ -97,7 +97,7 @@ We have the following attributes to create a CleverClient object:

| Attribute | Description | Required |
| ----------- |----------------------------------------|-----------|
| urlBase | Api's url | mandatory |
| baseUrl | Api's url | mandatory |
| headers | Pairs of headers name/value | optional |
| httpClient | Java HttpClient object | optional |
| endOfStream | Text used to mark the final of streams | optional |
Expand All @@ -107,7 +107,7 @@ The attribute ```endOfStream``` is required when you have endpoints sending back
Example:

```java
final var URL_BASE = "https://api.example.com";
final var BASE_URL = "https://api.example.com";
final var HEADER_NAME = "Authorization";
final var HEADER_VALUE = "Bearer qwertyasdfghzxcvb";
final var END_OF_STREAM = "[DONE]";
Expand All @@ -121,7 +121,7 @@ var httpClient = HttpClient.newBuilder()
.build();

var cleverClient = CleverClient.builder()
.urlBase(URL_BASE)
.baseUrl(BASE_URL)
.headers(Arrays.asList(HEADER_NAME, HEADER_VALUE))
.httpClient(httpClient)
.endOfStream(END_OF_STREAM)
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>io.github.sashirestela</groupId>
<artifactId>cleverclient</artifactId>
<version>0.12.0</version>
<version>0.13.0</version>
<packaging>jar</packaging>

<name>cleverclient</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
public class BasicExample {

public static void main(String[] args) {
final var URL_BASE = "https://jsonplaceholder.typicode.com";
final var BASE_URL = "https://jsonplaceholder.typicode.com";

var cleverClient = CleverClient.builder()
.urlBase(URL_BASE)
.baseUrl(BASE_URL)
.build();
var postService = cleverClient.create(PostService.class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ static interface ImageService {
}

public static void main(String[] args) throws IOException {
final var URL_BASE = "https://via.placeholder.com";
final var BASE_URL = "https://via.placeholder.com";

var cleverClient = CleverClient.builder()
.urlBase(URL_BASE)
.baseUrl(BASE_URL)
.build();

var imageService = cleverClient.create(ImageService.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ static interface MethodHeaderService {
}

public static void main(String[] args) {
final var URL_BASE = "https://httpbin.org";
final var BASE_URL = "https://httpbin.org";

var cleverClient = CleverClient.builder()
.urlBase(URL_BASE)
.baseUrl(BASE_URL)
.build();

var classHeaderService = cleverClient.create(ClassHeaderService.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
public class MultiServiceExample {

public static void main(String[] args) {
final var URL_BASE = "https://jsonplaceholder.typicode.com";
final var BASE_URL = "https://jsonplaceholder.typicode.com";

var cleverClient = CleverClient.builder()
.urlBase(URL_BASE)
.baseUrl(BASE_URL)
.build();
var postService = cleverClient.create(PostService.class);
var albumService = cleverClient.create(AlbumService.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
public class StreamExample {

public static void main(String[] args) {
final var URL_BASE = "https://api.openai.com";
final var BASE_URL = "https://api.openai.com";
final var AUTHORIZATION_HEADER = "Authorization";
final var BEARER_AUTHORIZATION = "Bearer " + System.getenv("OPENAI_API_KEY");
final var END_OF_STREAM = "[DONE]";

var cleverClient = CleverClient.builder()
.urlBase(URL_BASE)
.baseUrl(BASE_URL)
.headers(Arrays.asList(AUTHORIZATION_HEADER, BEARER_AUTHORIZATION))
.endOfStream(END_OF_STREAM)
.build();
Expand Down
32 changes: 22 additions & 10 deletions src/main/java/io/github/sashirestela/cleverclient/CleverClient.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.github.sashirestela.cleverclient;

import static io.github.sashirestela.cleverclient.util.CommonUtil.isNullOrEmpty;

import java.net.http.HttpClient;
import java.util.List;
import java.util.Optional;
Expand All @@ -12,7 +14,6 @@
import io.github.sashirestela.cleverclient.support.CleverClientSSE;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;
import lombok.Singular;

/**
Expand All @@ -22,17 +23,25 @@
*/
@Getter
public class CleverClient {
private static Logger logger = LoggerFactory.getLogger(CleverClient.class);
private static final Logger logger = LoggerFactory.getLogger(CleverClient.class);

private String urlBase;
private List<String> headers;
private HttpClient httpClient;
private HttpProcessor httpProcessor;
private final String baseUrl;
@Deprecated
private final String urlBase = null;
private final List<String> headers;
private final HttpClient httpClient;
private final HttpProcessor httpProcessor;

/**
* Constructor to create an instance of CleverClient.
*
* @param urlBase Root of the url of the API service to call. Mandatory.
* @param baseUrl Root of the url of the API service to call.
* at least one of baseUrl and the deprecated urlBase is mandatory.
* in case both are specified and different baseUrl takes precedence
*
* @param urlBase [[ Deprecated ]] Root of the url of the API service to call.
* it is here for backward compatibility only. It will be removed in
* a future version. use `baseUrl()` instead.
* @param headers Http headers for all the API service. Header's name and
* value must be individual entries in the list. Optional.
* @param httpClient Custom Java's HttpClient component. One is created by
Expand All @@ -41,16 +50,19 @@ public class CleverClient {
* server sent events (SSE). Optional.
*/
@Builder
public CleverClient(@NonNull String urlBase, @Singular List<String> headers, HttpClient httpClient,
public CleverClient(String baseUrl, String urlBase, @Singular List<String> headers, HttpClient httpClient,
String endOfStream) {
this.urlBase = urlBase;
if (isNullOrEmpty(baseUrl) && isNullOrEmpty(urlBase)) {
throw new CleverClientException("At least one of baseUrl and urlBase is mandatory.", null, null);
}
this.baseUrl = isNullOrEmpty(baseUrl) ? urlBase : baseUrl;
this.headers = Optional.ofNullable(headers).orElse(List.of());
if (this.headers.size() % 2 > 0) {
throw new CleverClientException("Headers must be entered as pair of values in the list.", null, null);
}
this.httpClient = Optional.ofNullable(httpClient).orElse(HttpClient.newHttpClient());
CleverClientSSE.setEndOfStream(endOfStream);
this.httpProcessor = new HttpProcessor(this.urlBase, this.headers, this.httpClient);
this.httpProcessor = new HttpProcessor(this.baseUrl, this.headers, this.httpClient);
logger.debug("CleverClient has been created.");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@
public class HttpProcessor implements InvocationHandler {
private static final Logger logger = LoggerFactory.getLogger(HttpProcessor.class);

private HttpClient httpClient;
private String urlBase;
private List<String> headers;
private final HttpClient httpClient;
private final String baseUrl;
private final List<String> headers;

/**
* Constructor to create an instance of HttpProcessor.
*
* @param httpClient Java's HttpClient component that solves the http calling.
* @param urlBase Root of the url of the API service to call.
* @param baseUrl Root of the url of the API service to call.
* @param headers Http headers for all the API service.
*/
public HttpProcessor(String urlBase, List<String> headers, HttpClient httpClient) {
this.urlBase = urlBase;
public HttpProcessor(String baseUrl, List<String> headers, HttpClient httpClient) {
this.baseUrl = baseUrl;
this.headers = headers;
this.httpClient = httpClient;
}
Expand Down Expand Up @@ -93,7 +93,7 @@ public Object invoke(Object proxy, Method method, Object[] arguments) throws Thr
/**
* Reads the interface method metadata from memory and uses them to prepare an
* HttpConnector object that will resend the request to the Java's HttpClient
* and will receive the response. This method is called from the invoke mehod.
* and will receive the response. This method is called from the invoke method.
*
* @param method The Method instance corresponding to the interface method
* invoked on the proxy instance.
Expand All @@ -106,7 +106,7 @@ private Object resolve(Method method, Object[] arguments) {
var interfaceMetadata = InterfaceMetadataStore.one().get(method.getDeclaringClass());
var methodMetadata = interfaceMetadata.getMethodBySignature().get(method.toString());
var urlMethod = interfaceMetadata.getFullUrlByMethod(methodMetadata);
var url = urlBase + URLBuilder.one().build(urlMethod, methodMetadata, arguments);
var url = baseUrl + URLBuilder.one().build(urlMethod, methodMetadata, arguments);
var httpMethod = methodMetadata.getHttpAnnotationName();
var returnType = methodMetadata.getReturnType();
var isMultipart = methodMetadata.isMultipart();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public InterfaceMetadata get(Class<?> interfaceClass) {
if (interfacesByFullName.containsKey(interfaceClass.getName())) {
return interfacesByFullName.get(interfaceClass.getName());
} else {
throw new CleverClientException("The interaface {0} has not been saved yet.", interfaceClass.getSimpleName(),
throw new CleverClientException("The interface {0} has not been saved yet.", interfaceClass.getSimpleName(),
null);
}
}
Expand Down Expand Up @@ -125,7 +125,7 @@ private void validate(InterfaceMetadata interfaceMetadata) {
interfaceMetadata.getMethodBySignature().forEach((methodSignature, methodMetadata) -> {
if (!methodMetadata.isDefault()) {
if (!methodMetadata.hasHttpAnnotation()) {
throw new CleverClientException("Missing HTTP anotation for the method {0}.",
throw new CleverClientException("Missing HTTP annotation for the method {0}.",
methodMetadata.getName(), null);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.net.http.HttpClient;
import java.util.List;
Expand All @@ -16,53 +15,69 @@

class CleverClientTest {

@Test
void shouldSetPropertiesToDefaultValuesWhenBuilderIsCalledWithoutThoseProperties() {
var cleverClient = CleverClient.builder()
.urlBase("https://test")
.build();
assertEquals(List.of(), cleverClient.getHeaders());
assertEquals(HttpClient.Version.HTTP_2, cleverClient.getHttpClient().version());
assertNotNull(cleverClient.getUrlBase());
assertNotNull(cleverClient.getHttpProcessor());
}

@Test
void shouldImplementInterfaceWhenCallingCreate() {
var cleverClient = CleverClient.builder()
.urlBase("https://test")
.header("headerName")
.header("headerValue")
.httpClient(HttpClient.newHttpClient())
.endOfStream("[DONE]")
.build();
var test = cleverClient.create(TestCleverClient.class);
assertNotNull(test);
}
@Test
void shouldSetPropertiesToDefaultValuesWhenBuilderIsCalledWithoutThoseProperties() {
var cleverClient = CleverClient.builder()
.baseUrl("https://test")
.build();
assertEquals(List.of(), cleverClient.getHeaders());
assertEquals(HttpClient.Version.HTTP_2, cleverClient.getHttpClient().version());
assertNotNull(cleverClient.getBaseUrl());
assertNotNull(cleverClient.getHttpProcessor());
}

@Test
void shouldThrownExceptionWhenTryingToPassAnEmptyUrlBase() {
var cleverClientBuilder = CleverClient.builder()
.header("headerName")
.header("headerValue")
.httpClient(HttpClient.newHttpClient())
.endOfStream("[DONE]");
assertThrows(NullPointerException.class,
() -> cleverClientBuilder.build());
}
@Test
void shouldBuildSuccessfullyUsingDeprecatedUrlBase() {
var baseUrl = "https://test";
var cleverClient = CleverClient.builder()
.urlBase(baseUrl)
.build();
assertEquals(List.of(), cleverClient.getHeaders());
assertEquals(HttpClient.Version.HTTP_2, cleverClient.getHttpClient().version());
// verify that baseUrl is set when building with the deprecated urlBase() method
assertEquals(cleverClient.getBaseUrl(), baseUrl);
assertNotNull(cleverClient.getHttpProcessor());
}

@Test
void shouldThrownExceptionWhenTryingToPassAnOddNumbersOfHeaders() {
var cleverClientBuilder = CleverClient.builder()
.urlBase("http://test")
.header("oneHeader");
Exception exception = assertThrows(CleverClientException.class,
() -> cleverClientBuilder.build());
assertTrue(exception.getMessage().equals("Headers must be entered as pair of values in the list."));
}
@Test
void shouldImplementInterfaceWhenCallingCreate() {
var cleverClient = CleverClient.builder()
.baseUrl("https://test")
.header("headerName")
.header("headerValue")
.httpClient(HttpClient.newHttpClient())
.endOfStream("[DONE]")
.build();
var test = cleverClient.create(TestCleverClient.class);
assertNotNull(test);
}

interface TestCleverClient {
@GET("/api/")
CompletableFuture<String> getText();
}
@Test
void shouldThrownExceptionWhenTryingToPassAnEmptyBaseUrlAndUrlBase() {
var cleverClientBuilder = CleverClient.builder()
.header("headerName")
.header("headerValue")
.httpClient(HttpClient.newHttpClient())
.endOfStream("[DONE]");
assertThrows(CleverClientException.class,
cleverClientBuilder::build);
}

@Test
void shouldThrownExceptionWhenTryingToPassAnOddNumbersOfHeaders() {
var cleverClientBuilder = CleverClient.builder()
.baseUrl("http://test")
.header("oneHeader");
Exception exception = assertThrows(CleverClientException.class,
cleverClientBuilder::build);
assertEquals("Headers must be entered as pair of values in the list.",
exception.getMessage());
}

interface TestCleverClient {

@GET("/api/")
CompletableFuture<String> getText();
}
}
Loading

0 comments on commit c71af09

Please sign in to comment.