Skip to content

Contacts api #64

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 65 commits into from
Jun 9, 2025
Merged

Contacts api #64

merged 65 commits into from
Jun 9, 2025

Conversation

narekhovhannisyan
Copy link
Collaborator

@narekhovhannisyan narekhovhannisyan commented May 17, 2025

Contacts API Integration

Motivation

The contacts and contact lists APIs were not properly integrated into the Mailtrap client. We needed to add these APIs as direct getters on the MailtrapClient class to maintain consistency with the API design and provide easy access to contact management functionality.

Changes

  • Added contacts and contactLists getters to MailtrapClient class
  • Updated tests to use direct getters instead of accessing through general API
  • Fixed test assertions to match axios interceptor response format

How to test

  • Run the test suite to verify all tests pass:
    yarn test

Summary by CodeRabbit

  • New Features
    • Introduced support for managing contacts, including creating, updating, retrieving, and deleting contacts via the API.
    • Added new example scripts demonstrating the full lifecycle of contact management.
  • Documentation
    • Updated documentation to include examples and details for the new Contacts API.
  • Tests
    • Added comprehensive tests for contact-related API operations to ensure reliability and correctness.
  • Type Definitions
    • Added new type definitions for contacts and contact lists to support structured and type-safe API interactions.

Copy link

coderabbitai bot commented May 17, 2025

Walkthrough

This update introduces a new Contacts API feature, including type definitions, API classes, and example scripts for managing contacts and contact lists. It adds related documentation, test files, and integrates the Contacts API into the main client. No breaking changes or modifications to existing exported entities were made.

Changes

File(s) Change Summary
README.md Added "Contacts API" section with links to new examples.
examples/contacts/everything.ts New example script demonstrating full lifecycle management of contacts using the MailtrapClient.
src/lib/MailtrapClient.ts Added contacts getter returning ContactsBaseAPI; reorganized imports.
src/lib/api/Contacts.ts Introduced ContactsBaseAPI class with methods: get, create, update, delete.
src/lib/api/resources/Contacts.ts Added ContactsApi class implementing contact CRUD methods using Axios.
src/types/mailtrap.ts Added ContactFields and ContactData interfaces for contact type definitions.
src/types/api/contacts.ts Added interfaces: Contact, ContactData, ContactUpdateData, ContactResponse.
src/types/api/contactlist.ts Added interfaces: ContactList and ContactListData for contact list typing.
src/tests/lib/api/Contacts.test.ts New test suite for ContactsBaseAPI class, verifying method presence.
src/tests/lib/api/resources/Contacts.test.ts New test suite for ContactsApi, covering CRUD methods with success and error cases.
src/tests/lib/mailtrap-client.test.ts Reordered import statements; no logic changes.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant MailtrapClient
    participant ContactsBaseAPI
    participant ContactsApi
    participant Mailtrap API

    User->>MailtrapClient: Initialize with token/accountId
    User->>MailtrapClient: Access contacts property
    MailtrapClient->>ContactsBaseAPI: Instantiate with axios/accountId
    User->>ContactsBaseAPI: create/update/delete/get contact
    ContactsBaseAPI->>ContactsApi: Forward method call
    ContactsApi->>Mailtrap API: HTTP request (GET/POST/PATCH/DELETE)
    Mailtrap API-->>ContactsApi: API response
    ContactsApi-->>ContactsBaseAPI: Return data
    ContactsBaseAPI-->>User: Return result
Loading

Poem

In burrows deep, a feature grows,
Contacts and lists now Mailtrap knows!
With types and tests, the code is neat,
New endpoints make our toolkit complete.
From create to delete, the flow is clear—
Hooray for contacts, let’s all cheer!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 272964f and 26f43e4.

📒 Files selected for processing (1)
  • examples/contacts/everything.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/contacts/everything.ts
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@narekhovhannisyan narekhovhannisyan marked this pull request as draft May 17, 2025 18:14
@narekhovhannisyan narekhovhannisyan marked this pull request as ready for review May 17, 2025 18:18
@narekhovhannisyan narekhovhannisyan self-assigned this May 17, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (6)
src/lib/api/resources/contacts/ContactLists.ts (1)

8-24: ContactListsApi implementation looks good but could be enhanced

The ContactListsApi class has a clean implementation for listing contact lists. However, there are a few enhancements to consider:

  1. The account ID is optional in the constructor but the URL construction doesn't handle the case when it's undefined.
  2. There's no type definition for the response structure.
  3. The API doesn't support pagination which might be needed for accounts with many contact lists.

Consider adding these improvements:

import { AxiosInstance } from "axios";

import CONFIG from "../../../../config";
+ import { ContactListsResponse } from "../../../../../types/mailtrap";

const { CLIENT_SETTINGS } = CONFIG;
const { GENERAL_ENDPOINT } = CLIENT_SETTINGS;

export default class ContactListsApi {
  private client: AxiosInstance;

  private contactListsURL: string;

  constructor(client: AxiosInstance, accountId?: number) {
    this.client = client;
+   if (!accountId) {
+     throw new Error("Account ID is required for ContactListsApi");
+   }
    this.contactListsURL = `${GENERAL_ENDPOINT}/api/accounts/${accountId}/contacts/lists`;
  }

  /**
   * Lists all contact lists for the account.
+  * @returns Promise with contact lists data
   */
-  public async list() {
-    return this.client.get(this.contactListsURL);
+  public async list(params?: { page?: number; per_page?: number }) {
+    return this.client.get<ContactListsResponse>(this.contactListsURL, { params });
  }
}
src/lib/api/resources/contacts/Contacts.ts (1)

21-23: Add return type annotations for better code clarity

Adding explicit return type annotations to the async methods would improve code clarity and provide better TypeScript type checking.

- public async create(data: ContactData) {
+ public async create(data: ContactData): Promise<AxiosResponse> {
    return this.client.post(this.contactsURL, { contact: data });
  }

- public async update(id: number, data: ContactData) {
+ public async update(id: number, data: ContactData): Promise<AxiosResponse> {
    const url = `${this.contactsURL}/${id}`;
    return this.client.patch(url, { contact: data });
  }

- public async delete(id: number) {
+ public async delete(id: number): Promise<AxiosResponse> {
    const url = `${this.contactsURL}/${id}`;
    return this.client.delete(url);
  }

Don't forget to also import the AxiosResponse type:

- import { AxiosInstance } from "axios";
+ import { AxiosInstance, AxiosResponse } from "axios";

Also applies to: 28-31, 36-39

src/lib/MailtrapClient.ts (1)

155-179: Minor clean-ups inside batchSend

  1. preparedRequests still serialises properties that are undefined; removing them trims the payload and matches classic Mailtrap examples.
-    const preparedRequests = request.requests.map((req) => ({
-      to: req.to,
-      cc: req.cc,
-      bcc: req.bcc,
-      custom_variables: req.custom_variables,
-    }));
+    const preparedRequests = request.requests.map(
+      ({ to, cc, bcc, custom_variables }) =>
+        Object.fromEntries(
+          Object.entries({ to, cc, bcc, custom_variables }).filter(
+            ([, v]) => v !== undefined
+          )
+        )
+    );
  1. A short JSDoc block describing the supported shapes (InlineBatchSendBase | TemplateBatchSendBase) would help IDEs and consumers.
src/types/mailtrap.ts (1)

79-83: BaseAddress duplicates Address – keep a single source of truth

BaseAddress and the earlier-declared Address share the exact shape. Re-use Address instead of introducing a parallel type to avoid drift.

-interface BaseAddress {
-  email: string;
-  name?: string;
-}
+type BaseAddress = Address;
src/__tests__/lib/mailtrap-client.test.ts (2)

331-675: Isolate Axios mocks between test suites

The AxiosMockAdapter instance is created only inside the send() suite.
batch sending tests run inside that suite (✓) but later contacts and contact lists suites rely on the same mock without their own beforeAll/afterEach, risking leftover interceptors if additional suites are appended in the future.

A minimal fix is to move the adapter initialisation & reset one level up:

describe("lib/mailtrap-client: ", () => {
-  let mock: AxiosMockAdapter;
+  let mock: AxiosMockAdapter;
+
+  beforeAll(() => {
+    mock = new AxiosMockAdapter(axios);
+  });
+
+  afterEach(() => {
+    mock.reset();
+  });

…and remove the nested beforeAll / afterEach blocks.
This guarantees every test starts with a clean slate.


733-871: Expand coverage & negative cases for Contacts / Lists APIs

Nice positive-path assertions! Two quick wins:

  1. Add a test that accessing client.contacts/client.contactLists without an accountId throws MailtrapError once you implement the guard recommended above.
  2. Verify that fields and list_ids round-trip correctly when present in responses, ensuring JSON serialisation remains symmetric.

Would you like help drafting these extra tests?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9f24dfd and 91b0cde.

📒 Files selected for processing (15)
  • README.md (2 hunks)
  • examples/batch/bulk.ts (1 hunks)
  • examples/batch/sandbox.ts (1 hunks)
  • examples/batch/template.ts (1 hunks)
  • examples/batch/transactional.ts (1 hunks)
  • examples/contacts/contact-lists.ts (1 hunks)
  • examples/contacts/everything.ts (1 hunks)
  • examples/testing/send-mail.ts (1 hunks)
  • src/__tests__/lib/mailtrap-client.test.ts (3 hunks)
  • src/lib/MailtrapClient.ts (3 hunks)
  • src/lib/api/Contacts.ts (1 hunks)
  • src/lib/api/resources/contacts/ContactLists.ts (1 hunks)
  • src/lib/api/resources/contacts/Contacts.ts (1 hunks)
  • src/lib/mail-buffer-encoder.ts (1 hunks)
  • src/types/mailtrap.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
src/lib/mail-buffer-encoder.ts (1)
src/types/mailtrap.ts (1)
  • Mail (52-52)
src/lib/api/Contacts.ts (2)
src/lib/api/resources/contacts/Contacts.ts (1)
  • ContactsApi (8-40)
src/lib/api/resources/contacts/ContactLists.ts (1)
  • ContactListsApi (8-24)
src/lib/api/resources/contacts/Contacts.ts (1)
src/types/mailtrap.ts (1)
  • ContactData (121-125)
src/__tests__/lib/mailtrap-client.test.ts (1)
src/lib/MailtrapError.ts (1)
  • MailtrapError (1-1)
src/lib/MailtrapClient.ts (4)
src/lib/api/resources/contacts/Contacts.ts (1)
  • ContactsApi (8-40)
src/lib/api/resources/contacts/ContactLists.ts (1)
  • ContactListsApi (8-24)
src/types/mailtrap.ts (2)
  • BatchSendRequest (105-113)
  • BatchSendResponse (74-77)
src/lib/mail-buffer-encoder.ts (1)
  • encodeMailBuffers (8-33)
🪛 LanguageTool
README.md

[grammar] ~61-~61: You’ve repeated a verb. Did you mean to only write one of them?
Context: ...s](examples/general/permissions.ts) - Contacts - [Contact Lists](examples/contacts/contact-lists....

(REPEATED_VERBS)


[grammar] ~74-~74: Possible verb agreement error. Did you mean “sends”? (Some collective nouns can be treated as both singular and plural, so ‘Send’ is not always incorrect.)
Context: ...ails](examples/batch/send-batch.ts) - [Send a batch of transactional emails](exampl...

(COLLECTIVE_NOUN_VERB_AGREEMENT_VBP)

🪛 markdownlint-cli2 (0.17.2)
README.md

61-61: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


62-62: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


73-73: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


74-74: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


75-75: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


76-76: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

🔇 Additional comments (10)
examples/testing/send-mail.ts (1)

7-7: Documentation enhancement looks good!

Adding a more specific link to the Demo Domain setup section is helpful for users following this example. This improves the documentation quality.

examples/contacts/contact-lists.ts (1)

1-20: Well-structured example for the new contactLists API

This example effectively demonstrates how to use the newly added contactLists API, providing a clear pattern for users to follow. The code showcases:

  • Proper initialization of the client with token and accountId
  • Direct access to the contactLists getter
  • Appropriate error handling

This example aligns well with the PR objective of integrating contact lists APIs into the Mailtrap client as direct getters.

README.md (2)

61-62: Documentation updates for new contact APIs look good

Adding references to the new contact-related examples aligns with the PR objective of integrating contacts and contact lists APIs into the Mailtrap client.

🧰 Tools
🪛 LanguageTool

[grammar] ~61-~61: You’ve repeated a verb. Did you mean to only write one of them?
Context: ...s](examples/general/permissions.ts) - Contacts - [Contact Lists](examples/contacts/contact-lists....

(REPEATED_VERBS)

🪛 markdownlint-cli2 (0.17.2)

61-61: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


62-62: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


71-77: New Batch Sending API section enhances documentation

This new section with examples for batch sending provides valuable user guidance. While batch sending isn't mentioned in the PR objectives, it complements the contacts API integration by providing comprehensive documentation.

🧰 Tools
🪛 LanguageTool

[grammar] ~74-~74: Possible verb agreement error. Did you mean “sends”? (Some collective nouns can be treated as both singular and plural, so ‘Send’ is not always incorrect.)
Context: ...ails](examples/batch/send-batch.ts) - [Send a batch of transactional emails](exampl...

(COLLECTIVE_NOUN_VERB_AGREEMENT_VBP)

🪛 markdownlint-cli2 (0.17.2)

73-73: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


74-74: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


75-75: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


76-76: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

src/lib/mail-buffer-encoder.ts (1)

8-8: Good improvement to function signature flexibility

Changing from Mail to Partial<Mail> allows the function to handle objects with any subset of Mail properties. This increases the function's reusability and makes it compatible with partial mail objects that might be used in batch operations or contact-related functionality.

The implementation correctly maintains its behavior while supporting this more flexible type.

examples/batch/bulk.ts (1)

1-40: Well-structured batch email example with proper error handling

This example clearly demonstrates how to use the batch sending API for multiple recipients with custom variables. The code structure follows best practices with promise chaining and proper error handling.

examples/batch/template.ts (1)

1-39: Clear template-based batch sending example

The example effectively demonstrates how to use the template-based batch sending capability with different template variables for each recipient. The code is well-structured and follows consistent patterns with other examples.

examples/contacts/everything.ts (1)

1-37: Overall good example demonstrating contact lifecycle management

This example effectively shows the complete contact lifecycle including creation, updating, and deletion. The code is well-structured with appropriate error handling.

Also applies to: 41-44

examples/batch/transactional.ts (1)

1-37: Well-structured example demonstrating batch transactional email sending

This example clearly demonstrates how to use the batch sending API with a well-organized structure including base email configuration, multiple recipient requests with custom variables, and proper promise handling.

examples/batch/sandbox.ts (1)

1-42: Well-implemented sandbox mode example

This example correctly demonstrates how to configure the client for sandbox mode with a test inbox ID and structure a batch send request with custom variables. The code follows good practices for promise handling and clearly shows the configuration differences compared to standard transactional sending.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
README.md (2)

61-62: Remove leading space before list items under "General API"
The list markers for the new "Contacts" and "Contact Lists" entries are indented and trigger markdownlint MD007. They should be aligned at the margin.

-  - [Contacts](examples/contacts/everything.ts)
+ - [Contacts](examples/contacts/everything.ts)

-  - [Contact Lists](examples/contacts/contact-lists.ts)
+ - [Contact Lists](examples/contacts/contact-lists.ts)
🧰 Tools
🪛 LanguageTool

[grammar] ~61-~61: You’ve repeated a verb. Did you mean to only write one of them?
Context: ...s](examples/general/permissions.ts) - Contacts - [Contact Lists](examples/contacts/contact-lists....

(REPEATED_VERBS)

🪛 markdownlint-cli2 (0.17.2)

61-61: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


62-62: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


73-76: Remove leading space before list items under "Batch Sending API"
The new batch sending example entries are indented and trigger markdownlint MD007. Align the list markers at the root margin for consistency.

-  - [Send a batch of emails](examples/batch/send-batch.ts)
+ - [Send a batch of emails](examples/batch/send-batch.ts)

-  - [Send a batch of transactional emails](examples/batch/transactional-batch.ts)
+ - [Send a batch of transactional emails](examples/batch/transactional-batch.ts)

-  - [Send a batch of bulk emails](examples/batch/bulk-batch.ts)
+ - [Send a batch of bulk emails](examples/batch/bulk-batch.ts)

-  - [Send a batch of sandbox emails](examples/batch/sandbox-batch.ts)
+ - [Send a batch of sandbox emails](examples/batch/sandbox-batch.ts)
🧰 Tools
🪛 LanguageTool

[grammar] ~74-~74: Possible verb agreement error. Did you mean “sends”? (Some collective nouns can be treated as both singular and plural, so ‘Send’ is not always incorrect.)
Context: ...ails](examples/batch/send-batch.ts) - [Send a batch of transactional emails](exampl...

(COLLECTIVE_NOUN_VERB_AGREEMENT_VBP)

🪛 markdownlint-cli2 (0.17.2)

73-73: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


74-74: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


75-75: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


76-76: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 91b0cde and 7f75f82.

📒 Files selected for processing (3)
  • README.md (2 hunks)
  • src/lib/api/Contacts.ts (1 hunks)
  • src/types/mailtrap.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/types/mailtrap.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/api/Contacts.ts
🧰 Additional context used
🪛 LanguageTool
README.md

[grammar] ~61-~61: You’ve repeated a verb. Did you mean to only write one of them?
Context: ...s](examples/general/permissions.ts) - Contacts - [Contact Lists](examples/contacts/contact-lists....

(REPEATED_VERBS)


[grammar] ~74-~74: Possible verb agreement error. Did you mean “sends”? (Some collective nouns can be treated as both singular and plural, so ‘Send’ is not always incorrect.)
Context: ...ails](examples/batch/send-batch.ts) - [Send a batch of transactional emails](exampl...

(COLLECTIVE_NOUN_VERB_AGREEMENT_VBP)

🪛 markdownlint-cli2 (0.17.2)
README.md

61-61: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


62-62: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


73-73: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


74-74: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


75-75: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


76-76: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

@narekhovhannisyan narekhovhannisyan marked this pull request as draft May 17, 2025 18:31
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
src/__tests__/lib/api/resources/Contacts.test.ts (2)

31-31: Test data correctly matches the Contact interface.

The string ID in the mock response correctly matches the Contact interface definition where id: string. The past review comment suggesting this should be a number appears to be outdated.


39-40: Test data correctly matches the Contact interface.

The numeric timestamps in the mock response correctly match the Contact interface definition where created_at: number and updated_at: number. The past review comment suggesting these should be strings appears to be outdated.

🧹 Nitpick comments (1)
examples/contacts/everything.ts (1)

40-42: Consider adding more context to error logging.

For better debugging in real applications, consider including the operation context in error messages.

  .catch(error => {
-   console.error("Error in contact lifecycle:", error);
+   console.error("Error in contact lifecycle (create/update/delete):", error);
  }); 
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de5cb1c and d697894.

📒 Files selected for processing (6)
  • examples/contacts/everything.ts (1 hunks)
  • src/__tests__/lib/api/Contacts.test.ts (1 hunks)
  • src/__tests__/lib/api/resources/Contacts.test.ts (1 hunks)
  • src/lib/api/Contacts.ts (1 hunks)
  • src/lib/api/resources/Contacts.ts (1 hunks)
  • src/types/api/contacts.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/tests/lib/api/Contacts.test.ts
  • src/lib/api/resources/Contacts.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/__tests__/lib/api/resources/Contacts.test.ts (3)
src/lib/api/resources/Contacts.ts (1)
  • ContactsApi (14-61)
src/lib/axios-logger.ts (1)
  • handleSendingError (20-69)
src/lib/MailtrapError.ts (1)
  • MailtrapError (1-1)
src/lib/api/Contacts.ts (2)
src/lib/api/resources/Contacts.ts (1)
  • ContactsApi (14-61)
src/lib/MailtrapClient.ts (1)
  • contacts (109-111)
🔇 Additional comments (9)
examples/contacts/everything.ts (1)

20-42: LGTM! Consistent API usage throughout the contact lifecycle.

The example correctly demonstrates the contact lifecycle using the direct client.contacts getter, which aligns perfectly with the PR objectives of providing straightforward access to contact APIs.

src/lib/api/Contacts.ts (1)

5-27: LGTM! Clean wrapper implementation with proper method binding.

The ContactsBaseAPI class provides a clean abstraction over ContactsApi with proper method binding to maintain context. The constructor correctly passes both client and accountId parameters to the underlying ContactsApi instance.

src/__tests__/lib/api/resources/Contacts.test.ts (4)

98-131: LGTM! Comprehensive test coverage for create method.

The tests properly cover both success and error scenarios with correct endpoint verification and error handling validation.


133-171: LGTM! Thorough testing of update method.

The update tests correctly verify the PATCH request with proper endpoint construction and error handling.


173-219: LGTM! Complete delete method test coverage.

The delete tests appropriately verify the DELETE request and error scenarios.


221-268: LGTM! Proper list method testing.

The list tests correctly validate the contact lists endpoint and error handling.

src/types/api/contacts.ts (3)

1-9: LGTM! Well-structured Contact interface.

The Contact interface provides a clear and comprehensive structure for contact data with appropriate types for each field.


11-21: LGTM! Clean data interfaces with proper inheritance.

The ContactData and ContactUpdateData interfaces are well-designed with ContactUpdateData appropriately extending ContactData to add list management fields.


23-25: LGTM! Consistent response wrapper interface.

The ContactResponse interface follows the expected API response pattern by wrapping the Contact data.

Copy link
Contributor

@mklocek mklocek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • README lists example files that don't exist
  • ContactLists should probably be their own "API" because there will be more ContactLists methods
  • We need small adjustments to type definitions

README.md Outdated
Comment on lines 64 to 65
- [Contacts](examples/contacts/contacts.ts)
- [Contact Lists](examples/contacts/contact-lists.ts)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no such files

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And there is no link to everything.ts

Comment on lines 6 to 7
const testInboxId = 100;
const contactsAPI = new Contacts(axios, testInboxId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not an inbox ID

Suggested change
const testInboxId = 100;
const contactsAPI = new Contacts(axios, testInboxId);
const accountId = 100;
const contactsAPI = new Contacts(axios, accountId);

Comment on lines 55 to 58
/**
* Gets a list of contact lists.
*/
public async list() {
Copy link
Contributor

@mklocek mklocek Jun 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's a list of lists, I think the method should be plural then. But also, I have seen we already exposed ContactLists API operations like create and update, so ContactLists should probably be a separate "API", not just a method on Contacts API.

https://api-docs.mailtrap.io/docs/mailtrap-api-docs/e3bba0bfa185e-create-contact-list

Suggested change
/**
* Gets a list of contact lists.
*/
public async list() {
/**
* Gets a list of contact lists.
*/
public async lists() {

Copy link
Contributor

@vittorius vittorius Jun 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mklocek I guess it's an "index" action for the Contact resource.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not, it requests contactListsURL (${GENERAL_ENDPOINT}/api/accounts/${accountId}/contacts/lists)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vittorius yes, otherwise we are having one more nesting layer, which is uncomfortable. In any case let me know which approach fits better and I will tune the implementation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no such thing as index of contacts. there is such thing as index of contact lists though, and there are also endpoints for creating, updating contact lists etc. it's a separate "resource"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mklocek seems create and update was added recently, I can provide it with separate PR

updated_at: number;
list_ids: number[];
status: "subscribed" | "unsubscribed";
fields: Record<string, string>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The values can be: string | integer | float | boolean | date string in ISO-8601 format

export interface ContactFields {
first_name?: string;
last_name?: string;
[key: string]: string | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The values can be: string | integer | float | boolean | date string in ISO-8601 format

Comment on lines 128 to 129
first_name?: string;
last_name?: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are default fields but are not required (users can delete them). I think they shouldn't be part of the type definition

@mklocek mklocek requested a review from vittorius June 3, 2025 06:34
Copy link
Contributor

@vittorius vittorius left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I support Marcin's comments and also added a couple of my own

README.md Outdated
Comment on lines 64 to 65
- [Contacts](examples/contacts/contacts.ts)
- [Contact Lists](examples/contacts/contact-lists.ts)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And there is no link to everything.ts

Comment on lines 55 to 58
/**
* Gets a list of contact lists.
*/
public async list() {
Copy link
Contributor

@vittorius vittorius Jun 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mklocek I guess it's an "index" action for the Contact resource.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
README.md (1)

62-65: Fix list indentation for Contacts API.

The list item under the Contacts API section has an extra leading space and violates MD007 (ul-indent). It should start at column 0 for consistency with the lint rules.

-  - [Contacts](examples/contacts/everything.ts)
+- [Contacts](examples/contacts/everything.ts)
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

64-64: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d697894 and 8d01d01.

📒 Files selected for processing (5)
  • README.md (1 hunks)
  • examples/contacts/everything.ts (1 hunks)
  • src/__tests__/lib/api/Contacts.test.ts (1 hunks)
  • src/lib/api/Contacts.ts (1 hunks)
  • src/lib/api/resources/Contacts.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/tests/lib/api/Contacts.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • examples/contacts/everything.ts
  • src/lib/api/Contacts.ts
  • src/lib/api/resources/Contacts.ts
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
README.md

64-64: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

🔇 Additional comments (1)
README.md (1)

64-64:

✅ Verification successful

Verify example file presence.

Ensure that examples/contacts/everything.ts exists in the repository and is correctly linked in the README.


🏁 Script executed:

#!/bin/bash
# Verify the presence of the Contacts example script.
if [ ! -f examples/contacts/everything.ts ]; then
  echo "Error: examples/contacts/everything.ts not found"
  exit 1
fi
echo "OK: examples/contacts/everything.ts exists."

Length of output: 145


Example file verified in README
The examples/contacts/everything.ts file exists in the repository and is correctly referenced in README.md. No further action is needed.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

64-64: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/__tests__/lib/api/resources/Contacts.test.ts (1)

31-31: Data type inconsistencies persist from past reviews.

The mock data still contains type inconsistencies that were flagged in previous reviews:

  1. ID fields: Using strings (e.g., "018dd5e3-f6d2-7c00-8f9b-e5c3f2d8a132") but should be numbers according to past review feedback
  2. Timestamp fields: Using numbers (e.g., 1742820600230) but should be strings according to past review feedback

These inconsistencies could cause type validation issues and test failures.

Apply these fixes to align with the Contact interface:

-      id: "018dd5e3-f6d2-7c00-8f9b-e5c3f2d8a132",
+      id: 123456,
-      created_at: 1742820600230,
-      updated_at: 1742820600230,
+      created_at: "2025-01-27T14:30:00.230Z",
+      updated_at: "2025-01-27T14:30:00.230Z",

Apply similar fixes to all other mock responses in the file.

Also applies to: 39-40, 60-60, 62-63, 104-104, 106-107, 229-229, 237-238

🧹 Nitpick comments (2)
src/lib/api/Contacts.ts (1)

5-27: Consider simplifying the wrapper pattern or adding value.

The ContactsBaseAPI class is essentially a delegation wrapper around ContactsApi. While functional, this pattern adds complexity without clear benefits. Consider either:

  1. Directly exposing ContactsApi from the client
  2. Adding value in this wrapper (caching, validation, etc.)
  3. Using a factory function instead of a class

Current implementation works but could be streamlined:

-export default class ContactsBaseAPI {
-  private client: AxiosInstance;
-  private accountId?: number;
-  public get: ContactsApi["get"];
-  public create: ContactsApi["create"];
-  public update: ContactsApi["update"];
-  public delete: ContactsApi["delete"];
-
-  constructor(client: AxiosInstance, accountId?: number) {
-    this.client = client;
-    this.accountId = accountId;
-    const contacts = new ContactsApi(this.client, this.accountId);
-    this.get = contacts.get.bind(contacts);
-    this.create = contacts.create.bind(contacts);
-    this.update = contacts.update.bind(contacts);
-    this.delete = contacts.delete.bind(contacts);
-  }
-}
+export default function createContactsAPI(client: AxiosInstance, accountId?: number) {
+  return new ContactsApi(client, accountId);
+}
src/__tests__/lib/api/resources/Contacts.test.ts (1)

75-80: Add missing assertion for the 'get' method.

The initialization test checks for create, update, and delete methods but omits the get method, which is also part of the ContactsApi interface.

 it("initializes with all necessary params.", () => {
+  expect(contactsAPI).toHaveProperty("get");
   expect(contactsAPI).toHaveProperty("create");
   expect(contactsAPI).toHaveProperty("update");
   expect(contactsAPI).toHaveProperty("delete");
 });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 970fe76 and 272964f.

📒 Files selected for processing (3)
  • src/__tests__/lib/api/Contacts.test.ts (1 hunks)
  • src/__tests__/lib/api/resources/Contacts.test.ts (1 hunks)
  • src/lib/api/Contacts.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/tests/lib/api/Contacts.test.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/lib/api/Contacts.ts (2)
src/lib/api/resources/Contacts.ts (1)
  • ContactsApi (13-59)
src/lib/MailtrapClient.ts (1)
  • contacts (109-111)
src/__tests__/lib/api/resources/Contacts.test.ts (3)
src/lib/api/resources/Contacts.ts (1)
  • ContactsApi (13-59)
src/lib/axios-logger.ts (1)
  • handleSendingError (20-69)
src/lib/MailtrapError.ts (1)
  • MailtrapError (1-1)
🔇 Additional comments (1)
src/__tests__/lib/api/resources/Contacts.test.ts (1)

83-96: Excellent test coverage and structure.

The test suite demonstrates good practices:

  • Proper setup/teardown with axios interceptors
  • Comprehensive coverage of all CRUD operations
  • Both success and error scenarios tested
  • Correct use of axios-mock-adapter
  • Proper error handling verification with MailtrapError

Also applies to: 98-269

@narekhovhannisyan narekhovhannisyan merged commit f97f15f into main Jun 9, 2025
4 checks passed
@narekhovhannisyan narekhovhannisyan deleted the contacts-api branch June 9, 2025 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants