Skip to content

Conversation

@dr-3lo
Copy link
Collaborator

@dr-3lo dr-3lo commented Sep 22, 2025

Motivation

Contacts Events API support into .NET client #151

Changes

  • Added Contact Events management interfaces, models, requests, and validation
  • Added example project to demonstrate Contact Events API usage
  • Updated Contacts interface to provide access to Contact Events
  • Added Contact Events unit tests and integration tests
  • Extended Contacts unit tests to cover new methods for accessing events

How to test

Summary by CodeRabbit

  • New Features
    • Introduced Contact Events support: create events for a contact via the client.
    • Added validation for event name and parameter keys.
    • Provided a runnable example app demonstrating Contact Events usage with configuration.
  • Documentation
    • Added sample appsettings with Mailtrap API token placeholder and logging defaults.
  • Tests
    • Added unit tests for request validation and resource construction.
    • Added integration tests covering successful event creation and validation failures.

- Added Contact Events management interfaces, models, requests, and validation
- Added example project to demonstrate Contact Events API usage
- Updated Contacts interface to provide access to Contact Events
- Added Contact Events unit tests and integration tests
- Extended Contacts unit tests to cover new methods for accessing events
@coderabbitai
Copy link

coderabbitai bot commented Sep 22, 2025

Walkthrough

Adds Contact Events feature: new abstractions (model, request, validator, interface), concrete resource and navigation from contacts, example console project, global usings, solution wiring, and comprehensive unit/integration tests with JSON fixtures.

Changes

Cohort / File(s) Summary
Solution & project wiring
Mailtrap.sln
Registers new example project examples\Mailtrap.Example.ContactEvents\...csproj, adds build configs and nesting.
Example app (Contact Events)
examples/Mailtrap.Example.ContactEvents/*, .../Program.cs, .../appsettings.json, .../Properties/launchSettings.json, .../Mailtrap.Example.ContactEvents.csproj
New console app demonstrating contact retrieval/creation and event creation via DI, config, and logging; references Http and Json; copies appsettings on build.
Abstractions: Contact Events API
src/Mailtrap.Abstractions/ContactEvents/IContactsEventCollectionResource.cs, .../Models/ContactsEvent.cs, .../Requests/CreateContactsEventRequest.cs, .../Validators/CreateContactsEventRequestValidator.cs, src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs, src/Mailtrap.Abstractions/GlobalUsings.cs
Introduces Contact Events contract: resource interface with Create, event model, create request (validation, JSON attrs), validator, navigation method Events(string contactId) on contacts, and global usings.
Runtime implementation
src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs, src/Mailtrap/Contacts/ContactCollectionResource.cs, src/Mailtrap/GlobalUsings.cs
Implements events collection resource with Create, extends contacts resource with Events(contactId) and URI segment, adds global usings.
Integration tests & fixtures
tests/Mailtrap.IntegrationTests/ContactEvents/*, tests/Mailtrap.IntegrationTests/GlobalUsings.cs
Adds integration tests for create (plain/with params), validation failure paths; provides request/response JSON fixtures; adds global usings.
Unit tests
tests/Mailtrap.UnitTests/ContactEvents/ContactsEventCollectionResourceTests.cs, tests/Mailtrap.UnitTests/ContactEvents/Requests/CreateContactsEventRequestTests.cs, tests/Mailtrap.UnitTests/Contacts/ContactCollectionResourceTests.cs, tests/Mailtrap.UnitTests/GlobalUsings.cs
Tests resource constructor/URI wiring, request behavior and validation boundaries, and contacts -> events navigation; adds global usings.
Test constants
tests/.../TestConstants/UrlSegmentsTestConstants.cs
Adds EventsSegment = "events" to URL segments for tests.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App as Example App
  participant Client as IMailtrapClient
  participant Accounts as Accounts Resource
  participant Contacts as Contacts Resource
  participant Events as ContactsEventCollectionResource
  participant API as Mailtrap API

  App->>Client: Resolve from DI
  App->>Accounts: client.Accounts(accountId)
  Accounts->>Contacts: .Contacts()
  Contacts->>Events: .Events(contactId)
  App->>Events: Create(request)
  Events->>API: POST /accounts/{id}/contacts/{contactId}/events
  API-->>Events: 201 Created (ContactsEvent)
  Events-->>App: ContactsEvent
  App->>App: Log event details
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • mklocek
  • zhaparoff
  • vittorius

Poem

A hop, a skip, an event appears—
Contacts now can mark their cheers.
I tap my paw, post JSON neat,
201—what a treat!
Params in pockets, logs alight—
Burrow builds green, all tests take flight. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly and accurately summarizes the primary change — adding Contact Events API support — and references the related issue, making it concise, specific, and relevant to the changeset for quick history scanning.
Description Check ✅ Passed The PR description follows the repository template by providing a clear Motivation, a detailed Changes list, and a How to test section with actionable checkboxes and links to tests and the example project; these items give reviewers the necessary context and testing steps. The Images and GIFs section from the template is not present but is non-critical for this feature-focused change. Overall the description is complete and actionable.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/151-Contact-Events

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

@dr-3lo dr-3lo linked an issue Sep 22, 2025 that may be closed by this pull request
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: 4

🧹 Nitpick comments (11)
examples/Mailtrap.Example.ContactEvents/appsettings.json (1)

1-17: Avoid secrets in repo; prefer env vars or user‑secrets

Keep the placeholder, and document using Mailtrap__ApiToken env var or dotnet user‑secrets to supply the token at run time.

src/Mailtrap.Abstractions/ContactEvents/IContactsEventsCollectionResource.cs (1)

1-1: Rename file to match type name.

File is IContactsEventsCollectionResource.cs but type is IContactsEventCollectionResource. Please align.

examples/Mailtrap.Example.ContactEvents/Program.cs (3)

29-31: Use configuration for accountId instead of a magic number.

Improves portability of the example.

Apply:

-    var accountId = 12345;
+    var accountId = hostBuilder.Configuration.GetSection("Mailtrap").GetValue<long?>("AccountId") ?? 12345;

56-56: Nullability warning: contact may be considered nullable by the compiler.

Make the intent explicit to avoid CS8602.

Apply:

-    IContactsEventCollectionResource contactsEventsResource = contactsResource.Events(contact.Id);
+    IContactsEventCollectionResource contactsEventsResource = contactsResource.Events(contact!.Id);

64-64: Log message label is incorrect.

“Created At” doesn’t match the logged value (ContactEmail).

Apply:

-    logger.LogInformation("Created At: {ContactEmail}", contactsEvent.ContactEmail);
+    logger.LogInformation("Contact Email: {ContactEmail}", contactsEvent.ContactEmail);
src/Mailtrap.Abstractions/ContactEvents/Validators/CreateContactsEventRequestValidator.cs (1)

23-31: Simplify key validation with RuleForEach; current ChildRules usage is unnecessary.

This is clearer and aligns with typical FluentValidation patterns.

Apply:

-        When(r => r.Params != null && r.Params.Count > 0, () =>
-        {
-            RuleFor(r => r.Params.Keys)
-            .Cascade(CascadeMode.Stop)
-            .ChildRules(r =>
-                {
-                    r.RuleForEach(k => k).NotEmpty().MaximumLength(255);
-                });
-        });
+        When(r => r.Params != null && r.Params.Count > 0, () =>
+        {
+            RuleForEach(r => r.Params.Keys)
+                .Cascade(CascadeMode.Stop)
+                .NotEmpty()
+                .MaximumLength(255);
+        });
tests/Mailtrap.UnitTests/ContactEvents/Requests/CreateContactsEventRequestTests.cs (1)

27-45: Add a test to assert defensive copy semantics for Params.

Ensure later mutations of the source dictionary don’t affect the request state.

Add:

@@
     public void Constructor_ShouldInitializeFieldsCorrectly()
     {
@@
         request.Params.Should().BeEquivalentTo(parameters);
     }
+
+    [Test]
+    public void Constructor_ShouldDefensivelyCopyParams()
+    {
+        // Arrange
+        var src = new Dictionary<string, object?> { { "k", "v" } };
+        var request = new CreateContactsEventRequest("name", src);
+
+        // Act
+        src["k"] = "changed";
+        src["new"] = 123;
+
+        // Assert
+        request.Params.Should().BeEquivalentTo(new Dictionary<string, object?> { { "k", "v" } });
+    }
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1)

15-18: Minor: default-initialize Name at the property for consistency.

Keeps defaults visible in one place; behavior unchanged.

Apply:

-    public string Name { get; set; }
+    public string Name { get; set; } = string.Empty;

And simplify the parameterless ctor:

-    [JsonConstructor]
-    public CreateContactsEventRequest()
-    {
-        Name = string.Empty;
-    }
+    [JsonConstructor]
+    public CreateContactsEventRequest() { }
tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventsIntegrationTests.cs (3)

45-51: Silence nullable warnings for deserialization results.

Use the null‑forgiving operator so the compiler knows these aren’t null after assertions.

-        var request = JsonSerializer.Deserialize<CreateContactsEventRequest>(requestContent, _jsonSerializerOptions);
-        request.Should().NotBeNull();
+        var request = JsonSerializer.Deserialize<CreateContactsEventRequest>(requestContent, _jsonSerializerOptions)!;
+        request.Should().NotBeNull();

-        var expectedResponse = await responseContent.DeserializeStringContentAsync<ContactsEvent>(_jsonSerializerOptions);
-        expectedResponse.Should().NotBeNull();
+        var expectedResponse = (await responseContent.DeserializeStringContentAsync<ContactsEvent>(_jsonSerializerOptions))!;
+        expectedResponse.Should().NotBeNull();
-        var request = JsonSerializer.Deserialize<CreateContactsEventRequest>(requestContent, _jsonSerializerOptions);
-        request.Should().NotBeNull();
+        var request = JsonSerializer.Deserialize<CreateContactsEventRequest>(requestContent, _jsonSerializerOptions)!;
+        request.Should().NotBeNull();

-        var expectedResponse = await responseContent.DeserializeStringContentAsync<ContactsEvent>(_jsonSerializerOptions);
-        expectedResponse.Should().NotBeNull();
+        var expectedResponse = (await responseContent.DeserializeStringContentAsync<ContactsEvent>(_jsonSerializerOptions))!;
+        expectedResponse.Should().NotBeNull();

Also applies to: 95-101


39-83: DRY the duplicated Arrange/Act in success tests.

Both success tests are identical aside from fixtures. Extract a helper to reduce duplication and speed up future edits.

     [Test]
     public async Task Create_WithParams_Success()
     {
-        // Arrange
-        var httpMethod = HttpMethod.Post;
-        var requestUri = _resourceUri.AbsoluteUri;
-        ...
-        result.ShouldBeEquivalentToContactResponse(expectedResponse);
+        await RunCreateSuccessAsync();
     }
@@
     [Test]
     public async Task Create_Plain_Success()
     {
-        // Arrange
-        var httpMethod = HttpMethod.Post;
-        var requestUri = _resourceUri.AbsoluteUri;
-        ...
-        result.ShouldBeEquivalentToContactResponse(expectedResponse);
+        await RunCreateSuccessAsync();
     }

Add this helper inside the class:

private async Task RunCreateSuccessAsync()
{
    var httpMethod = HttpMethod.Post;
    var requestUri = _resourceUri.AbsoluteUri;

    var fileName = TestContext.CurrentContext.Test.MethodName;

    var requestContent = await Feature.LoadFileToString(fileName + "_Request");
    var request = JsonSerializer.Deserialize<CreateContactsEventRequest>(requestContent, _jsonSerializerOptions)!;
    request.Should().NotBeNull();

    using var responseContent = await Feature.LoadFileToStringContent(fileName + "_Response");
    var expectedResponse = (await responseContent.DeserializeStringContentAsync<ContactsEvent>(_jsonSerializerOptions))!;
    expectedResponse.Should().NotBeNull();

    using var mockHttp = new MockHttpMessageHandler();
    mockHttp.Expect(httpMethod, requestUri)
        .WithHeaders("Authorization", $"Bearer {_clientConfig.ApiToken}")
        .WithHeaders("Accept", MimeTypes.Application.Json)
        .WithHeaders("User-Agent", HeaderValues.UserAgent.ToString())
        .WithJsonContent(request, _jsonSerializerOptions)
        .Respond(HttpStatusCode.Created, responseContent);

    var services = new ServiceCollection()
        .AddMailtrapClient(_clientConfig)
        .ConfigurePrimaryHttpMessageHandler(() => mockHttp)
        .BuildServiceProvider();

    using (services as IDisposable)
    {
        var client = services.GetRequiredService<IMailtrapClient>();
        var result = await client.Account(_accountId).Contacts().Events(_contactId).Create(request).ConfigureAwait(false);

        mockHttp.VerifyNoOutstandingExpectation();
        result.ShouldBeEquivalentToContactResponse(expectedResponse);
    }
}

Also applies to: 88-131


5-5: Class/file naming mismatch.

File is ContactsEventsIntegrationTests.cs, class is ContactsEventIntegrationTests. Align names for discoverability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e67010a and e3be3d4.

📒 Files selected for processing (26)
  • Mailtrap.sln (3 hunks)
  • examples/Mailtrap.Example.ContactEvents/Mailtrap.Example.ContactEvents.csproj (1 hunks)
  • examples/Mailtrap.Example.ContactEvents/Program.cs (1 hunks)
  • examples/Mailtrap.Example.ContactEvents/Properties/launchSettings.json (1 hunks)
  • examples/Mailtrap.Example.ContactEvents/appsettings.json (1 hunks)
  • src/Mailtrap.Abstractions/ContactEvents/IContactsEventsCollectionResource.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactEvents/Models/ContactsEvent.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactEvents/Validators/CreateContactsEventRequestValidator.cs (1 hunks)
  • src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (1 hunks)
  • src/Mailtrap.Abstractions/GlobalUsings.cs (1 hunks)
  • src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs (1 hunks)
  • src/Mailtrap/Contacts/ContactCollectionResource.cs (2 hunks)
  • src/Mailtrap/GlobalUsings.cs (1 hunks)
  • tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventsIntegrationTests.cs (1 hunks)
  • tests/Mailtrap.IntegrationTests/ContactEvents/Create_Plain_Success_Request.json (1 hunks)
  • tests/Mailtrap.IntegrationTests/ContactEvents/Create_Plain_Success_Response.json (1 hunks)
  • tests/Mailtrap.IntegrationTests/ContactEvents/Create_WithParams_Success_Request.json (1 hunks)
  • tests/Mailtrap.IntegrationTests/ContactEvents/Create_WithParams_Success_Response.json (1 hunks)
  • tests/Mailtrap.IntegrationTests/GlobalUsings.cs (1 hunks)
  • tests/Mailtrap.IntegrationTests/TestConstants/UrlSegmentsTestConstants.cs (1 hunks)
  • tests/Mailtrap.UnitTests/ContactEvents/ContactsEventCollectionResourceTests.cs (1 hunks)
  • tests/Mailtrap.UnitTests/ContactEvents/Requests/CreateContactsEventRequestTests.cs (1 hunks)
  • tests/Mailtrap.UnitTests/Contacts/ContactCollectionResourceTests.cs (1 hunks)
  • tests/Mailtrap.UnitTests/GlobalUsings.cs (1 hunks)
  • tests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs (1 hunks)
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2025-09-22T08:20:57.349Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#150
File: src/Mailtrap.Abstractions/ContactFields/Validators/CreateContactsFieldRequestValidator.cs:8-8
Timestamp: 2025-09-22T08:20:57.349Z
Learning: In the Mailtrap.Abstractions project, global using statements in GlobalUsings.cs make types from Mailtrap.ContactFields.Requests (and other ContactFields namespaces) globally available, so explicit using statements are not needed in individual files like validators.

Applied to files:

  • tests/Mailtrap.UnitTests/GlobalUsings.cs
  • src/Mailtrap/GlobalUsings.cs
  • src/Mailtrap.Abstractions/GlobalUsings.cs
  • src/Mailtrap.Abstractions/ContactEvents/Validators/CreateContactsEventRequestValidator.cs
  • examples/Mailtrap.Example.ContactEvents/Program.cs
  • examples/Mailtrap.Example.ContactEvents/Mailtrap.Example.ContactEvents.csproj
  • tests/Mailtrap.IntegrationTests/GlobalUsings.cs
  • Mailtrap.sln
📚 Learning: 2025-09-22T08:20:27.713Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#150
File: src/Mailtrap.Abstractions/ContactFields/Validators/CreateContactsFieldRequestValidator.cs:1-1
Timestamp: 2025-09-22T08:20:27.713Z
Learning: In the Mailtrap .NET project, FluentValidation is imported globally through GlobalUsings.cs files, making explicit using statements for FluentValidation unnecessary in individual validator files within the project.

Applied to files:

  • tests/Mailtrap.UnitTests/GlobalUsings.cs
  • src/Mailtrap/GlobalUsings.cs
  • src/Mailtrap.Abstractions/GlobalUsings.cs
  • tests/Mailtrap.IntegrationTests/GlobalUsings.cs
📚 Learning: 2025-09-22T09:52:44.028Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#150
File: examples/Mailtrap.Example.ContactFields/Mailtrap.Example.ContactFields.csproj:1-10
Timestamp: 2025-09-22T09:52:44.028Z
Learning: In the Mailtrap .NET client project, example projects use a centralized `mailtrap-example.props` file to define common MSBuild properties like TargetFramework, so individual .csproj files don't need to explicitly declare these properties.

Applied to files:

  • tests/Mailtrap.UnitTests/GlobalUsings.cs
  • examples/Mailtrap.Example.ContactEvents/Properties/launchSettings.json
  • src/Mailtrap/GlobalUsings.cs
  • src/Mailtrap.Abstractions/GlobalUsings.cs
  • examples/Mailtrap.Example.ContactEvents/Program.cs
  • examples/Mailtrap.Example.ContactEvents/Mailtrap.Example.ContactEvents.csproj
  • examples/Mailtrap.Example.ContactEvents/appsettings.json
  • tests/Mailtrap.IntegrationTests/GlobalUsings.cs
  • Mailtrap.sln
📚 Learning: 2025-09-04T12:22:07.783Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#139
File: src/Mailtrap/Contacts/Requests/ContactRequestExtensions.cs:6-9
Timestamp: 2025-09-04T12:22:07.783Z
Learning: In the Mailtrap .NET client codebase, internal extension methods with non-nullable reference types don't require explicit null guards as the compiler provides compile-time safety and call sites are controlled within the codebase.

Applied to files:

  • tests/Mailtrap.UnitTests/GlobalUsings.cs
  • src/Mailtrap/GlobalUsings.cs
  • src/Mailtrap.Abstractions/GlobalUsings.cs
  • examples/Mailtrap.Example.ContactEvents/Program.cs
  • tests/Mailtrap.IntegrationTests/GlobalUsings.cs
📚 Learning: 2025-09-04T12:23:59.276Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#139
File: tests/Mailtrap.IntegrationTests/Contacts/Update_Success.json:16-17
Timestamp: 2025-09-04T12:23:59.276Z
Learning: Test fixtures in the Mailtrap .NET client should accurately represent the actual server response format and should not be modified to match client-side converters or serialization preferences.

Applied to files:

  • tests/Mailtrap.IntegrationTests/ContactEvents/Create_WithParams_Success_Response.json
  • examples/Mailtrap.Example.ContactEvents/Program.cs
  • tests/Mailtrap.IntegrationTests/ContactEvents/Create_Plain_Success_Response.json
  • tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventsIntegrationTests.cs
📚 Learning: 2025-09-04T08:53:06.292Z
Learnt from: vittorius
PR: railsware/mailtrap-dotnet#139
File: src/Mailtrap.Abstractions/Contacts/Models/Contact.cs:67-70
Timestamp: 2025-09-04T08:53:06.292Z
Learning: In the Mailtrap .NET client, DateTimeOffset properties should not use explicit JsonConverter attributes. All models in the codebase (TestingMessage, Inbox, EmailAttachment, etc.) handle DateTimeOffset properties using default JSON serialization without custom converters, and the Contact model should follow this same pattern for consistency.

Applied to files:

  • tests/Mailtrap.IntegrationTests/ContactEvents/Create_WithParams_Success_Response.json
  • src/Mailtrap.Abstractions/ContactEvents/Models/ContactsEvent.cs
  • examples/Mailtrap.Example.ContactEvents/Mailtrap.Example.ContactEvents.csproj
📚 Learning: 2025-09-10T17:01:49.270Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#142
File: src/Mailtrap.Abstractions/ContactImports/Validators/ContactsImportRequestValidator.cs:27-30
Timestamp: 2025-09-10T17:01:49.270Z
Learning: In ContactsImportRequestValidator, ContactRequestValidator.Instance is used to validate ContactImportRequest items because ContactImportRequest inherits from ContactRequest and doesn't introduce additional validation rules that would require a separate validator.

Applied to files:

  • src/Mailtrap.Abstractions/ContactEvents/Validators/CreateContactsEventRequestValidator.cs
🧬 Code graph analysis (11)
src/Mailtrap.Abstractions/ContactEvents/IContactsEventsCollectionResource.cs (4)
src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (3)
  • IContactsEventCollectionResource (98-98)
  • Task (111-111)
  • Task (128-128)
src/Mailtrap/Contacts/ContactCollectionResource.cs (3)
  • IContactsEventCollectionResource (34-35)
  • Task (37-38)
  • Task (40-41)
src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs (2)
  • Task (11-12)
  • Task (14-15)
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1)
  • CreateContactsEventRequest (53-66)
src/Mailtrap.Abstractions/ContactEvents/Validators/CreateContactsEventRequestValidator.cs (1)
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1)
  • CreateContactsEventRequest (53-66)
tests/Mailtrap.UnitTests/Contacts/ContactCollectionResourceTests.cs (5)
tests/Mailtrap.UnitTests/TestExtensions/ResourceValidator.cs (2)
  • ResourceValidator (4-16)
  • Validate (6-15)
src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (1)
  • IContactsEventCollectionResource (98-98)
src/Mailtrap/Contacts/ContactCollectionResource.cs (1)
  • IContactsEventCollectionResource (34-35)
src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs (2)
  • ContactsEventCollectionResource (6-16)
  • ContactsEventCollectionResource (8-9)
tests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs (1)
  • UrlSegmentsTestConstants (4-22)
tests/Mailtrap.UnitTests/ContactEvents/Requests/CreateContactsEventRequestTests.cs (2)
tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventsIntegrationTests.cs (5)
  • TestFixture (4-216)
  • Test (36-83)
  • Test (85-131)
  • Test (133-171)
  • Test (173-215)
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1)
  • CreateContactsEventRequest (53-66)
examples/Mailtrap.Example.ContactEvents/Program.cs (4)
src/Mailtrap.Abstractions/Contacts/Requests/CreateContactRequest.cs (1)
  • CreateContactRequest (19-19)
src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (1)
  • IContactsEventCollectionResource (98-98)
src/Mailtrap/Contacts/ContactCollectionResource.cs (1)
  • IContactsEventCollectionResource (34-35)
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1)
  • CreateContactsEventRequest (53-66)
src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs (5)
tests/Mailtrap.UnitTests/ContactEvents/ContactsEventCollectionResourceTests.cs (1)
  • ContactsEventCollectionResource (52-52)
src/Mailtrap/Contacts/ContactCollectionResource.cs (3)
  • IContactsEventCollectionResource (34-35)
  • Task (37-38)
  • Task (40-41)
src/Mailtrap.Abstractions/ContactEvents/IContactsEventsCollectionResource.cs (1)
  • Task (23-23)
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1)
  • CreateContactsEventRequest (53-66)
src/Mailtrap/ContactFields/ContactsFieldCollectionResource.cs (1)
  • ContactsFieldCollectionResource (6-16)
src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (1)
src/Mailtrap/Contacts/ContactCollectionResource.cs (1)
  • IContactsEventCollectionResource (34-35)
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (2)
src/Mailtrap.Abstractions/Core/Extensions/Ensure.cs (1)
  • Ensure (9-106)
src/Mailtrap.Abstractions/ContactEvents/Validators/CreateContactsEventRequestValidator.cs (2)
  • CreateContactsEventRequestValidator (9-33)
  • CreateContactsEventRequestValidator (19-32)
tests/Mailtrap.UnitTests/ContactEvents/ContactsEventCollectionResourceTests.cs (3)
tests/Mailtrap.UnitTests/Contacts/ContactCollectionResourceTests.cs (6)
  • Test (18-26)
  • Test (28-36)
  • Test (38-46)
  • Test (52-64)
  • Test (66-79)
  • Test (81-92)
tests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs (1)
  • UrlSegmentsTestConstants (4-22)
src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs (2)
  • ContactsEventCollectionResource (6-16)
  • ContactsEventCollectionResource (8-9)
tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventsIntegrationTests.cs (9)
tests/Mailtrap.UnitTests/ContactEvents/Requests/CreateContactsEventRequestTests.cs (7)
  • TestFixture (4-90)
  • Test (7-17)
  • Test (27-45)
  • Test (47-53)
  • Test (55-61)
  • Test (63-75)
  • Test (77-89)
src/Mailtrap/Configuration/MailtrapClientOptions.cs (1)
  • JsonSerializerOptions (148-154)
tests/Mailtrap.IntegrationTests/TestConstants/UrlSegmentsTestConstants.cs (1)
  • UrlSegmentsTestConstants (4-25)
src/Mailtrap.Abstractions/ContactEvents/IContactsEventsCollectionResource.cs (1)
  • Task (23-23)
src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs (2)
  • Task (11-12)
  • Task (14-15)
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1)
  • CreateContactsEventRequest (53-66)
src/Mailtrap/Core/Constants/MimeTypes.cs (2)
  • MimeTypes (4-19)
  • Application (6-11)
src/Mailtrap/Core/Constants/HeaderValues.cs (1)
  • HeaderValues (7-12)
tests/Mailtrap.IntegrationTests/TestExtensions/ValidationHelpers.cs (1)
  • ShouldBeEquivalentToContactResponse (25-40)
src/Mailtrap/Contacts/ContactCollectionResource.cs (2)
src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (1)
  • IContactsEventCollectionResource (98-98)
src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs (2)
  • ContactsEventCollectionResource (6-16)
  • ContactsEventCollectionResource (8-9)
🔇 Additional comments (21)
tests/Mailtrap.IntegrationTests/GlobalUsings.cs (1)

24-25: LGTM: ContactEvents namespaces added for integration tests

Matches the new feature surface; no issues.

src/Mailtrap/GlobalUsings.cs (1)

45-47: LGTM: Runtime global usings for ContactEvents

Keeps grouping aligned with other feature areas.

tests/Mailtrap.IntegrationTests/ContactEvents/Create_Plain_Success_Response.json (1)

1-5: Confirm fixture matches the real API response

Ensure these are exactly the fields the API returns for create (no missing id/timestamps or different casing). Don’t tailor fixtures to client-side converters.

tests/Mailtrap.IntegrationTests/ContactEvents/Create_WithParams_Success_Request.json (1)

1-9: Verify params typing/null handling align with server and validator

Confirm allowed scalar types and snake_case keys; ensure null values are accepted by the API and by CreateContactsEventRequestValidator.

examples/Mailtrap.Example.ContactEvents/Properties/launchSettings.json (1)

1-10: LGTM: Development profile

Straightforward dev setup.

tests/Mailtrap.UnitTests/GlobalUsings.cs (1)

35-36: Do not add Mailtrap.ContactEvents.Models to tests/Mailtrap.UnitTests/GlobalUsings.cs — not needed

ContactsEvent is only used in integration tests/examples; tests/Mailtrap.IntegrationTests/GlobalUsings.cs already includes global using Mailtrap.ContactEvents.Models and the model exists at src/Mailtrap.Abstractions/ContactEvents/Models/ContactsEvent.cs.

Likely an incorrect or invalid review comment.

tests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs (1)

21-21: LGTM — Events URL segment constant; tests use it. No other "events" string literal found in tests; all usages reference UrlSegmentsTestConstants.EventsSegment (defined in tests/Mailtrap.UnitTests/TestConstants/UrlSegmentsTestConstants.cs and tests/Mailtrap.IntegrationTests/TestConstants/UrlSegmentsTestConstants.cs).

examples/Mailtrap.Example.ContactEvents/Mailtrap.Example.ContactEvents.csproj (2)

1-11: Project configuration follows established patterns.

The project configuration follows the established pattern for example projects in the codebase, using the centralized mailtrap-example.props file for common properties and appropriately managing dependencies and content files.


3-4: Verify/pin package versions. PackageReference entries in examples/Mailtrap.Example.ContactEvents/Mailtrap.Example.ContactEvents.csproj (lines 3–4) omit explicit versions — pin them here or confirm central package management. Latest stable System.Text.Json: 9.0.8 (Aug 5, 2025). (nuget.org) Latest stable Microsoft.Extensions.Http: 9.0.9 (Sep 9, 2025). (nuget.org)

src/Mailtrap.Abstractions/GlobalUsings.cs (1)

42-45: Global using statements properly organized.

The ContactEvents namespace imports are correctly alphabetically positioned with the existing ContactFields imports and follow the established pattern for namespace organization in the project.

tests/Mailtrap.IntegrationTests/ContactEvents/Create_WithParams_Success_Response.json (1)

1-11: Test fixture accurately represents expected server response.

The JSON fixture structure appears consistent with other test fixtures in the project and properly includes all expected fields for a contact event creation response.

src/Mailtrap/Contacts/ContactCollectionResource.cs (2)

11-11: LGTM!

The EventsSegment constant follows the established naming convention and pattern used by other segment constants in the class.


34-35: Navigation method implementation is correct.

The Events method properly implements the resource navigation pattern by constructing the URI with the contactId followed by the EventsSegment, matching the pattern used by other navigation methods in the class.

tests/Mailtrap.UnitTests/Contacts/ContactCollectionResourceTests.cs (1)

188-205: Unit test follows established testing patterns.

The test properly validates resource creation, URI construction, and type assertions using the established ResourceValidator pattern consistent with other tests in the class.

tests/Mailtrap.IntegrationTests/TestConstants/UrlSegmentsTestConstants.cs (1)

24-24: Constant addition maintains consistency.

The EventsSegment constant properly follows the established pattern and maintains alphabetical ordering with existing URL segment constants.

tests/Mailtrap.IntegrationTests/ContactEvents/Create_Plain_Success_Request.json (1)

1-3: Minimal test fixture is appropriate.

The plain request fixture correctly represents a minimal contact event creation scenario with only the required "name" field.

src/Mailtrap.Abstractions/Contacts/IContactCollectionResource.cs (1)

87-98: Interface method properly documented and typed.

The Events method signature and documentation follow established patterns in the interface and correctly specify the return type and parameter requirements.

src/Mailtrap.Abstractions/ContactEvents/Models/ContactsEvent.cs (1)

8-48: LGTM: response model is straightforward and consistent with existing patterns.

Params with JsonObjectCreationHandling.Populate avoids nulls and supports deserialization as expected.

tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventsIntegrationTests.cs (2)

143-171: Nice negative‑path coverage and no‑send assertion.

Asserting RequestValidationException and verifying 0 matches ensures client‑side validation blocks the HTTP call. LGTM.

Also applies to: 187-215


45-51: Fixture fidelity to server schema.

Loading request/response from JSON fixtures is good. Keep fixtures mirroring real server payloads (don’t tweak to fit client), per prior guidance.

Would you confirm these fixtures were captured from actual API responses/requests?

Also applies to: 98-101

Mailtrap.sln (1)

98-99: Approve — Mailtrap.Example.ContactEvents solution wiring verified.
examples/Mailtrap.Example.ContactEvents/Mailtrap.Example.ContactEvents.csproj exists; Mailtrap.sln contains the project entry and build mappings (lines 98, 190–193, 220); examples imports mailtrap-example.props (examples/Directory.Build.props line 6).

Copy link

@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.

A couple of comments, and I think it's worth paying attention to some CodeRabbit comments about interfaces and their implementation. Besides that, LGTM.

post review updates and fixes:
- Added Contact Events params in example project
- Made file names in consistent with class name
- Removed ContactsEvent.GetAll impl
- updates in integration tests to be DRY
- additonal unit test
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)
src/Mailtrap.Abstractions/ContactEvents/Validators/CreateContactsEventRequestValidator.cs (2)

21-21: Minor: simplify Name rule.

NotEmpty() plus Length(1, 255) is redundant. Prefer MaximumLength(255) with NotEmpty() for clarity.

-        RuleFor(r => r.Name).NotEmpty().Length(1, 255);
+        RuleFor(r => r.Name)
+            .NotEmpty()
+            .MaximumLength(255);

23-29: Consider treating whitespace-only param keys as invalid.

Current NotEmpty() allows " " keys. Optionally reject whitespace and slightly simplify the guard.

-        When(r => r.Params != null && r.Params.Count > 0, () =>
+        When(r => r.Params is not null, () =>
         {
-            RuleForEach(r => r.Params.Keys)
+            RuleForEach(r => r.Params!.Keys)
                 .Cascade(CascadeMode.Stop)
-                .NotEmpty()
+                .Must(k => !string.IsNullOrWhiteSpace(k)).WithMessage("Parameter key cannot be whitespace.")
                 .MaximumLength(255);
         });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e3be3d4 and 4f29e35.

📒 Files selected for processing (6)
  • examples/Mailtrap.Example.ContactEvents/Program.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactEvents/IContactsEventCollectionResource.cs (1 hunks)
  • src/Mailtrap.Abstractions/ContactEvents/Validators/CreateContactsEventRequestValidator.cs (1 hunks)
  • src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs (1 hunks)
  • tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventIntegrationTests.cs (1 hunks)
  • tests/Mailtrap.UnitTests/ContactEvents/Requests/CreateContactsEventRequestTests.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/Mailtrap.Example.ContactEvents/Program.cs
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-23T10:44:34.295Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#152
File: src/Mailtrap.Abstractions/ContactEvents/IContactsEventsCollectionResource.cs:6-6
Timestamp: 2025-09-23T10:44:34.295Z
Learning: The Contact Events API backend does not provide a GetAll/list method - only Create is supported. The ContactsEventCollectionResource implementation should not include a GetAll method.

Applied to files:

  • src/Mailtrap.Abstractions/ContactEvents/IContactsEventCollectionResource.cs
  • src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs
📚 Learning: 2025-09-10T17:01:49.270Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#142
File: src/Mailtrap.Abstractions/ContactImports/Validators/ContactsImportRequestValidator.cs:27-30
Timestamp: 2025-09-10T17:01:49.270Z
Learning: In ContactsImportRequestValidator, ContactRequestValidator.Instance is used to validate ContactImportRequest items because ContactImportRequest inherits from ContactRequest and doesn't introduce additional validation rules that would require a separate validator.

Applied to files:

  • src/Mailtrap.Abstractions/ContactEvents/Validators/CreateContactsEventRequestValidator.cs
📚 Learning: 2025-09-04T12:23:59.276Z
Learnt from: dr-3lo
PR: railsware/mailtrap-dotnet#139
File: tests/Mailtrap.IntegrationTests/Contacts/Update_Success.json:16-17
Timestamp: 2025-09-04T12:23:59.276Z
Learning: Test fixtures in the Mailtrap .NET client should accurately represent the actual server response format and should not be modified to match client-side converters or serialization preferences.

Applied to files:

  • tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventIntegrationTests.cs
🧬 Code graph analysis (5)
src/Mailtrap.Abstractions/ContactEvents/IContactsEventCollectionResource.cs (3)
src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs (1)
  • Task (11-12)
tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventIntegrationTests.cs (1)
  • Task (36-70)
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1)
  • CreateContactsEventRequest (53-66)
src/Mailtrap.Abstractions/ContactEvents/Validators/CreateContactsEventRequestValidator.cs (1)
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1)
  • CreateContactsEventRequest (53-66)
tests/Mailtrap.UnitTests/ContactEvents/Requests/CreateContactsEventRequestTests.cs (2)
tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventIntegrationTests.cs (4)
  • Test (72-80)
  • Test (82-90)
  • Test (92-130)
  • Test (132-174)
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1)
  • CreateContactsEventRequest (53-66)
tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventIntegrationTests.cs (8)
tests/Mailtrap.UnitTests/ContactEvents/Requests/CreateContactsEventRequestTests.cs (8)
  • TestFixture (4-106)
  • Test (7-17)
  • Test (27-46)
  • Test (48-61)
  • Test (63-69)
  • Test (71-77)
  • Test (79-91)
  • Test (93-105)
src/Mailtrap/Configuration/MailtrapClientOptions.cs (1)
  • JsonSerializerOptions (148-154)
src/Mailtrap.Abstractions/ContactEvents/IContactsEventCollectionResource.cs (1)
  • Task (23-23)
src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs (1)
  • Task (11-12)
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1)
  • CreateContactsEventRequest (53-66)
src/Mailtrap/Core/Constants/MimeTypes.cs (2)
  • MimeTypes (4-19)
  • Application (6-11)
src/Mailtrap/Core/Constants/HeaderValues.cs (1)
  • HeaderValues (7-12)
tests/Mailtrap.IntegrationTests/TestExtensions/ValidationHelpers.cs (1)
  • ShouldBeEquivalentToContactResponse (25-40)
src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs (5)
tests/Mailtrap.UnitTests/ContactEvents/ContactsEventCollectionResourceTests.cs (1)
  • ContactsEventCollectionResource (52-52)
src/Mailtrap/Contacts/ContactCollectionResource.cs (3)
  • IContactsEventCollectionResource (34-35)
  • Task (37-38)
  • Task (40-41)
src/Mailtrap.Abstractions/ContactEvents/IContactsEventCollectionResource.cs (1)
  • Task (23-23)
tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventIntegrationTests.cs (1)
  • Task (36-70)
src/Mailtrap.Abstractions/ContactEvents/Requests/CreateContactsEventRequest.cs (1)
  • CreateContactsEventRequest (53-66)
🔇 Additional comments (9)
src/Mailtrap.Abstractions/ContactEvents/IContactsEventCollectionResource.cs (1)

6-24: LGTM: interface shape matches backend (Create only).

Contract is minimal and consistent with API capabilities.

tests/Mailtrap.IntegrationTests/ContactEvents/ContactsEventIntegrationTests.cs (3)

36-70: Nice end-to-end success path.

Good fixture usage and strict header assertions; VerifyNoOutstandingExpectation() confirms exact call.


92-130: Good validation guard: no HTTP on invalid name.

The test ensures local validation short-circuits and no network call is made.


132-174: Good validation guard: no HTTP on invalid param key.

Covers oversized key and asserts zero matches on mock.

src/Mailtrap/ContactEvents/ContactsEventCollectionResource.cs (1)

11-12: LGTM: thin delegate to base with ConfigureAwait(false).

Matches interface and project patterns.

tests/Mailtrap.UnitTests/ContactEvents/Requests/CreateContactsEventRequestTests.cs (4)

7-17: Record-with test reads well.

Verifies copy semantics and Params immutability expectations.


19-25: Constructor null/empty guard covered.

Asserts ParamName; good specificity.


63-77: Boundary tests are solid.

Covers 1 and 255 lengths for name and param tag.


79-105: Invalid-length cases covered.

Ensures validator fails at 256 for both name and key.

@dr-3lo dr-3lo merged commit a610692 into main Sep 24, 2025
3 checks passed
@dr-3lo dr-3lo deleted the feature/151-Contact-Events branch September 24, 2025 10:48
@coderabbitai coderabbitai bot mentioned this pull request Sep 25, 2025
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Contacts API: Events

4 participants