Skip to content

Commit

Permalink
Merge pull request #48 from sashirestela/47-change-headers-from-list-…
Browse files Browse the repository at this point in the history
…to-map

Change headers from list to map
  • Loading branch information
sashirestela authored Feb 11, 2024
2 parents d3ecab3 + 3b177bb commit be20041
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 53 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ We have the following attributes to create a CleverClient object:
| Attribute | Description | Required |
| -------------- |------------------------------------------|-----------|
| baseUrl | Api's url | mandatory |
| headers | Pairs of headers name/value | optional |
| headers | Map of headers (name/value) | optional |
| header | Single header (alternative to headers) | optional |
| httpClient | Java HttpClient object | optional |
| urlInterceptor | Function to modify the url once is built | optional |
| endOfStream | Text used to mark the final of streams | optional |
Expand All @@ -123,7 +124,7 @@ var httpClient = HttpClient.newBuilder()

var cleverClient = CleverClient.builder()
.baseUrl(BASE_URL)
.headers(Arrays.asList(HEADER_NAME, HEADER_VALUE))
.header(HEADER_NAME, HEADER_VALUE)
.httpClient(httpClient)
.urlInterceptor(url -> url + (url.contains("?") ? "&" : "?") + "env=testing")
.endOfStream(END_OF_STREAM)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static void main(String[] args) {

var cleverClient = CleverClient.builder()
.baseUrl(BASE_URL)
.headers(Arrays.asList(AUTHORIZATION_HEADER, BEARER_AUTHORIZATION))
.header(AUTHORIZATION_HEADER, BEARER_AUTHORIZATION)
.endOfStream(END_OF_STREAM)
.build();
var chatService = cleverClient.create(ChatService.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package io.github.sashirestela.cleverclient;

import java.net.http.HttpClient;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.github.sashirestela.cleverclient.http.HttpProcessor;
import io.github.sashirestela.cleverclient.support.CleverClientException;
import io.github.sashirestela.cleverclient.support.CleverClientSSE;
import io.github.sashirestela.cleverclient.util.CommonUtil;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;
Expand All @@ -25,8 +25,9 @@
public class CleverClient {
private static final Logger logger = LoggerFactory.getLogger(CleverClient.class);

@NonNull private final String baseUrl;
private final List<String> headers;
@NonNull
private final String baseUrl;
private final Map<String, String> headers;
private final HttpClient httpClient;
private final Function<String, String> urlInterceptor;
private final HttpProcessor httpProcessor;
Expand All @@ -35,28 +36,24 @@ public class CleverClient {
* Constructor to create an instance of CleverClient.
*
* @param baseUrl Root of the url of the API service to call. Mandatory.
* @param headers Http headers for all the API service. Header's name and
* value must be individual entries in the list. Optional.
* @param headers Http headers for all the API service. Optional.
* @param httpClient Custom Java's HttpClient component. One is created by
* default if none is passed. Optional.
* @param urlInterceptor Function to modify the url once it has been built.
* @param endOfStream Text used to mark the final of streams when handling
* server sent events (SSE). Optional.
*/
@Builder
public CleverClient(@NonNull String baseUrl, @Singular List<String> headers, HttpClient httpClient,
public CleverClient(@NonNull String baseUrl, @Singular Map<String, String> headers, HttpClient httpClient,
Function<String, String> urlInterceptor, String endOfStream) {
this.baseUrl = 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.headers = Optional.ofNullable(headers).orElse(Map.of());
this.httpClient = Optional.ofNullable(httpClient).orElse(HttpClient.newHttpClient());
this.urlInterceptor = urlInterceptor;
CleverClientSSE.setEndOfStream(endOfStream);
this.httpProcessor = HttpProcessor.builder()
.baseUrl(this.baseUrl)
.headers(this.headers)
.headers(CommonUtil.mapToListOfString(this.headers))
.httpClient(this.httpClient)
.urlInterceptor(this.urlInterceptor)
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.sashirestela.cleverclient.util;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
Expand Down Expand Up @@ -58,4 +59,13 @@ public static Map<String, String> createMapString(String... keyValPairs) {
}
return map;
}

public static List<String> mapToListOfString(Map<String, String> map) {
List<String> list = new ArrayList<>();
map.entrySet().stream().peek(e -> {
list.add(e.getKey());
list.add(e.getValue());
}).collect(Collectors.counting());
return list;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;

Expand All @@ -23,7 +23,6 @@
import io.github.sashirestela.cleverclient.annotation.GET;
import io.github.sashirestela.cleverclient.annotation.Query;
import io.github.sashirestela.cleverclient.annotation.Resource;
import io.github.sashirestela.cleverclient.support.CleverClientException;

class CleverClientTest {

Expand All @@ -32,7 +31,7 @@ void shouldSetPropertiesToDefaultValuesWhenBuilderIsCalledWithoutThoseProperties
var cleverClient = CleverClient.builder()
.baseUrl("https://test")
.build();
assertEquals(List.of(), cleverClient.getHeaders());
assertEquals(Map.of(), cleverClient.getHeaders());
assertEquals(HttpClient.Version.HTTP_2, cleverClient.getHttpClient().version());
assertNotNull(cleverClient.getBaseUrl());
assertNotNull(cleverClient.getHttpProcessor());
Expand All @@ -43,8 +42,7 @@ void shouldSetPropertiesToDefaultValuesWhenBuilderIsCalledWithoutThoseProperties
void shouldImplementInterfaceWhenCallingCreate() {
var cleverClient = CleverClient.builder()
.baseUrl("https://test")
.header("headerName")
.header("headerValue")
.header("headerName", "headerValue")
.httpClient(HttpClient.newHttpClient())
.endOfStream("[DONE]")
.build();
Expand All @@ -55,25 +53,13 @@ void shouldImplementInterfaceWhenCallingCreate() {
@Test
void shouldThrownExceptionWhenTryingToPassAnEmptyBaseUrl() {
var cleverClientBuilder = CleverClient.builder()
.header("headerName")
.header("headerValue")
.header("headerName", "headerValue")
.httpClient(HttpClient.newHttpClient())
.endOfStream("[DONE]");
assertThrows(NullPointerException.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());
}

@SuppressWarnings("unchecked")
@Test
void shouldModifyUrlWhenPassingUrlInterceptorFunction() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.sashirestela.cleverclient.metadata;

import static io.github.sashirestela.cleverclient.util.CommonUtil.createMapString;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

Expand All @@ -13,8 +14,7 @@
import io.github.sashirestela.cleverclient.metadata.InterfaceMetadata.MethodMetadata;
import io.github.sashirestela.cleverclient.metadata.InterfaceMetadata.ParameterMetadata;
import io.github.sashirestela.cleverclient.support.CleverClientException;
import io.github.sashirestela.cleverclient.support.ReturnType;
import io.github.sashirestela.cleverclient.util.CommonUtil;
import io.github.sashirestela.cleverclient.support.ReturnType;;

public class InterfaceMetadataStoreTest {

Expand All @@ -33,34 +33,33 @@ void shouldSaveInterfaceMetadataWhenAccomplishValidtion() {
AnnotationMetadata.builder()
.name("POST")
.isHttpMethod(true)
.valueByField(CommonUtil.createMapString("value", "/demos/{demoId}"))
.valueByField(createMapString("value", "/demos/{demoId}"))
.build(),
AnnotationMetadata.builder()
.name("Multipart")
.isHttpMethod(false)
.valueByField(CommonUtil.createMapString())
.valueByField(createMapString())
.build(),
AnnotationMetadata.builder()
.name("Header")
.isHttpMethod(false)
.valueByField(
CommonUtil.createMapString("name", "ThirdKey", "value", "ThirdVal"))
.valueByField(createMapString("name", "ThirdKey", "value", "ThirdVal"))
.build()))
.parameters(Arrays.asList(
ParameterMetadata.builder()
.index(0)
.annotation(AnnotationMetadata.builder()
.name("Body")
.isHttpMethod(false)
.valueByField(CommonUtil.createMapString())
.valueByField(createMapString())
.build())
.build(),
ParameterMetadata.builder()
.index(1)
.annotation(AnnotationMetadata.builder()
.name("Path")
.isHttpMethod(false)
.valueByField(CommonUtil.createMapString("value", "demoId"))
.valueByField(createMapString("value", "demoId"))
.build())
.build()))
.build());
Expand All @@ -75,32 +74,31 @@ void shouldSaveInterfaceMetadataWhenAccomplishValidtion() {
AnnotationMetadata.builder()
.name("GET")
.isHttpMethod(true)
.valueByField(
CommonUtil.createMapString("value", "/demos/{demoId}/subdemos"))
.valueByField(createMapString("value", "/demos/{demoId}/subdemos"))
.build()))
.parameters(Arrays.asList(
ParameterMetadata.builder()
.index(0)
.annotation(AnnotationMetadata.builder()
.name("Path")
.isHttpMethod(false)
.valueByField(CommonUtil.createMapString("value", "demoId"))
.valueByField(createMapString("value", "demoId"))
.build())
.build(),
ParameterMetadata.builder()
.index(1)
.annotation(AnnotationMetadata.builder()
.name("Query")
.isHttpMethod(false)
.valueByField(CommonUtil.createMapString("value", "size"))
.valueByField(createMapString("value", "size"))
.build())
.build(),
ParameterMetadata.builder()
.index(2)
.annotation(AnnotationMetadata.builder()
.name("Query")
.isHttpMethod(false)
.valueByField(CommonUtil.createMapString("value", "page"))
.valueByField(createMapString("value", "page"))
.build())
.build()))
.build());
Expand All @@ -110,17 +108,17 @@ void shouldSaveInterfaceMetadataWhenAccomplishValidtion() {
AnnotationMetadata.builder()
.name("Resource")
.isHttpMethod(false)
.valueByField(CommonUtil.createMapString("value", "/api"))
.valueByField(createMapString("value", "/api"))
.build(),
AnnotationMetadata.builder()
.name("Header")
.isHttpMethod(false)
.valueByField(CommonUtil.createMapString("name", "FirstKey", "value", "FirstVal"))
.valueByField(createMapString("name", "FirstKey", "value", "FirstVal"))
.build(),
AnnotationMetadata.builder()
.name("Header")
.isHttpMethod(false)
.valueByField(CommonUtil.createMapString("name", "SecondKey", "value", "SecondVal"))
.valueByField(createMapString("name", "SecondKey", "value", "SecondVal"))
.build()))
.methodBySignature(methodBySignature)
.build();
Expand All @@ -142,14 +140,15 @@ void shouldThrownExceptionWhenMethodHasNotHttpAnnotation() {
Exception exception = assertThrows(CleverClientException.class,
() -> store.save(ITest.NotAnnotatedService.class));
assertEquals("Missing HTTP annotation for the method unannotatedMethod.",
exception.getMessage());
exception.getMessage());
}

@Test
void shouldThrownExceptionWhenUrlPathParamAtMethodUnmatchesAnnotatedArguments() {
Exception exception = assertThrows(CleverClientException.class,
() -> store.save(ITest.BadPathParamService.class));
assertEquals("Path param demoId in the url cannot find an annotated argument in the method unmatchedPathParamMethod.",
exception.getMessage());
() -> store.save(ITest.BadPathParamService.class));
assertEquals(
"Path param demoId in the url cannot find an annotated argument in the method unmatchedPathParamMethod.",
exception.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

Expand All @@ -11,6 +12,7 @@
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertLinesMatch;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

Expand Down Expand Up @@ -124,4 +126,22 @@ void shouldThrownExceptionWhenCreatingMapStringAndExistsWrongCondition() {
assertThrows(IllegalArgumentException.class, () -> CommonUtil.createMapString(data));
}
}

@Test
void shouldConvertMapToListOfStringWhenAMapIsPassed() {
Map<String, String> map = new LinkedHashMap<>();
map.put("key1", "val1");
map.put("key2", "val2");
List<String> expectedList = List.of("key1", "val1", "key2", "val2");
List<String> actualList = CommonUtil.mapToListOfString(map);
assertLinesMatch(expectedList, actualList);
}

@Test
void shouldReturnAnEmptyListWhenCallingMapToListAnEmptyMapIsPassed() {
Map<String, String> map = Map.of();
List<String> expectedList = List.of();
List<String> actualList = CommonUtil.mapToListOfString(map);
assertLinesMatch(expectedList, actualList);
}
}

0 comments on commit be20041

Please sign in to comment.