diff --git a/pom.xml b/pom.xml index 037040c..fcc9862 100644 --- a/pom.xml +++ b/pom.xml @@ -61,6 +61,7 @@ 1.18.38 3.14.0 1.15.2 + 4.12.0 @@ -69,6 +70,11 @@ moshi ${moshi.version} + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + org.apache.httpcomponents.core5 httpcore5 diff --git a/src/main/java/dev/resms/core/mapper/IMapper.java b/src/main/java/dev/resms/core/mapper/IMapper.java new file mode 100644 index 0000000..46fc088 --- /dev/null +++ b/src/main/java/dev/resms/core/mapper/IMapper.java @@ -0,0 +1,23 @@ +package dev.resms.core.mapper; + +/** An interface for mapping between JSON representation and Java objects using Moshi. */ +public interface IMapper { + + /** + * Converts the provided object into its JSON representation. + * + * @param object The object to be converted to JSON. + * @return The JSON representation of the object. + */ + String toJson(Object object); + + /** + * Converts the provided JSON value into an instance of the specified class. + * + * @param value The JSON value to be converted. + * @param clazz The class to convert the JSON value to. + * @param The type of the resulting object. + * @return An instance of the specified class with values from the JSON value. + */ + T fromJson(String value, Class clazz); +} diff --git a/src/main/java/dev/resms/core/mapper/ReSMSMapper.java b/src/main/java/dev/resms/core/mapper/ReSMSMapper.java new file mode 100644 index 0000000..2040e44 --- /dev/null +++ b/src/main/java/dev/resms/core/mapper/ReSMSMapper.java @@ -0,0 +1,46 @@ +package dev.resms.core.mapper; + +import com.squareup.moshi.Moshi; +import java.io.IOException; + +/** + * Implementation of the IMapper interface for mapping between JSON representation and Java objects + * using Moshi. + */ +public class ReSMSMapper implements IMapper { + + private final Moshi moshi; + + public ReSMSMapper() { + this.moshi = new Moshi.Builder().build(); + } + + /** + * Converts the provided object into its JSON representation. + * + * @param object The object to be converted to JSON. + * @return The JSON representation of the object. + */ + @Override + public String toJson(Object object) { + return moshi.adapter(Object.class).toJson(object); + } + + /** + * Converts the provided JSON value into an instance of the specified class. + * + * @param value The JSON value to be converted. + * @param clazz The class to convert the JSON value to. + * @param The type of the resulting object. + * @return An instance of the specified class with values from the JSON value. + */ + @Override + public T fromJson(String value, Class clazz) { + try { + return moshi.adapter(clazz).fromJson(value); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/main/java/dev/resms/core/net/AbstractHttpResponse.java b/src/main/java/dev/resms/core/net/AbstractHttpResponse.java new file mode 100644 index 0000000..1b949d5 --- /dev/null +++ b/src/main/java/dev/resms/core/net/AbstractHttpResponse.java @@ -0,0 +1,25 @@ +package dev.resms.core.net; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +/** + * Represents an HTTP response containing the response code, body, and success status. + * + * @param The type of the response body. + */ +@Getter +@Setter +@AllArgsConstructor +public class AbstractHttpResponse { + + /** The HTTP response code. */ + private int code; + + /** The response body. */ + private T body; + + /** Indicates whether the HTTP request was successful. */ + private boolean isSuccessful; +} diff --git a/src/main/java/dev/resms/core/net/HttpMethod.java b/src/main/java/dev/resms/core/net/HttpMethod.java new file mode 100644 index 0000000..fd75db3 --- /dev/null +++ b/src/main/java/dev/resms/core/net/HttpMethod.java @@ -0,0 +1,7 @@ +package dev.resms.core.net; + +/** An enumeration representing common HTTP methods. */ +public enum HttpMethod { + GET, + POST, +} diff --git a/src/main/java/dev/resms/core/net/IHttpClient.java b/src/main/java/dev/resms/core/net/IHttpClient.java new file mode 100644 index 0000000..426bf0b --- /dev/null +++ b/src/main/java/dev/resms/core/net/IHttpClient.java @@ -0,0 +1,21 @@ +package dev.resms.core.net; + +/** + * An interface representing an HTTP client for performing HTTP requests and receiving responses. + * + * @param The type of response data expected. + */ +public interface IHttpClient { + + /** + * Perform an HTTP request with the specified path, method, and payload. + * + * @param path The path or endpoint of the request. + * @param apiKey The API Key used to authenticate the request. + * @param method The HTTP method (GET, POST, PUT, DELETE, etc.). + * @param payload The payload or data to send with the request. + * @return An {@link AbstractHttpResponse} representing the response from the server. + */ + AbstractHttpResponse perform( + final String path, final String apiKey, final HttpMethod method, final String payload); +} diff --git a/src/main/java/dev/resms/core/net/impl/HttpClient.java b/src/main/java/dev/resms/core/net/impl/HttpClient.java new file mode 100644 index 0000000..0e35438 --- /dev/null +++ b/src/main/java/dev/resms/core/net/impl/HttpClient.java @@ -0,0 +1,64 @@ +package dev.resms.core.net.impl; + +import dev.resms.core.net.AbstractHttpResponse; +import dev.resms.core.net.HttpMethod; +import dev.resms.core.net.IHttpClient; +import java.io.IOException; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +/** + * An implementation of the {@link IHttpClient} interface for performing HTTP requests. This + * implementation uses the OkHttp library for handling HTTP communication. + */ +public class HttpClient implements IHttpClient { + + /** The base URL for the API. */ + public static final String BASE_API = "https://api.resms.dev/"; + + /** The OkHttpClient instance for handling HTTP requests. */ + private final OkHttpClient httpClient; + + /** Constructs an instance of the HttpClient. */ + public HttpClient() { + this.httpClient = new OkHttpClient(); + } + + /** + * Performs an HTTP request with the specified path, HTTP method, and payload. + * + * @param path The path or endpoint of the request. + * @param apiKey The API Key used to authenticate the request. + * @param method The HTTP method (GET, POST, PUT, DELETE, etc.). + * @param payload The payload or data to send with the request. + * @return An {@link AbstractHttpResponse} representing the response from the server. + */ + @Override + public AbstractHttpResponse perform( + final String path, final String apiKey, final HttpMethod method, final String payload) { + + RequestBody requestBody = null; + if (payload != null) { + requestBody = RequestBody.create(payload, MediaType.get("application/json")); + } + + Request request = + new Request.Builder() + .url(BASE_API + path) + .addHeader("Accept", "application/json") + .addHeader("X-Api-Key", apiKey) + .method(method.name(), requestBody) + .build(); + + try { + Response response = httpClient.newCall(request).execute(); + return new AbstractHttpResponse( + response.code(), response.body().string(), response.isSuccessful()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/dev/resms/core/service/BaseService.java b/src/main/java/dev/resms/core/service/BaseService.java new file mode 100644 index 0000000..dbd82f2 --- /dev/null +++ b/src/main/java/dev/resms/core/service/BaseService.java @@ -0,0 +1,35 @@ +package dev.resms.core.service; + +import dev.resms.core.mapper.ReSMSMapper; +import dev.resms.core.net.IHttpClient; +import dev.resms.core.net.impl.HttpClient; +import lombok.Getter; + +/** + * An abstract base class for service implementations, providing common functionality such as HTTP + * client, authentication provider, and mapper initialization. + */ +@Getter +public abstract class BaseService { + + /** Apikey used for authenticating requests. */ + protected final String apiKey; + + /** HTTP client for making HTTP requests. */ + protected final IHttpClient httpClient; + + /** Mapper responsible for mapping data between different representations. */ + protected final ReSMSMapper reSMSMapper; + + /** + * Constructs a BaseService instance with the specified authentication provider, default HTTP + * client, and mapper. + * + * @param apiKey The apiKey to use. + */ + protected BaseService(final String apiKey) { + this.apiKey = apiKey; + this.httpClient = new HttpClient(); + this.reSMSMapper = new ReSMSMapper(); + } +}