Skip to content

Conversation

@AlexO-85
Copy link
Contributor

@AlexO-85 AlexO-85 commented Nov 6, 2025

gin challenge-1-basic-routing Solution

Submitted by: @AlexO-85
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/AlexO-85/solution.go

Testing

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

Thank you for reviewing my submission! 🚀

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 6, 2025

Walkthrough

A Gin-based REST API implementing user CRUD operations with in-memory storage. Adds User and Response data models, six HTTP handlers for standard CRUD and search routes, in-memory user storage with seeding, validation logic, and standardized error responses on localhost:8080.

Changes

Cohort / File(s) Summary
Gin User CRUD API Implementation
packages/gin/challenge-1-basic-routing/submissions/AlexO-85/solution.go
Adds public types User and Response with JSON/binding tags; implements six HTTP handlers (getAllUsers, getUserByID, createUser, updateUser, deleteUser, searchUsers) for CRUD and search operations; adds private helper findUserByID for user lookup; seeds in-memory storage with three users and configures Gin server on localhost:8080 with routes for all operations; includes validation, error handling, and standardized response formatting.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Server as Gin Server
    participant Storage as In-Memory Storage

    Client->>Server: GET /users/:id
    Server->>Storage: findUserByID(id)
    alt User Found
        Storage-->>Server: *User, index
        Server-->>Client: 200 OK + Response{Success: true, Data: User}
    else User Not Found
        Storage-->>Server: nil, -1
        Server-->>Client: 404 Not Found + Response{Success: false, Error: "not found"}
    end

    Client->>Server: POST /users (JSON: Name, Email, Age)
    Server->>Server: Validate input
    alt Validation Success
        Server->>Storage: Append User with nextID++
        Storage-->>Server: User created
        Server-->>Client: 201 Created + Response{Success: true, Data: User}
    else Validation Failed
        Server-->>Client: 400 Bad Request + Response{Success: false, Error: "..."}
    end

    Client->>Server: GET /users/search?name=John
    Server->>Storage: Iterate & match (case-insensitive)
    Storage-->>Server: Matching users []User
    Server-->>Client: 200 OK + Response{Success: true, Data: []User}
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Multiple handler functions with distinct logic paths (CRUD operations, search with case-insensitive matching)
  • Validation and error handling patterns to verify across handlers
  • In-memory storage management and ID assignment logic
  • JSON binding and response standardization consistency
  • Edge cases in search and user lookup operations

Possibly related PRs

  • RezaSi/go-interview-practice#607: Implements identical Gin-based user CRUD API with same User/Response types, routes, and handlers for challenge-1-basic-routing.
  • RezaSi/go-interview-practice#656: Directly related submission with same Gin user CRUD implementation including getAllUsers, createUser, updateUser, deleteUser, searchUsers handlers and in-memory storage.
  • RezaSi/go-interview-practice#645: Modifies the same code-level entities (User, Response types and identical handlers) for the same challenge-1-basic-routing challenge in Gin.

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding a solution file for the gin challenge-1-basic-routing by AlexO-85. It is concise, related to the changeset, and helps reviewers understand the primary contribution.
Description check ✅ Passed The description is directly related to the changeset, providing context about the challenge submission, the file location, and claiming that tests pass and best practices are followed. It adequately describes the purpose of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.

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
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: 3

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

68-99: Consider extracting error response creation to reduce duplication.

The error response creation pattern is repeated across multiple handlers. You could optionally create a helper function to reduce duplication:

func errorResponse(c *gin.Context, statusCode int, errorMsg string, details ...string) {
	response := Response{
		Success: false,
		Error:   errorMsg,
		Code:    statusCode,
	}
	if len(details) > 0 {
		response.Message = details[0]
	}
	c.IndentedJSON(statusCode, response)
}

This is a nice-to-have improvement that can be deferred.

Also applies to: 128-176, 179-213

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 29abe40 and 3555703.

📒 Files selected for processing (1)
  • packages/gin/challenge-1-basic-routing/submissions/AlexO-85/solution.go (1 hunks)
🔇 Additional comments (9)
packages/gin/challenge-1-basic-routing/submissions/AlexO-85/solution.go (9)

1-9: LGTM!

Package declaration and imports are appropriate for the implemented functionality.


11-17: LGTM!

User struct is well-defined with appropriate JSON and validation tags.


19-26: LGTM!

Response struct provides a consistent API response format. The Code field is somewhat redundant with the HTTP status code but doesn't cause issues.


28-34: LGTM!

In-memory storage is properly initialized with seed data.


58-65: LGTM!

Handler correctly returns all users with appropriate response structure.


67-99: LGTM!

Handler correctly parses the ID parameter, validates format, and returns appropriate responses for success and error cases.


178-213: LGTM!

Handler correctly deletes the user and returns appropriate responses. Performing the deletion after sending the response is acceptable for this in-memory implementation.


215-243: LGTM!

Search handler correctly validates the required query parameter and performs case-insensitive substring matching. Returning an empty slice when no matches are found is good API design.


245-253: LGTM!

Helper function correctly returns a pointer to the user in the slice and its index, enabling efficient lookups and in-place updates.

Comment on lines +36 to +54
func main() {
router := gin.Default()

// TODO: Setup routes
// GET /users - Get all users
router.GET("/users", getAllUsers)
// GET /users/:id - Get user by ID
router.GET("/users/:id", getUserByID)
// POST /users - Create new user
router.POST("/users", createUser)
// PUT /users/:id - Update user
router.PUT("/users/:id", updateUser)
// DELETE /users/:id - Delete user
router.DELETE("/users/:id", deleteUser)
// GET /users/search - Search users by name
router.GET("/users/search", searchUsers)

router.Run("localhost:8080")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix route registration order to prevent conflict.

The route /users/search (line 51) is registered after /users/:id (line 43). In Gin's router, parameterized routes like :id match any path segment, including "search". This means requests to /users/search will be incorrectly handled by getUserByID with id="search", and the search endpoint will never be reached.

Apply this diff to register the specific route before the parameterized one:

 	// GET /users - Get all users
 	router.GET("/users", getAllUsers)
+	// GET /users/search - Search users by name
+	router.GET("/users/search", searchUsers)
 	// GET /users/:id - Get user by ID
 	router.GET("/users/:id", getUserByID)
 	// POST /users - Create new user
 	router.POST("/users", createUser)
 	// PUT /users/:id - Update user
 	router.PUT("/users/:id", updateUser)
 	// DELETE /users/:id - Delete user
 	router.DELETE("/users/:id", deleteUser)
-	// GET /users/search - Search users by name
-	router.GET("/users/search", searchUsers)
🤖 Prompt for AI Agents
In packages/gin/challenge-1-basic-routing/submissions/AlexO-85/solution.go
around lines 36 to 54, the parameterized route router.GET("/users/:id",
getUserByID) is registered before the specific route router.GET("/users/search",
searchUsers), causing "/users/search" to be captured as an id; move the
router.GET("/users/search", searchUsers) registration so it appears before
router.GET("/users/:id", getUserByID) to ensure the specific search route is
matched first.

Comment on lines +101 to +125
// createUser handles POST /users
func createUser(c *gin.Context) {
var user User

if err := c.ShouldBindJSON(&user); err != nil {
response := Response{
Success: false,
Error: "Bas request",
Message: err.Error(),
Code: http.StatusBadRequest,
}
c.IndentedJSON(http.StatusBadRequest, response)
return
}

user.ID = nextID
users = append(users, user)
nextID++

response := Response{
Success: true,
Data: user,
}
c.IndentedJSON(http.StatusCreated, response)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typo in error message.

Line 108 contains a typo: "Bas request" should be "Bad request".

Apply this diff:

 		response := Response{
 			Success: false,
-			Error:   "Bas request",
+			Error:   "Bad request",
 			Message: err.Error(),
 			Code:    http.StatusBadRequest,
 		}
📝 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
// createUser handles POST /users
func createUser(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
response := Response{
Success: false,
Error: "Bas request",
Message: err.Error(),
Code: http.StatusBadRequest,
}
c.IndentedJSON(http.StatusBadRequest, response)
return
}
user.ID = nextID
users = append(users, user)
nextID++
response := Response{
Success: true,
Data: user,
}
c.IndentedJSON(http.StatusCreated, response)
}
// createUser handles POST /users
func createUser(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
response := Response{
Success: false,
Error: "Bad request",
Message: err.Error(),
Code: http.StatusBadRequest,
}
c.IndentedJSON(http.StatusBadRequest, response)
return
}
user.ID = nextID
users = append(users, user)
nextID++
response := Response{
Success: true,
Data: user,
}
c.IndentedJSON(http.StatusCreated, response)
}
🤖 Prompt for AI Agents
In packages/gin/challenge-1-basic-routing/submissions/AlexO-85/solution.go
around lines 101 to 125, there's a typo in the error response string "Bas
request" at line 108; update that string to "Bad request" so the Response.Error
field contains the correct message, then run gofmt/quick vet to ensure no other
changes are needed.

Comment on lines +127 to +176
// updateUser handles PUT /users/:id
func updateUser(c *gin.Context) {
idStr := c.Param("id")
// Handle invalid ID format
id, err := strconv.Atoi(idStr)
if err != nil {
response := Response{
Success: false,
Error: "User ID format is wrong",
Message: err.Error(),
Code: http.StatusBadRequest,
}
c.IndentedJSON(http.StatusBadRequest, response)
return
}

var newUser User

if err := c.ShouldBindJSON(&newUser); err != nil {
response := Response{
Success: false,
Error: "Bas request",
Message: err.Error(),
Code: http.StatusBadRequest,
}
c.IndentedJSON(http.StatusBadRequest, response)
return
}

if user, _ := findUserByID(id); user != nil {
user.Name = newUser.Name
user.Email = newUser.Email
user.Age = newUser.Age

response := Response{
Success: true,
Data: user,
}
c.IndentedJSON(http.StatusOK, response)
return
}

response := Response{
Success: false,
Error: "User not found",
Code: http.StatusNotFound,
}

c.IndentedJSON(http.StatusNotFound, response)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typo in error message.

Line 148 contains the same typo: "Bas request" should be "Bad request".

Apply this diff:

 		response := Response{
 			Success: false,
-			Error:   "Bas request",
+			Error:   "Bad request",
 			Message: err.Error(),
 			Code:    http.StatusBadRequest,
 		}
🤖 Prompt for AI Agents
packages/gin/challenge-1-basic-routing/submissions/AlexO-85/solution.go lines
127-176: the error response for JSON binding has a typo "Bas request"; update
the Response.Error string to "Bad request" (fix the typo) so the error reads
"Bad request" before returning the 400 response.

@RezaSi RezaSi merged commit 219b21e into RezaSi:main Nov 7, 2025
5 checks passed
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.

2 participants