"If a worker wants to do his job well, he must first sharpen his tools." - Confucius, "The Analects of Confucius. Lu Linggong"
Front page > Programming > Adding Logging and Error Handling Middleware to Your Go API

Adding Logging and Error Handling Middleware to Your Go API

Published on 2024-11-08
Browse:334

Adding Logging and Error Handling Middleware to Your Go API

Quick Note: If you checked out my previous post on JWT authentication and noticed some rendering issues, those have now been fixed! Be sure to give it another look because these examples build on top of that tutorial. :)

Alright folks, we’ve got our Go API running, we’ve added JWT authentication, and we’ve even connected it to a PostgreSQL database. But we’re not done yet! This week, we’re going to take things up a notch and make our API smarter and more developer-friendly by adding custom middleware for logging and error handling.

What’s Middleware Again? ?

Middleware is like a bouncer at your favorite club—it intercepts requests before they hit your API endpoints. You can have middleware that checks authentication (like we did with JWT), logs information, or handles errors when things go wrong.

Today, we’re going to build middleware that:

  • Logs: Every incoming request, so we know who’s knocking on our API’s door.
  • Handles Errors: Gracefully, so your users don’t see those ugly 500 errors.

Let’s dive into it!


Step 1: Creating a Logging Middleware ?

Logging is your best friend when it comes to debugging and understanding what’s happening in your API. We’re going to create a middleware that logs every request that comes through—method, URL, and time taken.


func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()

        // Log the method and the requested URL
        log.Printf("Started %s %s", r.Method, r.URL.Path)

        // Call the next handler in the chain
        next.ServeHTTP(w, r)

        // Log how long it took
        log.Printf("Completed in %v", time.Since(start))
    })
}


For those who are interested in diving deeper into logging middleware, I recommend checking out Matt Silverlock’s fantastic guide on writing logging middleware in Go. He breaks down how to structure reusable middleware for various use cases like authentication, tracing, and of course, logging!

Step 2: Error Handling Middleware ?

Let’s talk about errors. Errors happen, right? But rather than letting them cause a crash or send a vague error message, let’s handle them gracefully.


func errorHandlingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        defer func() {
            if err := recover(); err != nil {
                // Log the error and send a user-friendly message
                log.Printf("Error occurred: %v", err)
                http.Error(w, "Internal Server Error", http.StatusInternalServerError)
            }
        }()
        next.ServeHTTP(w, r)
    })
}



Step 3: Integrating Middleware in Your API ?

Now that we’ve built our logging and error-handling middleware, let’s hook them up to our API. We’ll apply them globally so every request gets logged and errors are caught.


func main() {
    db = connectDB()
    defer db.Close()

    r := mux.NewRouter()

    // Apply middleware globally
    r.Use(loggingMiddleware)
    r.Use(errorHandlingMiddleware)

    r.HandleFunc("/login", login).Methods("POST")
    r.Handle("/books", authenticate(http.HandlerFunc(getBooks))).Methods("GET")
    r.Handle("/books", authenticate(http.HandlerFunc(createBook))).Methods("POST")

    fmt.Println("Server started on port :8000")
    log.Fatal(http.ListenAndServe(":8000", r))
}



Step 4: Testing It Out ?

To make sure everything’s working, start up your API:


go run main.go


Now, try hitting any of your endpoints (like /books) and check your terminal. You should see logs like:


Started GET /books
Completed in 1.2ms


And if there’s an error, you’ll see:


Error occurred: some error details


But your user will only see a clean "500 Internal Server Error" message. ?


Why Is This Important?

  1. Logging helps you track down bugs and monitor the behavior of your API. If something goes wrong, you’ll know exactly which endpoint was hit and how long the request took.

  2. Error Handling prevents your API from crashing when something unexpected happens. Instead, it recovers gracefully and sends a clean error message to the client.


What’s Next?

Next time, we’ll take things to the next level and dockerize our Go API! This will make your app portable and ready for deployment on any machine or cloud service. Get ready for some container magic! ?

Release Statement This article is reproduced at: https://dev.to/neelp03/adding-logging-and-error-handling-middleware-to-your-go-api-2f33?1 If there is any infringement, please contact [email protected] to delete it
Latest tutorial More>

Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.

Copyright© 2022 湘ICP备2022001581号-3