Organize your code in a way that makes it easy to understand and extend. A common structure includes separating your code into folders such as models, handlers, routes, middlewares, utils, and config.
Example structure:
go-rest-api/ |-- main.go |-- config/ | |-- config.go |-- handlers/ | |-- user.go |-- models/ | |-- user.go |-- routes/ | |-- routes.go |-- middlewares/ | |-- logging.go |-- utils/ | |-- helpers.go
Store configuration settings (like database credentials, port numbers, etc.) in environment variables or configuration files. Use a package like viper to manage configurations.
config/config.go:
package config import ( "github.com/spf13/viper" "log" ) type Config struct { Port string DB struct { Host string Port string User string Password string Name string } } var AppConfig Config func LoadConfig() { viper.SetConfigName("config") viper.AddConfigPath(".") viper.AutomaticEnv() if err := viper.ReadInConfig(); err != nil { log.Fatalf("Error reading config file, %s", err) } err := viper.Unmarshal(&AppConfig) if err != nil { log.Fatalf("Unable to decode into struct, %v", err) } }
Always handle errors appropriately. Return meaningful error messages and HTTP status codes.
handlers/user.go:
func GetUserHandler(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) id, err := strconv.Atoi(params["id"]) if err != nil { http.Error(w, "Invalid user ID", http.StatusBadRequest) return } user, err := findUserByID(id) if err != nil { http.Error(w, "User not found", http.StatusNotFound) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(user) }
Use middlewares for logging, authentication, and other cross-cutting concerns.
middlewares/logging.go:
package middlewares import ( "log" "net/http" "time" ) func LoggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() next.ServeHTTP(w, r) log.Printf("%s %s %s", r.Method, r.RequestURI, time.Since(start)) }) }
In main.go or routes/routes.go:
r.Use(middlewares.LoggingMiddleware)
Use proper JSON encoding and decoding. Validate incoming JSON data to ensure it meets the expected structure.
handlers/user.go:
func CreateUserHandler(w http.ResponseWriter, r *http.Request) { var user models.User if err := json.NewDecoder(r.Body).Decode(&user); err != nil { http.Error(w, "Invalid input", http.StatusBadRequest) return } // Validate user data... users = append(users, user) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(user) }
Use a database to store your data. Use a package like gorm for ORM or sqlx for raw SQL queries.
models/user.go:
package models import "gorm.io/gorm" type User struct { gorm.Model Name string `json:"name"` Email string `json:"email"` }
main.go:
package main import ( "github.com/yourusername/go-rest-api/config" "github.com/yourusername/go-rest-api/routes" "gorm.io/driver/postgres" "gorm.io/gorm" "log" "net/http" ) func main() { config.LoadConfig() dsn := "host=" + config.AppConfig.DB.Host + " user=" + config.AppConfig.DB.User + " password=" + config.AppConfig.DB.Password + " dbname=" + config.AppConfig.DB.Name + " port=" + config.AppConfig.DB.Port + " sslmode=disable" db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) if err != nil { log.Fatalf("Could not connect to the database: %v", err) } r := routes.NewRouter(db) log.Println("Starting server on port", config.AppConfig.Port) log.Fatal(http.ListenAndServe(":"+config.AppConfig.Port, r)) }
Use a structured logging library like logrus or zap for better logging.
middlewares/logging.go:
package middlewares import ( "github.com/sirupsen/logrus" "net/http" "time" ) func LoggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() next.ServeHTTP(w, r) logrus.WithFields(logrus.Fields{ "method": r.Method, "url": r.URL.Path, "time": time.Since(start), }).Info("handled request") }) }
Ensure your API is secure by using HTTPS, validating and sanitizing inputs, and implementing proper authentication and authorization.
Version your API to handle changes without breaking existing clients. This can be done by including the version in the URL, such as /api/v1/users.
Document your API using tools like Swagger or Postman to provide clear usage instructions for developers.
By following these best practices, you can create a robust, maintainable, and scalable RESTful API in Go.
The above is the detailed content of Rest Full API - Golang (Best Practices). For more information, please follow other related articles on the PHP Chinese website!