{"id":1969,"date":"2025-02-27T09:42:19","date_gmt":"2025-02-27T01:42:19","guid":{"rendered":"https:\/\/www.fanyamin.com\/wordpress\/?p=1969"},"modified":"2025-02-27T09:42:19","modified_gmt":"2025-02-27T01:42:19","slug":"best-practice-of-go-backend-service-2","status":"publish","type":"post","link":"https:\/\/www.fanyamin.com\/wordpress\/?p=1969","title":{"rendered":"best practice of go backend service  2"},"content":{"rendered":"<p>Writing a backend service in Go efficiently involves following best practices for code structure, maintainability, and performance. Below is a simple and well-structured example of a RESTful backend service in Go with best practices applied.<\/p>\n<hr \/>\n<h2><strong>Best Practices for Writing a Backend Service in Go<\/strong><\/h2>\n<h3><strong>1. Project Structure<\/strong><\/h3>\n<p>Organizing your code properly improves maintainability and scalability. A standard Go project structure looks like this:<\/p>\n<pre><code>myapp\/\n\u2502\u2500\u2500 cmd\/                # Main application entry points\n\u2502   \u251c\u2500\u2500 server\/         # HTTP server main\n\u2502   \u2502   \u2514\u2500\u2500 main.go\n\u2502\u2500\u2500 internal\/           # Business logic, database, API handlers\n\u2502   \u251c\u2500\u2500 handler\/        # HTTP request handlers\n\u2502   \u251c\u2500\u2500 service\/        # Business logic layer\n\u2502   \u251c\u2500\u2500 repository\/     # Database operations\n\u2502\u2500\u2500 pkg\/                # Utility packages (logging, config)\n\u2502\u2500\u2500 config\/             # Configuration files\n\u2502\u2500\u2500 migrations\/         # Database migrations\n\u2502\u2500\u2500 go.mod              # Go module file\n\u2502\u2500\u2500 go.sum\n\u2502\u2500\u2500 Makefile            # Automation commands\n\u2502\u2500\u2500 README.md<\/code><\/pre>\n<hr \/>\n<h3><strong>2. Use a Web Framework like <code>chi<\/code><\/strong><\/h3>\n<p><code>chi<\/code> is lightweight and idiomatic, making it great for building Go APIs.<\/p>\n<h4><strong>Install <code>chi<\/code><\/strong><\/h4>\n<pre><code class=\"language-sh\">go get github.com\/go-chi\/chi\/v5<\/code><\/pre>\n<h4><strong>Create a Simple HTTP Server<\/strong><\/h4>\n<p><code>cmd\/server\/main.go<\/code><\/p>\n<pre><code class=\"language-go\">package main\n\nimport (\n    &quot;fmt&quot;\n    &quot;net\/http&quot;\n    &quot;myapp\/internal\/handler&quot;\n    &quot;github.com\/go-chi\/chi\/v5&quot;\n    &quot;github.com\/go-chi\/chi\/v5\/middleware&quot;\n)\n\nfunc main() {\n    r := chi.NewRouter()\n\n    \/\/ Middlewares\n    r.Use(middleware.Logger)\n    r.Use(middleware.Recoverer)\n\n    \/\/ Routes\n    r.Get(&quot;\/health&quot;, handler.HealthCheck)\n    r.Get(&quot;\/users&quot;, handler.GetUsers)\n\n    fmt.Println(&quot;Server running on :8080&quot;)\n    http.ListenAndServe(&quot;:8080&quot;, r)\n}<\/code><\/pre>\n<hr \/>\n<h3><strong>3. Separate Handlers, Services, and Repositories<\/strong><\/h3>\n<h4><strong>Handler (HTTP Layer)<\/strong><\/h4>\n<p><code>internal\/handler\/user_handler.go<\/code><\/p>\n<pre><code class=\"language-go\">package handler\n\nimport (\n    &quot;encoding\/json&quot;\n    &quot;net\/http&quot;\n    &quot;myapp\/internal\/service&quot;\n)\n\nfunc HealthCheck(w http.ResponseWriter, r *http.Request) {\n    w.WriteHeader(http.StatusOK)\n    w.Write([]byte(`{&quot;status&quot;: &quot;ok&quot;}`))\n}\n\nfunc GetUsers(w http.ResponseWriter, r *http.Request) {\n    users := service.FetchUsers()\n    w.Header().Set(&quot;Content-Type&quot;, &quot;application\/json&quot;)\n    json.NewEncoder(w).Encode(users)\n}<\/code><\/pre>\n<h4><strong>Service (Business Logic Layer)<\/strong><\/h4>\n<p><code>internal\/service\/user_service.go<\/code><\/p>\n<pre><code class=\"language-go\">package service\n\nimport &quot;myapp\/internal\/repository&quot;\n\nfunc FetchUsers() []string {\n    return repository.GetUsersFromDB()\n}<\/code><\/pre>\n<h4><strong>Repository (Database Layer)<\/strong><\/h4>\n<p><code>internal\/repository\/user_repository.go<\/code><\/p>\n<pre><code class=\"language-go\">package repository\n\nfunc GetUsersFromDB() []string {\n    return []string{&quot;Alice&quot;, &quot;Bob&quot;, &quot;Charlie&quot;}\n}<\/code><\/pre>\n<hr \/>\n<h3><strong>4. Use Dependency Injection<\/strong><\/h3>\n<p>Avoid using global variables for dependencies. Instead, pass them explicitly.<\/p>\n<p>Example:<\/p>\n<pre><code class=\"language-go\">type UserService struct {\n    repo repository.UserRepository\n}\n\nfunc NewUserService(repo repository.UserRepository) *UserService {\n    return &amp;UserService{repo: repo}\n}<\/code><\/pre>\n<hr \/>\n<h3><strong>5. Configuration Management<\/strong><\/h3>\n<p>Use <code>viper<\/code> to manage configuration.<\/p>\n<h4><strong>Install Viper<\/strong><\/h4>\n<pre><code class=\"language-sh\">go get github.com\/spf13\/viper<\/code><\/pre>\n<h4><strong>Load Config<\/strong><\/h4>\n<pre><code class=\"language-go\">package config\n\nimport (\n    &quot;log&quot;\n    &quot;github.com\/spf13\/viper&quot;\n)\n\ntype Config struct {\n    Port string\n    DB   string\n}\n\nfunc LoadConfig() *Config {\n    viper.SetConfigName(&quot;config&quot;)\n    viper.SetConfigType(&quot;yaml&quot;)\n    viper.AddConfigPath(&quot;config\/&quot;)\n\n    if err := viper.ReadInConfig(); err != nil {\n        log.Fatalf(&quot;Error reading config file: %v&quot;, err)\n    }\n\n    return &amp;Config{\n        Port: viper.GetString(&quot;port&quot;),\n        DB:   viper.GetString(&quot;db&quot;),\n    }\n}<\/code><\/pre>\n<hr \/>\n<h3><strong>6. Logging<\/strong><\/h3>\n<p>Use <code>logrus<\/code> for structured logging.<\/p>\n<h4><strong>Install Logrus<\/strong><\/h4>\n<pre><code class=\"language-sh\">go get github.com\/sirupsen\/logrus<\/code><\/pre>\n<h4><strong>Logging Example<\/strong><\/h4>\n<pre><code class=\"language-go\">package logger\n\nimport (\n    &quot;github.com\/sirupsen\/logrus&quot;\n)\n\nvar log = logrus.New()\n\nfunc InitLogger() {\n    log.SetFormatter(&amp;logrus.JSONFormatter{})\n}\n\nfunc Info(msg string) {\n    log.Info(msg)\n}\n\nfunc Error(msg string, err error) {\n    log.WithError(err).Error(msg)\n}<\/code><\/pre>\n<hr \/>\n<h3><strong>7. Graceful Shutdown<\/strong><\/h3>\n<p>Ensure the server shuts down properly on termination signals.<\/p>\n<pre><code class=\"language-go\">package main\n\nimport (\n    &quot;context&quot;\n    &quot;net\/http&quot;\n    &quot;os&quot;\n    &quot;os\/signal&quot;\n    &quot;syscall&quot;\n    &quot;time&quot;\n)\n\nfunc main() {\n    server := &amp;http.Server{Addr: &quot;:8080&quot;, Handler: router}\n\n    go func() {\n        if err := server.ListenAndServe(); err != nil &amp;&amp; err != http.ErrServerClosed {\n            log.Fatalf(&quot;Listen: %s\\n&quot;, err)\n        }\n    }()\n\n    quit := make(chan os.Signal, 1)\n    signal.Notify(quit, os.Interrupt, syscall.SIGTERM)\n\n    &lt;-quit\n    log.Println(&quot;Shutting down server...&quot;)\n\n    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n    defer cancel()\n\n    if err := server.Shutdown(ctx); err != nil {\n        log.Fatal(&quot;Server forced to shutdown:&quot;, err)\n    }\n\n    log.Println(&quot;Server exiting&quot;)\n}<\/code><\/pre>\n<hr \/>\n<h3><strong>8. Unit Testing<\/strong><\/h3>\n<p>Use <code>httptest<\/code> to test handlers.<\/p>\n<h4><strong>Install Testify<\/strong><\/h4>\n<pre><code class=\"language-sh\">go get github.com\/stretchr\/testify<\/code><\/pre>\n<h4><strong>Write a Test<\/strong><\/h4>\n<p><code>internal\/handler\/user_handler_test.go<\/code><\/p>\n<pre><code class=\"language-go\">package handler\n\nimport (\n    &quot;net\/http&quot;\n    &quot;net\/http\/httptest&quot;\n    &quot;testing&quot;\n\n    &quot;github.com\/go-chi\/chi\/v5&quot;\n    &quot;github.com\/stretchr\/testify\/assert&quot;\n)\n\nfunc TestHealthCheck(t *testing.T) {\n    req, _ := http.NewRequest(&quot;GET&quot;, &quot;\/health&quot;, nil)\n    res := httptest.NewRecorder()\n\n    handler := http.HandlerFunc(HealthCheck)\n    handler.ServeHTTP(res, req)\n\n    assert.Equal(t, http.StatusOK, res.Code)\n}<\/code><\/pre>\n<hr \/>\n<h3><strong>9. Dockerizing the Service<\/strong><\/h3>\n<p>Create a <code>Dockerfile<\/code>:<\/p>\n<pre><code class=\"language-dockerfile\">FROM golang:1.20\nWORKDIR \/app\nCOPY . .\nRUN go mod tidy &amp;&amp; go build -o myapp .\/cmd\/server\/main.go\nCMD [&quot;.\/myapp&quot;]\nEXPOSE 8080<\/code><\/pre>\n<hr \/>\n<h3><strong>10. Automate with <code>Makefile<\/code><\/strong><\/h3>\n<pre><code class=\"language-makefile\">run:\n    go run cmd\/server\/main.go\n\ntest:\n    go test .\/... -v\n\nbuild:\n    go build -o myapp .\/cmd\/server\/main.go\n\ndocker-build:\n    docker build -t myapp .<\/code><\/pre>\n<hr \/>\n<h2><strong>Final Thoughts<\/strong><\/h2>\n<p>These best practices ensure:<br \/>\n\u2705 Clean architecture<br \/>\n\u2705 Maintainability<br \/>\n\u2705 Scalability<br \/>\n\u2705 Performance optimization  <\/p>\n<p>Would you like a more advanced example, such as integrating PostgreSQL, Redis, or gRPC? \ud83d\ude80<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Writing a backend service in Go efficiently involves following best practices for code structure, maintainability, and performance. Below is a simple and well-structured example of a RESTful backend service in Go with best practices applied. Best Practices for Writing a Backend Service in Go 1. Project Structure Organizing your code properly improves maintainability and scalability. [&hellip;] <a class=\"read-more\" href=\"https:\/\/www.fanyamin.com\/wordpress\/?p=1969\" title=\"Permanent Link to: best practice of go backend service  2\">&rarr;Read&nbsp;more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22],"tags":[],"class_list":["post-1969","post","type-post","status-publish","format-standard","hentry","category-golang"],"_links":{"self":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1969"}],"collection":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1969"}],"version-history":[{"count":1,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1969\/revisions"}],"predecessor-version":[{"id":1970,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1969\/revisions\/1970"}],"wp:attachment":[{"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1969"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1969"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fanyamin.com\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1969"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}