Skip to content

Add solution for gin challenge-1-basic-routing by yogtanko#1744

Closed
yogtanko wants to merge 4 commits into
RezaSi:mainfrom
yogtanko:package-gin-challenge-1-basic-routing-yogtanko
Closed

Add solution for gin challenge-1-basic-routing by yogtanko#1744
yogtanko wants to merge 4 commits into
RezaSi:mainfrom
yogtanko:package-gin-challenge-1-basic-routing-yogtanko

Conversation

@yogtanko
Copy link
Copy Markdown
Contributor

gin challenge-1-basic-routing Solution

Submitted by: @yogtanko
Package: gin
Challenge: challenge-1-basic-routing

Description

This PR contains my solution for gin challenge-1-basic-routing.

Changes

  • Added solution file to packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go

Testing

  • Solution passes all test cases
  • Code follows Go best practices

Thank you for reviewing my submission! 🚀

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 30, 2026

Review Change Stack

Walkthrough

Adds a single-file Gin REST API exposing BasicRouting(), defines exported User and Response types, initializes RWMutex-protected in-memory users with nextID, wires GET/POST/PUT/DELETE + /users/search routes, and implements handlers plus find/validate helpers.

Changes

In-Memory User CRUD API

Layer / File(s) Summary
Data model and in-memory store
packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go
Defines exported User and Response structs, initializes seeded users slice, nextID counter, and package mu (RWMutex).
Router initialization and route registration
packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go
Exports BasicRouting() which creates a Gin engine, registers routes: GET /users, GET /users/:id, POST /users, PUT /users/:id, DELETE /users/:id, GET /users/search, and runs the server.
Read handlers and search
packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go
getAllUsers (read lock) returns users or success=false when empty; getUserByID parses :id and returns 200/400/404; searchUsers requires name query, filters case-insensitively, returns 200 with results.
Create, update, delete handlers
packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go
createUser binds/validates JSON and appends new user under write lock returning 201; updateUser parses path ID, binds/validates, replaces stored record at index forcing ID consistency, returns 200/404/500 as implemented; deleteUser removes by index under write lock and returns 200/404.
Validation and lookup helpers
packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go
findUserByID scans slice returning pointer+index or nil,-1; validateUser checks non-empty Name/Email and that Email contains @.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped into code with a carrot and key,
I wired routes for users, simple and free,
Create, read, update, delete — tidy and neat,
Search by name with a case-folded beat,
Gin hums softly — a rabbit’s small feat.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main change—adding a solution for the gin challenge-1-basic-routing challenge submitted by yogtanko.
Description check ✅ Passed The description is directly related to the changeset, providing context about the challenge submission, file location, and testing status.
Docstring Coverage ✅ Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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.

Copy link
Copy Markdown
Contributor

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

🧹 Nitpick comments (2)
packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go (2)

121-130: ⚡ Quick win

Prefer Gin's ShouldBindJSON for idiomatic request parsing.

Using json.NewDecoder works but Gin provides c.ShouldBindJSON(&user) which is more idiomatic, provides better error messages, and integrates seamlessly with Gin's validation framework.

♻️ Proposed refactor
-	user := User{}
-	decoder := json.NewDecoder(c.Request.Body)
-	err := decoder.Decode(&user)
+	var user User
+	err := c.ShouldBindJSON(&user)
 	if err != nil {
-		c.JSON(500, Response{
+		c.JSON(400, Response{
 			Success: false,
 			Error:   err.Error(),
 		})

166-175: ⚡ Quick win

Prefer ShouldBindJSON and return 400 for malformed JSON.

Similar to createUser, this handler should use c.ShouldBindJSON(&user) for idiomatic Gin code and return 400 (not 500) for JSON decode errors.

♻️ Proposed refactor
-	user := &User{}
-	decoder := json.NewDecoder(c.Request.Body)
-	err = decoder.Decode(user)
+	var user User
+	err = c.ShouldBindJSON(&user)
 	if err != nil {
-		c.JSON(500, Response{
+		c.JSON(400, Response{
 			Success: false,
 			Error:   err.Error(),
 		})
 		return
 	}
-	if err = validateUser(*user); err != nil {
+	if err = validateUser(user); err != nil {

Note: This also requires updating line 194 to use user instead of *user.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5b7f82a9-a8fc-43b3-8af7-8fc123817008

📥 Commits

Reviewing files that changed from the base of the PR and between aa037e3 and 0edb441.

📒 Files selected for processing (1)
  • packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go

Comment on lines +69 to +80
if len(users) > 0 {
c.JSON(200, Response{
Success: true,
Data: users,
})
} else {
c.JSON(404, Response{
Success: false,
Error: "User not found",
})
return
}
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot May 30, 2026

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Return 200 with empty array instead of 404 for no users.

When the user list is empty, returning 404 with "User not found" is misleading. An empty collection is a valid state and should return 200 with an empty array [], not a 404 error. This aligns with REST API best practices where 404 indicates a missing resource, not an empty collection.

♻️ Proposed fix
-	if len(users) > 0 {
-		c.JSON(200, Response{
-			Success: true,
-			Data:    users,
-		})
-	} else {
-		c.JSON(404, Response{
-			Success: false,
-			Error:   "User not found",
-		})
-		return
-	}
+	c.JSON(200, Response{
+		Success: true,
+		Data:    users,
+	})
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if len(users) > 0 {
c.JSON(200, Response{
Success: true,
Data: users,
})
} else {
c.JSON(404, Response{
Success: false,
Error: "User not found",
})
return
}
c.JSON(200, Response{
Success: true,
Data: users,
})

✅ Addressed in commit 9441dda

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

unit test used 404 instead 200

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the test file for this challenge
fd -e go 'solution_test' packages/gin/challenge-1-basic-routing/ --exec cat {}

Length of output: 373


🏁 Script executed:

#!/bin/bash
# Find all Go files in the challenge directory
fd -e go . packages/gin/challenge-1-basic-routing/ --exec echo {}
cat packages/gin/challenge-1-basic-routing/solution_test.go 2>/dev/null || echo "not found at that path"
find packages/gin/challenge-1-basic-routing/ -name "*.go" | xargs ls -la 2>/dev/null

Length of output: 8798


🏁 Script executed:

#!/bin/bash
cat packages/gin/challenge-1-basic-routing/solution-template_test.go

Length of output: 6911



@yogtanko, I checked the test file (solution-template_test.go) and the actual test for GET /users is:

func TestGetAllUsers(t *testing.T) {
    router := setupRouter()
    // ...
    assert.Equal(t, 200, w.Code)  // expects 200, not 404

The test always pre-populates users with 3 entries via setupRouter(), so it expects 200 and never tests the empty-list scenario. There is no test case that exercises the 404 branch in getAllUsers at all — meaning the 404 code path is effectively dead code during testing.

My original suggestion still holds: returning 404 for an empty collection is non-standard REST behaviour. Since no test requires it, you can safely simplify to always return 200:

func getAllUsers(c *gin.Context) {
    mu.RLock()
    defer mu.RUnlock()
    c.JSON(200, Response{
        Success: true,
        Data:    users,
    })
}

This removes the misleading 404 path without breaking any tests.


✏️ Learnings added
Learnt from: yogtanko
Repo: RezaSi/go-interview-practice PR: 1744
File: packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go:69-80
Timestamp: 2026-05-30T08:42:48.267Z
Learning: In the gin challenge-1-basic-routing challenge (`packages/gin/challenge-1-basic-routing/solution-template_test.go`), the `TestGetAllUsers` test always pre-populates 3 users via `setupRouter()` and expects HTTP 200. There is no test case for an empty users list in `getAllUsers`. Returning 404 for an empty `users` slice is non-standard REST behavior and is never required by the challenge tests.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: PopovMarko
Repo: RezaSi/go-interview-practice PR: 1396
File: challenge-18/submissions/PopovMarko/solution-template.go:36-44
Timestamp: 2026-02-20T12:38:34.852Z
Learning: Do not modify predefined function signatures in submission solutions. In this repository, challenges specify exact function signatures that tests rely on. Keep parameter types and return types intact; only implement the required logic within the given function bodies.

Learnt from: CV-Elevation
Repo: RezaSi/go-interview-practice PR: 1559
File: packages/gin/challenge-1-basic-routing/submissions/CV-Elevation/solution.go:236-245
Timestamp: 2026-04-07T14:19:58.995Z
Learning: In Go repositories using modules with `go 1.22` or later in `go.mod`, the iteration variable in `for range` loops has per-iteration scope. Therefore, taking `&loopVar` inside a `range` loop should not be flagged as the classic shared-loop-variable bug for Go 1.22+. The review should focus instead on correctness: `&loopVar` points to a per-iteration copy of the value, not the underlying slice/map element. If the caller intends to mutate the original slice element through the pointer, prefer taking the address of the original element (e.g., `&slice[i]`) rather than `&loopVar`.

Comment thread packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go Outdated
Comment on lines +158 to +163
if err != nil {
c.JSON(500, Response{
Success: false,
Error: err.Error(),
})
return
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use 400 Bad Request for client errors, not 500 Internal Server Error.

Lines 159 and 177 return HTTP 500 for invalid client input (malformed ID and validation failures). These are client errors and should return 400 Bad Request. Reserve 500 for unexpected server failures.

🛠️ Proposed fix
 	id, err := strconv.Atoi(paramId)
 	if err != nil {
-		c.JSON(500, Response{
+		c.JSON(400, Response{
 			Success: false,
 			Error:   err.Error(),
 		})
 	if err = validateUser(*user); err != nil {
-		c.JSON(500, Response{
+		c.JSON(400, Response{
 			Success: false,
 			Error:   err.Error(),
 		})

Also applies to: 176-181

Comment thread packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go Outdated
Comment thread packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go Outdated
Comment thread packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go Outdated
Copy link
Copy Markdown
Contributor

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go (1)

200-205: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use 400 Bad Request for invalid ID format.

Parsing failure of the ID parameter indicates a client error (malformed input), not a missing resource. This should return http.StatusBadRequest (400) instead of 404.

🛠️ Proposed fix
 	id, err := strconv.Atoi(paramId)
 	if err != nil {
-		c.JSON(http.StatusNotFound, Response{
+		c.JSON(http.StatusBadRequest, Response{
 			Success: false,
 			Error:   err.Error(),
 		})
♻️ Duplicate comments (2)
packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go (2)

152-156: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use 400 Bad Request for invalid ID format.

Parsing failure of the ID parameter indicates a client error (malformed input), not an internal server failure. This should return http.StatusBadRequest (400) instead of 500.

🛠️ Proposed fix
 	id, err := strconv.Atoi(paramId)
 	if err != nil {
-		c.JSON(500, Response{
+		c.JSON(http.StatusBadRequest, Response{
 			Success: false,
 			Error:   err.Error(),
 		})

168-173: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use 400 Bad Request for validation failures.

Validation errors indicate the client sent invalid data (missing or malformed fields), not an internal server failure. This should return http.StatusBadRequest (400) instead of 500.

🛠️ Proposed fix
 	if err = validateUser(user); err != nil {
-		c.JSON(http.StatusInternalServerError, Response{
+		c.JSON(http.StatusBadRequest, Response{
 			Success: false,
 			Error:   err.Error(),
 		})
🧹 Nitpick comments (1)
packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go (1)

69-80: ⚡ Quick win

Simplify by removing the unnecessary else branch.

The else branch returns 200 OK with Success: false and an error message when the list is empty, which is semantically confusing. Since an empty collection is a valid state and the test suite pre-populates users (per the retrieved learning), you can safely remove the conditional and always return 200 OK with the users slice (empty or not).

♻️ Simplified implementation
 func getAllUsers(c *gin.Context) {
 	mu.RLock()
 	defer mu.RUnlock()
-	if len(users) > 0 {
-		c.JSON(http.StatusOK, Response{
-			Success: true,
-			Data:    users,
-		})
-	} else {
-		c.JSON(http.StatusOK, Response{
-			Success: false,
-			Error:   "User not found",
-		})
-		return
-	}
+	c.JSON(http.StatusOK, Response{
+		Success: true,
+		Data:    users,
+	})
 }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 36d68a9a-7d3e-4bf6-8bc5-f7b38009917c

📥 Commits

Reviewing files that changed from the base of the PR and between 0edb441 and 9441dda.

📒 Files selected for processing (1)
  • packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go

Copy link
Copy Markdown
Contributor

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go (2)

75-78: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Return an empty list payload for empty collections, not an error-shaped body.

For GET /users with HTTP 200, returning Success: false + "User not found" makes a valid empty collection look like a failure. Prefer Success: true with Data: []User{}.

Proposed fix
-	} else {
-		c.JSON(http.StatusOK, Response{
-			Success: false,
-			Error:   "User not found",
-		})
-		return
-	}
+	} else {
+		c.JSON(http.StatusOK, Response{
+			Success: true,
+			Data:    []User{},
+		})
+		return
+	}

Based on learnings: for this challenge, GET /users should remain 200, and empty-list handling should be non-breaking.


199-203: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use 400 Bad Request for malformed :id in delete handler.

strconv.Atoi failure is a client input error, not a missing resource. Returning 404 here misclassifies the error.

Proposed fix
 	if err != nil {
-		c.JSON(http.StatusNotFound, Response{
+		c.JSON(http.StatusBadRequest, Response{
 			Success: false,
-			Error:   err.Error(),
+			Error:   "Invalid ID",
 		})
 		return
 	}

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1b30b9c5-387a-4ef1-9919-f4e2d32efa6e

📥 Commits

Reviewing files that changed from the base of the PR and between 213d983 and d84a00b.

📒 Files selected for processing (1)
  • packages/gin/challenge-1-basic-routing/submissions/yogtanko/solution.go

@yogtanko yogtanko closed this May 30, 2026
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.

1 participant