A web API (Application Programming Interface) is a set of rules and protocols that allows different software applications to communicate with each other over the web. It defines the methods and data formats that can be used to interact with a service.
src
, pkg
, and bin
directory. For example:mkdir go - projects
cd go - projects
mkdir src pkg bin
GOPATH
environment variable: This variable should point to your workspace directory.export GOPATH=$HOME/go - projects
Let’s start by creating a simple web API that returns a “Hello, World!” message.
package main
import (
"net/http"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello, World!"))
}
func main() {
http.HandleFunc("/", helloHandler)
http.ListenAndServe(":8080", nil)
}
To run this code, save it as main.go
and execute the following command in the terminal:
go run main.go
Now, open your browser and navigate to http://localhost:8080
. You should see the “Hello, World!” message.
The http.Request
object contains information about the incoming HTTP request, such as the request method (GET, POST, etc.), headers, and URL parameters.
package main
import (
"fmt"
"net/http"
)
func paramHandler(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
if name == "" {
name = "Guest"
}
message := fmt.Sprintf("Hello, %s!", name)
w.WriteHeader(http.StatusOK)
w.Write([]byte(message))
}
func main() {
http.HandleFunc("/greet", paramHandler)
http.ListenAndServe(":8080", nil)
}
In this example, the API expects a name
parameter in the URL. If the parameter is not provided, it uses “Guest” as the default name.
The http.ResponseWriter
interface is used to send HTTP responses back to the client. You can set the status code, headers, and the response body.
package main
import (
"net/http"
)
func customResponseHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content - Type", "text/plain")
w.WriteHeader(http.StatusCreated)
w.Write([]byte("Resource created successfully"))
}
func main() {
http.HandleFunc("/create", customResponseHandler)
http.ListenAndServe(":8080", nil)
}
The standard library’s http.ServeMux
provides basic routing capabilities. However, for more complex routing, you can use third - party libraries like gorilla/mux
.
package main
import (
"net/http"
"github.com/gorilla/mux"
)
func homeHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Home page"))
}
func aboutHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("About page"))
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/", homeHandler)
r.HandleFunc("/about", aboutHandler)
http.ListenAndServe(":8080", r)
}
Middleware functions are used to perform common tasks such as logging, authentication, and request validation before the actual request handler is called.
package main
import (
"log"
"net/http"
)
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("Received request: %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
})
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello, Middleware!"))
}
func main() {
mux := http.NewServeMux()
mux.Handle("/", loggingMiddleware(http.HandlerFunc(helloHandler)))
http.ListenAndServe(":8080", mux)
}
When receiving data from clients, it’s important to validate it to ensure its integrity. You can use the validator
package.
package main
import (
"fmt"
"net/http"
"github.com/go - playground/validator/v10"
)
type User struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
}
func createUserHandler(w http.ResponseWriter, r *http.Request) {
var user User
err := json.NewDecoder(r.Body).Decode(&user)
if err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
validate := validator.New()
err = validate.Struct(user)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusCreated)
w.Write([]byte(fmt.Sprintf("User %s created successfully", user.Name)))
}
To send data back to the client in a structured format, we often use JSON serialization.
package main
import (
"encoding/json"
"net/http"
)
type Book struct {
Title string `json:"title"`
Author string `json:"author"`
}
func getBookHandler(w http.ResponseWriter, r *http.Request) {
book := Book{
Title: "Go Programming",
Author: "John Doe",
}
w.Header().Set("Content - Type", "application/json")
json.NewEncoder(w).Encode(book)
}
Proper error handling is essential for building robust web APIs.
package main
import (
"log"
"net/http"
)
func errorHandler(w http.ResponseWriter, r *http.Request) {
_, err := 0 / 0
if err != nil {
http.Error(w, "Internal server error", http.StatusInternalServerError)
log.Println("Error:", err)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("No error"))
}
You can use the net/http/httptest
package to write unit tests for your web APIs.
package main
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestHelloHandler(t *testing.T) {
req, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Fatal(err)
}
rr := httptest.NewRecorder()
handler := http.HandlerFunc(helloHandler)
handler.ServeHTTP(rr, req)
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v",
status, http.StatusOK)
}
expected := "Hello, World!"
if rr.Body.String() != expected {
t.Errorf("handler returned unexpected body: got %v want %v",
rr.Body.String(), expected)
}
}
log
package, consider using a more feature - rich logging library like logrus
or zap
for better logging management.In this practical guide, we have covered the fundamental concepts, usage methods, common practices, and best practices for developing web APIs with Golang. We started by setting up the environment, building a basic API, and then explored more advanced topics such as routing, middleware, data validation, and testing. By following these guidelines, you can build efficient, scalable, and robust web APIs using Golang.