From 6da093b5251eda7584ea14280dfb836eb5579e19 Mon Sep 17 00:00:00 2001 From: Kewyn Akshlley Date: Thu, 2 Apr 2026 00:10:56 -0300 Subject: [PATCH] feat: support logs endpoints --- src/main/java/com/resend/Resend.java | 10 ++ .../java/com/resend/services/logs/Logs.java | 77 +++++++++++++ .../logs/model/GetLogResponseSuccess.java | 47 ++++++++ .../logs/model/ListLogsResponseSuccess.java | 43 ++++++++ .../com/resend/services/logs/model/Log.java | 73 +++++++++++++ .../resend/services/logs/model/LogEntry.java | 60 +++++++++++ .../com/resend/services/logs/LogsTest.java | 102 ++++++++++++++++++ .../com/resend/services/util/LogsUtil.java | 33 ++++++ 8 files changed, 445 insertions(+) create mode 100644 src/main/java/com/resend/services/logs/Logs.java create mode 100644 src/main/java/com/resend/services/logs/model/GetLogResponseSuccess.java create mode 100644 src/main/java/com/resend/services/logs/model/ListLogsResponseSuccess.java create mode 100644 src/main/java/com/resend/services/logs/model/Log.java create mode 100644 src/main/java/com/resend/services/logs/model/LogEntry.java create mode 100644 src/test/java/com/resend/services/logs/LogsTest.java create mode 100644 src/test/java/com/resend/services/util/LogsUtil.java diff --git a/src/main/java/com/resend/Resend.java b/src/main/java/com/resend/Resend.java index 8191217..f8d65f6 100644 --- a/src/main/java/com/resend/Resend.java +++ b/src/main/java/com/resend/Resend.java @@ -12,6 +12,7 @@ import com.resend.services.webhooks.Webhooks; import com.resend.services.receiving.Receiving; import com.resend.services.topics.Topics; +import com.resend.services.logs.Logs; import com.resend.services.templates.Templates; /** @@ -151,4 +152,13 @@ public Topics topics() { public Templates templates() { return new Templates(apiKey); } + + /** + * Returns a Logs object that can be used to interact with the Logs service. + * + * @return A Logs object. + */ + public Logs logs() { + return new Logs(apiKey); + } } diff --git a/src/main/java/com/resend/services/logs/Logs.java b/src/main/java/com/resend/services/logs/Logs.java new file mode 100644 index 0000000..a87def9 --- /dev/null +++ b/src/main/java/com/resend/services/logs/Logs.java @@ -0,0 +1,77 @@ +package com.resend.services.logs; + +import com.resend.core.exception.ResendException; +import com.resend.core.helper.URLHelper; +import com.resend.core.net.AbstractHttpResponse; +import com.resend.core.net.HttpMethod; +import com.resend.core.net.ListParams; +import com.resend.core.service.BaseService; +import com.resend.services.logs.model.GetLogResponseSuccess; +import com.resend.services.logs.model.ListLogsResponseSuccess; +import okhttp3.MediaType; + +/** + * Represents the Resend Logs module. + */ +public class Logs extends BaseService { + + /** + * Constructs an instance of the {@code Logs} class. + * + * @param apiKey The apiKey used for authentication. + */ + public Logs(final String apiKey) { + super(apiKey); + } + + /** + * Retrieves a single log entry by its unique identifier. + * + * @param logId The unique identifier of the log. + * @return The retrieved log details. + * @throws ResendException If an error occurs while retrieving the log. + */ + public GetLogResponseSuccess get(String logId) throws ResendException { + AbstractHttpResponse response = this.httpClient.perform("/logs/" + logId, super.apiKey, HttpMethod.GET, null, MediaType.get("application/json")); + + if (!response.isSuccessful()) { + throw new ResendException(response.getCode(), response.getBody()); + } + + return resendMapper.readValue(response.getBody(), GetLogResponseSuccess.class); + } + + /** + * Retrieves a list of logs. + * + * @return A ListLogsResponseSuccess containing the list of logs. + * @throws ResendException If an error occurs during the logs list retrieval process. + */ + public ListLogsResponseSuccess list() throws ResendException { + AbstractHttpResponse response = this.httpClient.perform("/logs", super.apiKey, HttpMethod.GET, null, MediaType.get("application/json")); + + if (!response.isSuccessful()) { + throw new ResendException(response.getCode(), response.getBody()); + } + + return resendMapper.readValue(response.getBody(), ListLogsResponseSuccess.class); + } + + /** + * Retrieves a paginated list of logs. + * + * @param params The params used to customize the list (limit, after, before). + * @return A ListLogsResponseSuccess containing the paginated list of logs. + * @throws ResendException If an error occurs during the logs list retrieval process. + */ + public ListLogsResponseSuccess list(ListParams params) throws ResendException { + String pathWithQuery = "/logs" + URLHelper.parse(params); + AbstractHttpResponse response = this.httpClient.perform(pathWithQuery, super.apiKey, HttpMethod.GET, null, MediaType.get("application/json")); + + if (!response.isSuccessful()) { + throw new ResendException(response.getCode(), response.getBody()); + } + + return resendMapper.readValue(response.getBody(), ListLogsResponseSuccess.class); + } +} diff --git a/src/main/java/com/resend/services/logs/model/GetLogResponseSuccess.java b/src/main/java/com/resend/services/logs/model/GetLogResponseSuccess.java new file mode 100644 index 0000000..1e0c11f --- /dev/null +++ b/src/main/java/com/resend/services/logs/model/GetLogResponseSuccess.java @@ -0,0 +1,47 @@ +package com.resend.services.logs.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Map; + +/** + * Represents a successful response for retrieving a single log entry. + */ +public class GetLogResponseSuccess extends Log { + + @JsonProperty("object") + private String object; + + /** + * Default constructor. + */ + public GetLogResponseSuccess() { + } + + /** + * Constructs a GetLogResponseSuccess. + * + * @param id The unique identifier of the log. + * @param createdAt The creation timestamp of the log. + * @param endpoint The API endpoint that was called. + * @param method The HTTP method used. + * @param responseStatus The HTTP response status code. + * @param userAgent The user agent string. + * @param requestBody The request body. + * @param responseBody The response body. + * @param object The object type ("log"). + */ + public GetLogResponseSuccess(String id, String createdAt, String endpoint, String method, Integer responseStatus, String userAgent, Map requestBody, Map responseBody, String object) { + super(id, createdAt, endpoint, method, responseStatus, userAgent, requestBody, responseBody); + this.object = object; + } + + /** + * Gets the object type. + * + * @return The object type ("log"). + */ + public String getObject() { + return object; + } +} diff --git a/src/main/java/com/resend/services/logs/model/ListLogsResponseSuccess.java b/src/main/java/com/resend/services/logs/model/ListLogsResponseSuccess.java new file mode 100644 index 0000000..b36b733 --- /dev/null +++ b/src/main/java/com/resend/services/logs/model/ListLogsResponseSuccess.java @@ -0,0 +1,43 @@ +package com.resend.services.logs.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +/** + * Represents a successful response for listing logs. + */ +public class ListLogsResponseSuccess { + + @JsonProperty("object") + private String object; + + @JsonProperty("has_more") + private Boolean hasMore; + + @JsonProperty("data") + private List data; + + /** + * Default constructor. + */ + public ListLogsResponseSuccess() { + } + + /** + * Constructs a ListLogsResponseSuccess. + * + * @param object The object type ("list"). + * @param hasMore Whether there are more items available for pagination. + * @param data The list of log entries. + */ + public ListLogsResponseSuccess(String object, Boolean hasMore, List data) { + this.object = object; + this.hasMore = hasMore; + this.data = data; + } + + public String getObject() { return object; } + public Boolean hasMore() { return hasMore; } + public List getData() { return data; } +} diff --git a/src/main/java/com/resend/services/logs/model/Log.java b/src/main/java/com/resend/services/logs/model/Log.java new file mode 100644 index 0000000..2d402e0 --- /dev/null +++ b/src/main/java/com/resend/services/logs/model/Log.java @@ -0,0 +1,73 @@ +package com.resend.services.logs.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Map; + +/** + * Represents a log entry for a single API request. + */ +public class Log { + + @JsonProperty("id") + private String id; + + @JsonProperty("created_at") + private String createdAt; + + @JsonProperty("endpoint") + private String endpoint; + + @JsonProperty("method") + private String method; + + @JsonProperty("response_status") + private Integer responseStatus; + + @JsonProperty("user_agent") + private String userAgent; + + @JsonProperty("request_body") + private Map requestBody; + + @JsonProperty("response_body") + private Map responseBody; + + /** + * Default constructor. + */ + public Log() { + } + + /** + * Constructs a Log entry. + * + * @param id The unique identifier of the log. + * @param createdAt The creation timestamp of the log. + * @param endpoint The API endpoint that was called. + * @param method The HTTP method used. + * @param responseStatus The HTTP response status code. + * @param userAgent The user agent string. + * @param requestBody The request body. + * @param responseBody The response body. + */ + public Log(String id, String createdAt, String endpoint, String method, Integer responseStatus, String userAgent, Map requestBody, Map responseBody) { + this.id = id; + this.createdAt = createdAt; + this.endpoint = endpoint; + this.method = method; + this.responseStatus = responseStatus; + this.userAgent = userAgent; + this.requestBody = requestBody; + this.responseBody = responseBody; + } + + public String getId() { return id; } + public String getCreatedAt() { return createdAt; } + public String getEndpoint() { return endpoint; } + public String getMethod() { return method; } + public Integer getResponseStatus() { return responseStatus; } + public String getUserAgent() { return userAgent; } + public Map getRequestBody() { return requestBody; } + public Map getResponseBody() { return responseBody; } +} diff --git a/src/main/java/com/resend/services/logs/model/LogEntry.java b/src/main/java/com/resend/services/logs/model/LogEntry.java new file mode 100644 index 0000000..9412e6b --- /dev/null +++ b/src/main/java/com/resend/services/logs/model/LogEntry.java @@ -0,0 +1,60 @@ +package com.resend.services.logs.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents a summary log entry returned in the list logs response. + * Contains a subset of fields compared to the full {@link Log} object. + */ +public class LogEntry { + + @JsonProperty("id") + private String id; + + @JsonProperty("created_at") + private String createdAt; + + @JsonProperty("endpoint") + private String endpoint; + + @JsonProperty("method") + private String method; + + @JsonProperty("response_status") + private Integer responseStatus; + + @JsonProperty("user_agent") + private String userAgent; + + /** + * Default constructor. + */ + public LogEntry() { + } + + /** + * Constructs a LogEntry. + * + * @param id The unique identifier of the log. + * @param createdAt The creation timestamp of the log. + * @param endpoint The API endpoint that was called. + * @param method The HTTP method used. + * @param responseStatus The HTTP response status code. + * @param userAgent The user agent string. + */ + public LogEntry(String id, String createdAt, String endpoint, String method, Integer responseStatus, String userAgent) { + this.id = id; + this.createdAt = createdAt; + this.endpoint = endpoint; + this.method = method; + this.responseStatus = responseStatus; + this.userAgent = userAgent; + } + + public String getId() { return id; } + public String getCreatedAt() { return createdAt; } + public String getEndpoint() { return endpoint; } + public String getMethod() { return method; } + public Integer getResponseStatus() { return responseStatus; } + public String getUserAgent() { return userAgent; } +} diff --git a/src/test/java/com/resend/services/logs/LogsTest.java b/src/test/java/com/resend/services/logs/LogsTest.java new file mode 100644 index 0000000..ef07dcb --- /dev/null +++ b/src/test/java/com/resend/services/logs/LogsTest.java @@ -0,0 +1,102 @@ +package com.resend.services.logs; + +import com.resend.core.exception.ResendException; +import com.resend.core.net.ListParams; +import com.resend.services.logs.model.GetLogResponseSuccess; +import com.resend.services.logs.model.ListLogsResponseSuccess; +import com.resend.services.util.LogsUtil; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.*; + +public class LogsTest { + + @Mock + private Logs logs; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + logs = mock(Logs.class); + } + + @Test + public void testGetLog_Success() throws ResendException { + String logId = "log_123"; + GetLogResponseSuccess expected = LogsUtil.getLogResponseSuccess(); + + when(logs.get(logId)).thenReturn(expected); + + GetLogResponseSuccess res = logs.get(logId); + + assertNotNull(res); + assertEquals(expected.getId(), res.getId()); + assertEquals(expected.getEndpoint(), res.getEndpoint()); + assertEquals(expected.getMethod(), res.getMethod()); + assertEquals(expected.getResponseStatus(), res.getResponseStatus()); + assertEquals(expected.getObject(), res.getObject()); + verify(logs, times(1)).get(logId); + } + + @Test + public void testListLogs_Success() throws ResendException { + ListLogsResponseSuccess expected = LogsUtil.createLogsListResponse(); + + when(logs.list()).thenReturn(expected); + + ListLogsResponseSuccess res = logs.list(); + + assertNotNull(res); + assertEquals(expected.getData().size(), res.getData().size()); + assertEquals(expected.getObject(), res.getObject()); + verify(logs, times(1)).list(); + } + + @Test + public void testListLogsWithPagination_Success() throws ResendException { + ListParams params = ListParams.builder().limit(3).build(); + ListLogsResponseSuccess expected = LogsUtil.createLogsListResponse(); + + when(logs.list(params)).thenReturn(expected); + + ListLogsResponseSuccess res = logs.list(params); + + assertNotNull(res); + assertEquals(params.getLimit(), res.getData().size()); + assertEquals(expected.getObject(), res.getObject()); + verify(logs, times(1)).list(params); + } + + @Test + public void testListLogsWithAfterCursor_Success() throws ResendException { + ListParams params = ListParams.builder().after("log_50").build(); + ListLogsResponseSuccess expected = LogsUtil.createLogsListResponse(); + + when(logs.list(params)).thenReturn(expected); + + ListLogsResponseSuccess res = logs.list(params); + + assertNotNull(res); + assertEquals(expected.getData().size(), res.getData().size()); + verify(logs, times(1)).list(params); + } + + @Test + public void testListLogsWithBeforeCursor_Success() throws ResendException { + ListParams params = ListParams.builder().before("log_100").build(); + ListLogsResponseSuccess expected = LogsUtil.createLogsListResponse(); + + when(logs.list(params)).thenReturn(expected); + + ListLogsResponseSuccess res = logs.list(params); + + assertNotNull(res); + assertEquals(expected.getData().size(), res.getData().size()); + verify(logs, times(1)).list(params); + } +} diff --git a/src/test/java/com/resend/services/util/LogsUtil.java b/src/test/java/com/resend/services/util/LogsUtil.java new file mode 100644 index 0000000..308cd3a --- /dev/null +++ b/src/test/java/com/resend/services/util/LogsUtil.java @@ -0,0 +1,33 @@ +package com.resend.services.util; + +import com.resend.services.logs.model.GetLogResponseSuccess; +import com.resend.services.logs.model.ListLogsResponseSuccess; +import com.resend.services.logs.model.LogEntry; + +import java.util.ArrayList; +import java.util.List; + +public class LogsUtil { + + public static GetLogResponseSuccess getLogResponseSuccess() { + return new GetLogResponseSuccess( + "log_123", + "2024-01-01T00:00:00.000Z", + "/emails", + "POST", + 200, + "resend-java/4.13.0", + null, + null, + "log" + ); + } + + public static ListLogsResponseSuccess createLogsListResponse() { + List entries = new ArrayList<>(); + entries.add(new LogEntry("log_1", "2024-01-01T00:00:00.000Z", "/emails", "POST", 200, "resend-java/4.13.0")); + entries.add(new LogEntry("log_2", "2024-01-02T00:00:00.000Z", "/domains", "GET", 200, "resend-java/4.13.0")); + entries.add(new LogEntry("log_3", "2024-01-03T00:00:00.000Z", "/contacts", "DELETE", 204, null)); + return new ListLogsResponseSuccess("list", false, entries); + } +}