Skip to content

Add Create Product Handler#43

Merged
jlpdeveloper merged 6 commits intomainfrom
create-product
May 2, 2026
Merged

Add Create Product Handler#43
jlpdeveloper merged 6 commits intomainfrom
create-product

Conversation

@jlpdeveloper
Copy link
Copy Markdown
Contributor

@jlpdeveloper jlpdeveloper commented May 2, 2026

Description

  • adds create product handler
  • brings over commit re-using timestamp for create

Code Rabbit Summary

Summary by CodeRabbit

  • New Features
    • Added API endpoint for creating products with validation for required fields and appropriate error responses (201 Created for success, 400 Bad Request for invalid input, 500 Internal Server Error for server issues).

Fixes

Closes #23

Post Deployment Tasks?

@jlpdeveloper jlpdeveloper added this to the Phase 2: API Endpoints milestone May 2, 2026
@jlpdeveloper jlpdeveloper self-assigned this May 2, 2026
@jlpdeveloper jlpdeveloper added enhancement New feature or request skip-changelog Won't be added to the release notes labels May 2, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

Warning

Rate limit exceeded

@jlpdeveloper has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 50 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 721a8474-3b93-469b-9b2c-0f73c34737a4

📥 Commits

Reviewing files that changed from the base of the PR and between f99cd05 and 5dfe2b9.

📒 Files selected for processing (3)
  • api/product/create.go
  • api/product/product_test.go
  • internal/structured_logger_test.go
📝 Walkthrough

Walkthrough

A new HTTP POST handler for creating products is implemented across the data, application, routing, and test layers. The product creation flow validates JSON input and required fields, sets a UTC timestamp, calls the database within a 5-second context timeout, and returns appropriate HTTP status codes. A single Timestamp field replaces separate CreatedAt and UpdatedAt fields in the SQL and generated types.

Changes

Product Creation Handler

Layer / File(s) Summary
Data Layer
queries/products.sql, internal/db/product/products.sql.go
SQL CreateProduct query updated to use a single @timestamp parameter for both created_at and updated_at columns. CreateProductParams struct simplified to a single Timestamp field (removing CreatedAt/UpdatedAt).
Handler Implementation
api/product/product.go, api/product/create.go
NewProductHandler constructor initializes a handler with a product.Querier dependency. CreateProduct HTTP handler decodes JSON, validates required fields (Name and PlatformID), sets UTC timestamp, and executes database call under a 5-second context timeout. Returns 400 for validation errors, 500 for DB errors, 201 on success.
Routing Integration
router/router.go
Product handler imported and registered. registerProductCallHandler added to wire the handler into the router at /api/products with a POST / route.
Tests
api/product/product_test.go
Table-driven TestCreateProduct covers success case (201), invalid JSON body (400), missing required fields (400), and database failure (500). Uses mockProductQuerier to satisfy the product.Querier interface.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

A POST to create, with fields validated true,
Timestamps in sync, from a single SQL view,
The handler springs forth, five seconds to dwell,
The router now knows, our products to swell!
🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a Create Product handler as a new HTTP endpoint.
Linked Issues check ✅ Passed All coding requirements from issue #23 are met: CreateProduct handler decodes JSON, validates Name/PlatformID, creates 5-second timeout context, calls h.queries.CreateProduct with mapped params, and returns correct status codes.
Out of Scope Changes check ✅ Passed All changes directly support the Create Product handler objective. The SQL query modification (single timestamp parameter) is in scope as it supports the handler's requirement to use pgtype.Timestamptz for timestamps.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch create-product

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
Review rate limit: 0/1 reviews remaining, refill in 20 minutes and 50 seconds.

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

Copy link
Copy Markdown

@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: 2

🧹 Nitpick comments (2)
api/product/product_test.go (2)

42-103: ⚡ Quick win

Test bodies use json.Marshal(CreateProductParams{…}) which produces PascalCase keys, masking the snake_case decoding bug and leaving the real API contract untested.

All test cases marshal the Go struct directly (e.g., {"PlatformID":1,"Name":"Test Product"}). Go's Unmarshal() matches JSON keys in a case-insensitive manner as long as the characters and their order are the same, so this never exercises whether {"platform_id": 1} — the payload a real REST client would send — is handled correctly. Per coding guidelines, test coverage should be sufficient for the PR changes.

Add at least one case that sends a raw snake_case JSON payload matching what a real client would produce:

{
    name:        "Snake-case JSON keys",
    requestBody: `{"platform_id":1,"name":"Test Product"}`,
    mockSetup: func(m *mockProductQuerier) {
        m.createProductFunc = func(_ context.Context, _ product.CreateProductParams) error {
            return nil
        }
    },
    expectedStatus: http.StatusCreated,
},

As per coding guidelines, "Assess the unit test code assessing sufficient code coverage for the changes associated in the pull request."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/product/product_test.go` around lines 42 - 103, The TestCreateProduct
table uses json.Marshal on product.CreateProductParams which emits PascalCase
keys and misses exercising snake_case payload decoding; add a new test entry
inside the tests slice in TestCreateProduct named e.g. "Snake-case JSON keys"
where requestBody is a raw JSON string like `{"platform_id":1,"name":"Test
Product"}`, mockSetup assigns mockProductQuerier.createProductFunc to accept
product.CreateProductParams and return nil, and expectedStatus is
http.StatusCreated so the handler will be exercised with real snake_case keys
and validate decoding into product.CreateProductParams.

14-40: 💤 Low value

Mock delegate methods panic on a nil function field.

Every mock method calls its function field unconditionally (e.g., m.deleteProductFunc(ctx, id)). If any future handler code path calls DeleteProduct, GetProductById, etc. when those fields are not initialised, the test panics instead of failing gracefully. A nil guard makes the mock safer to extend:

♻️ Proposed refactor (example for one method; apply to all five)
 func (m *mockProductQuerier) DeleteProduct(ctx context.Context, id int32) error {
+	if m.deleteProductFunc == nil {
+		return nil
+	}
 	return m.deleteProductFunc(ctx, id)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/product/product_test.go` around lines 14 - 40, The mockProductQuerier
methods (CreateProduct, DeleteProduct, GetProductById, GetProductsByPlatform,
UpdateProduct) call their function fields unconditionally causing panics if nil;
update each method to check the corresponding function field (e.g.,
m.deleteProductFunc, m.getProductByIdFunc, etc.) and if nil return a sensible
zero value and a clear error (or testing.T-friendly error) instead of calling
it, so tests fail gracefully when a mock handler was not initialized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api/product/create.go`:
- Around line 13-22: The handler is using the auto-generated
product.CreateProductParams (which lacks json tags) so incoming snake_case keys
like "platform_id" are ignored; update ProductHandler.CreateProduct to decode
into a new local request DTO (e.g., CreateProductRequest) that defines
json:"name" and json:"platform_id" tags, validate that DTO (Name != "" and
PlatformID != 0), then map its fields into product.CreateProductParams before
proceeding with the existing creation logic; ensure you reference
CreateProductRequest in the CreateProduct method and perform the same validation
and error responses as before.

In `@api/product/product_test.go`:
- Around line 111-116: When marshaling tt.requestBody, don’t ignore the error
from json.Marshal; capture the error and fail the test with a clear message
(e.g., t.Fatalf or require.NoError) so marshal failures surface instead of
sending an empty body; keep the existing string branch (if s, ok :=
tt.requestBody.(string)) and only json.Marshal when needed, then on err != nil
call t.Fatalf("json.Marshal requestBody failed: %v", err) (or equivalent
assertion) to provide the root-cause in the test output.

---

Nitpick comments:
In `@api/product/product_test.go`:
- Around line 42-103: The TestCreateProduct table uses json.Marshal on
product.CreateProductParams which emits PascalCase keys and misses exercising
snake_case payload decoding; add a new test entry inside the tests slice in
TestCreateProduct named e.g. "Snake-case JSON keys" where requestBody is a raw
JSON string like `{"platform_id":1,"name":"Test Product"}`, mockSetup assigns
mockProductQuerier.createProductFunc to accept product.CreateProductParams and
return nil, and expectedStatus is http.StatusCreated so the handler will be
exercised with real snake_case keys and validate decoding into
product.CreateProductParams.
- Around line 14-40: The mockProductQuerier methods (CreateProduct,
DeleteProduct, GetProductById, GetProductsByPlatform, UpdateProduct) call their
function fields unconditionally causing panics if nil; update each method to
check the corresponding function field (e.g., m.deleteProductFunc,
m.getProductByIdFunc, etc.) and if nil return a sensible zero value and a clear
error (or testing.T-friendly error) instead of calling it, so tests fail
gracefully when a mock handler was not initialized.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 79738f1b-9bcb-4dae-ad93-89d9f83a5365

📥 Commits

Reviewing files that changed from the base of the PR and between 8c2edd4 and f99cd05.

📒 Files selected for processing (6)
  • api/product/create.go
  • api/product/product.go
  • api/product/product_test.go
  • internal/db/product/products.sql.go
  • queries/products.sql
  • router/router.go

Comment thread api/product/create.go
Comment thread api/product/product_test.go
@jlpdeveloper jlpdeveloper merged commit a2dda9e into main May 2, 2026
3 checks passed
@jlpdeveloper jlpdeveloper deleted the create-product branch May 2, 2026 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request skip-changelog Won't be added to the release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Create Product Handler

1 participant