My relevant work experience is with Java (mostly web development with Dropwizard/Spring) so I can not avoid using the same practices as I do in a Java project. The project is there but I am going to copy it here:
Project
A very simple project with Gin framework with an endpoint to return a list of users based on their score.
Structure
liveops-tool
-- user
---- model
------ user.go
---- service
------ userService.go
------ userDirectory.go (mock the db)
-- main.go
main.go
r.GET("/competition/users", func(c *gin.Context) {
numUsers, err := strconv.Atoi(c.DefaultQuery("numusers", "6"))
minScore, err := strconv.Atoi(c.DefaultQuery("minscore", "0"))
maxScore, err := strconv.Atoi(c.DefaultQuery("maxscore", "2000"))
fmt.Printf("numUsers: %d , minScore: %d , maxScore: %d \n", numUsers, minScore, maxScore)
if err == nil {
var res = userService.GenerateUserListByScore(numUsers, minScore, maxScore)
c.JSON(http.StatusOK, gin.H{"users": res})
} else {
c.JSON(http.StatusBadRequest, gin.H{"users": "no valid"})
}
})
user.go
package user
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Country string `json:"country"`
TotalScore int `json:"totalScore"`
}
userService.go
package user
import (
user "liveops-tool/user/model"
)
// GenerateUserListByScore returns a list of users for a tournament
func GenerateUserListByScore(numUsers, minScore, maxScore int) []user.User {
return searchUsers(numUsers, minScore, maxScore)
}
userDirectory.go
package user
import (
"fmt"
userModel "liveops-tool/user/model"
)
var users = []userModel.User{}
func init() {
initUsers()
}
func searchUsers(numUsers, minScore, maxScore int) []userModel.User {
return filterUsersByScore(numUsers, minScore, maxScore)
}
func filterUsersByScore(numUsers, minScore, maxScore int) []userModel.User {
var filteredUsers = []userModel.User{}
var countUsers = 0
if len(users) < numUsers {
numUsers = len(users)
}
for i := range users {
if users[i].TotalScore >= minScore && users[i].TotalScore <= maxScore {
filteredUsers = append(filteredUsers, users[i])
countUsers++
}
if countUsers >= numUsers {
break
}
}
return filteredUsers
}
func initUsers() {
user1 := userModel.User{ID: "1", Name: "John", Country: "UK", TotalScore: 500}
user2 := userModel.User{ID: "2", Name: "Frank", Country: "ES", TotalScore: 1500}
user3 := userModel.User{ID: "3", Name: "Bob", Country: "UK", TotalScore: 2000}
user4 := userModel.User{ID: "4", Name: "Anna", Country: "FR", TotalScore: 3000}
users = append(users, user1)
users = append(users, user2)
users = append(users, user3)
users = append(users, user4)
fmt.Printf("users: %+v\n", users)
}
Questions
I am mocking the user list and I would like the method initUsers would not be accesible from userService. Golang doesn't have public and private methods because the visibility depends on the package. The same for the function filterUsersByScore. How can I improve it?
User (model): I need to put the attributes with the first letter in uppercase to make it exportable when I return the JSON. Is it possible to have the attributes as private to access them through getters and setters and also return them in the JSON response?
Any other advice about the code is well received.