diff --git a/src/main/java/com/resend/services/contacts/Contacts.java b/src/main/java/com/resend/services/contacts/Contacts.java index 37f4f69..22f6071 100644 --- a/src/main/java/com/resend/services/contacts/Contacts.java +++ b/src/main/java/com/resend/services/contacts/Contacts.java @@ -33,7 +33,13 @@ public Contacts(final String apiKey) { public CreateContactResponseSuccess create(CreateContactOptions createContactOptions) throws ResendException { String segmentId = createContactOptions.getSegmentId() != null ? createContactOptions.getSegmentId() : createContactOptions.getAudienceId(); String payload = super.resendMapper.writeValue(createContactOptions); - AbstractHttpResponse response = httpClient.perform("/segments/" + segmentId + "/contacts" , super.apiKey, HttpMethod.POST, payload, MediaType.get("application/json")); + + // Use /contacts for global contacts (when no segment ID is provided) + String endpoint = (segmentId == null || segmentId.isEmpty()) + ? "/contacts" + : "/segments/" + segmentId + "/contacts"; + + AbstractHttpResponse response = httpClient.perform(endpoint, super.apiKey, HttpMethod.POST, payload, MediaType.get("application/json")); if (!response.isSuccessful()) { throw new ResendException(response.getCode(), response.getBody()); @@ -83,13 +89,51 @@ public ListContactsResponseSuccess list(String segmentId, ListParams params) thr return resendMapper.readValue(responseBody, ListContactsResponseSuccess.class); } + /** + * Retrieves a list of global contacts (not associated with any segment). + * + * @return A ListContactsResponseSuccess containing the list of global contacts. + * @throws ResendException If an error occurs during the contacts list retrieval process. + */ + public ListContactsResponseSuccess list() throws ResendException { + AbstractHttpResponse response = this.httpClient.perform("/contacts", super.apiKey, HttpMethod.GET, null, MediaType.get("application/json")); + + if (!response.isSuccessful()) { + throw new ResendException(response.getCode(), response.getBody()); + } + + String responseBody = response.getBody(); + + return resendMapper.readValue(responseBody, ListContactsResponseSuccess.class); + } + + /** + * Retrieves a paginated list of global contacts (not associated with any segment). + * + * @param params The params used to customize the list. + * @return A ListContactsResponseSuccess containing the paginated list of global contacts. + * @throws ResendException If an error occurs during the contacts list retrieval process. + */ + public ListContactsResponseSuccess list(ListParams params) throws ResendException { + String pathWithQuery = "/contacts" + 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()); + } + + String responseBody = response.getBody(); + + return resendMapper.readValue(responseBody, ListContactsResponseSuccess.class); + } + /** * Retrieves a contact by its unique identifier. * * @param params The object containing: * – {@code audienceId}: the audience to which the contact belongs - * – Either {@code id}: the contact’s id - * or {@code email}: the contact’s email address + * – Either {@code id}: the contact's id + * or {@code email}: the contact's email address * @return The retrieved contact details. * @throws ResendException If an error occurs while retrieving the contact. */ @@ -104,7 +148,35 @@ public GetContactResponseSuccess get(GetContactOptions params) throws ResendExce String contactIdentifier = (id != null && !id.isEmpty()) ? id : email; String segmentId = params.getSegmentId() != null ? params.getSegmentId() : params.getAudienceId(); - AbstractHttpResponse response = this.httpClient.perform("/segments/" + segmentId + "/contacts/" + contactIdentifier, super.apiKey, HttpMethod.GET, null, MediaType.get("application/json")); + // Use /contacts for global contacts (when no segment ID is provided) + String endpoint = (segmentId == null || segmentId.isEmpty()) + ? "/contacts/" + contactIdentifier + : "/segments/" + segmentId + "/contacts/" + contactIdentifier; + + AbstractHttpResponse response = this.httpClient.perform(endpoint, super.apiKey, HttpMethod.GET, null, MediaType.get("application/json")); + + if (!response.isSuccessful()) { + throw new ResendException(response.getCode(), response.getBody()); + } + + String responseBody = response.getBody(); + + return resendMapper.readValue(responseBody, GetContactResponseSuccess.class); + } + + /** + * Retrieves a global contact by its unique identifier (not associated with any segment). + * + * @param contactIdOrEmail The contact's id or email address. + * @return The retrieved contact details. + * @throws ResendException If an error occurs while retrieving the contact. + */ + public GetContactResponseSuccess get(String contactIdOrEmail) throws ResendException { + if (contactIdOrEmail == null || contactIdOrEmail.isEmpty()) { + throw new IllegalArgumentException("Contact id or email must be provided"); + } + + AbstractHttpResponse response = this.httpClient.perform("/contacts/" + contactIdOrEmail, super.apiKey, HttpMethod.GET, null, MediaType.get("application/json")); if (!response.isSuccessful()) { throw new ResendException(response.getCode(), response.getBody()); @@ -131,7 +203,36 @@ public RemoveContactResponseSuccess remove(RemoveContactOptions params) throws R String pathParameter = params.getId() != null ? params.getId() : params.getEmail(); String segmentId = params.getSegmentId() != null ? params.getSegmentId() : params.getAudienceId(); - AbstractHttpResponse response = httpClient.perform("/segments/" + segmentId + "/contacts/" + pathParameter, super.apiKey, HttpMethod.DELETE, "", null); + // Use /contacts for global contacts (when no segment ID is provided) + String endpoint = (segmentId == null || segmentId.isEmpty()) + ? "/contacts/" + pathParameter + : "/segments/" + segmentId + "/contacts/" + pathParameter; + + AbstractHttpResponse response = httpClient.perform(endpoint, super.apiKey, HttpMethod.DELETE, "", null); + + if (!response.isSuccessful()) { + throw new ResendException(response.getCode(), response.getBody()); + } + + String responseBody = response.getBody(); + + return resendMapper.readValue(responseBody, RemoveContactResponseSuccess.class); + } + + /** + * Deletes a global contact based on the provided contact ID. + * Note: Global contacts can only be removed by ID, not by email. + * + * @param contactId The contact's id. + * @return The RemoveContactsResponseSuccess with the details of the removed contact. + * @throws ResendException If an error occurs during the contact deletion process. + */ + public RemoveContactResponseSuccess remove(String contactId) throws ResendException { + if (contactId == null || contactId.isEmpty()) { + throw new IllegalArgumentException("Contact id must be provided"); + } + + AbstractHttpResponse response = httpClient.perform("/contacts/" + contactId, super.apiKey, HttpMethod.DELETE, "", null); if (!response.isSuccessful()) { throw new ResendException(response.getCode(), response.getBody()); @@ -158,8 +259,13 @@ public UpdateContactResponseSuccess update(UpdateContactOptions params) throws R String pathParameter = params.getId() != null ? params.getId() : params.getEmail(); String segmentId = params.getSegmentId() != null ? params.getSegmentId() : params.getAudienceId(); + // Use /contacts for global contacts (when no segment ID is provided) + String endpoint = (segmentId == null || segmentId.isEmpty()) + ? "/contacts/" + pathParameter + : "/segments/" + segmentId + "/contacts/" + pathParameter; + String payload = super.resendMapper.writeValue(params); - AbstractHttpResponse response = httpClient.perform("/segments/" + segmentId + "/contacts/" + pathParameter, super.apiKey, HttpMethod.PATCH, payload, MediaType.get("application/json")); + AbstractHttpResponse response = httpClient.perform(endpoint, super.apiKey, HttpMethod.PATCH, payload, MediaType.get("application/json")); if (!response.isSuccessful()) { throw new ResendException(response.getCode(), response.getBody()); diff --git a/src/test/java/com/resend/services/contacts/ContactsTest.java b/src/test/java/com/resend/services/contacts/ContactsTest.java index 2711ff1..f4bbb97 100644 --- a/src/test/java/com/resend/services/contacts/ContactsTest.java +++ b/src/test/java/com/resend/services/contacts/ContactsTest.java @@ -203,4 +203,132 @@ public void testUpdateTopics_Success() throws ResendException { assertEquals(expectedResponse.getId(), res.getId()); verify(contacts, times(1)).updateTopics(options); } + + // Global contacts tests (without segment ID) + + @Test + public void testCreateGlobalContact_Success() throws ResendException { + CreateContactResponseSuccess expectedContact = ContactsUtil.createContactResponseSuccess(); + CreateContactOptions param = CreateContactOptions.builder() + .email("user@example.com") + .firstName("John") + .lastName("Doe") + .build(); + + when(contacts.create(param)) + .thenReturn(expectedContact); + + CreateContactResponseSuccess createdContact = contacts.create(param); + + assertEquals(createdContact, expectedContact); + verify(contacts, times(1)).create(param); + } + + @Test + public void testListGlobalContacts_Success() throws ResendException { + ListContactsResponseSuccess expectedResponse = ContactsUtil.createContactsListResponse(); + + when(contacts.list()) + .thenReturn(expectedResponse); + + ListContactsResponseSuccess res = contacts.list(); + + assertNotNull(res); + assertEquals(expectedResponse.getData().size(), res.getData().size()); + assertEquals(expectedResponse.getObject(), res.getObject()); + } + + @Test + public void testListGlobalContactsWithPagination_Success() throws ResendException { + ListParams params = ListParams.builder() + .limit(3).build(); + + ListContactsResponseSuccess expectedResponse = ContactsUtil.createContactsListResponse(); + + when(contacts.list(params)) + .thenReturn(expectedResponse); + + ListContactsResponseSuccess res = contacts.list(params); + + assertNotNull(res); + assertEquals(params.getLimit(), res.getData().size()); + assertEquals(expectedResponse.getObject(), res.getObject()); + } + + @Test + public void testGetGlobalContactById_Success() throws ResendException { + String contactId = "e169aa45-1ecf-4183-9955-b1499d5701d3"; + GetContactResponseSuccess expected = ContactsUtil.getContactResponseSuccess(); + + when(contacts.get(contactId)).thenReturn(expected); + + GetContactResponseSuccess res = contacts.get(contactId); + + assertNotNull(res); + assertEquals(expected, res); + verify(contacts, times(1)).get(contactId); + } + + @Test + public void testGetGlobalContactByEmail_Success() throws ResendException { + String contactEmail = "user@example.com"; + GetContactResponseSuccess expected = ContactsUtil.getContactResponseSuccess(); + + when(contacts.get(contactEmail)).thenReturn(expected); + + GetContactResponseSuccess res = contacts.get(contactEmail); + + assertNotNull(res); + assertEquals(expected, res); + verify(contacts, times(1)).get(contactEmail); + } + + @Test + public void testRemoveGlobalContactById_Success() throws ResendException { + String contactId = "e169aa45-1ecf-4183-9955-b1499d5701d3"; + RemoveContactResponseSuccess removed = ContactsUtil.removeContactResponseSuccess(); + + when(contacts.remove(contactId)) + .thenReturn(removed); + + RemoveContactResponseSuccess res = contacts.remove(contactId); + + assertEquals(removed, res); + verify(contacts, times(1)).remove(contactId); + } + + @Test + public void testUpdateGlobalContact_Success() throws ResendException { + UpdateContactOptions params = UpdateContactOptions.builder() + .id("e169aa45-1ecf-4183-9955-b1499d5701d3") + .firstName("Jane") + .lastName("Smith") + .build(); + UpdateContactResponseSuccess expectedResponse = ContactsUtil.updateContactResponseSuccess(); + + when(contacts.update(params)) + .thenReturn(expectedResponse); + + UpdateContactResponseSuccess res = contacts.update(params); + + assertNotNull(res); + assertEquals(expectedResponse.getId(), res.getId()); + assertEquals(expectedResponse.getObject(), res.getObject()); + } + + @Test + public void testGetContactWithoutSegmentId_Success() throws ResendException { + GetContactOptions params = GetContactOptions.builder() + .id("e169aa45-1ecf-4183-9955-b1499d5701d3") + .build(); + GetContactResponseSuccess expected = ContactsUtil.getContactResponseSuccess(); + + when(contacts.get(params)).thenReturn(expected); + + GetContactResponseSuccess res = contacts.get(params); + + assertNotNull(res); + assertEquals(expected, res); + verify(contacts, times(1)).get(params); + } }