DEV Community

Saunak Surani for Widle Studio LLP

Posted on

Designing Microservices RESTful API using Go with CRUD Operations: A Practical Guide

Abstract:
Microservices architecture has gained immense popularity for building scalable and maintainable applications. In this article, we explore how to design a Microservices RESTful API using Go, a powerful and efficient programming language. We will walk through the process of creating a simple CRUD (Create, Read, Update, Delete) API for a hypothetical blog application. By following this step-by-step guide, developers will gain a clear understanding of how to design microservices and RESTful APIs using Go, enabling them to build robust and flexible systems.

Designing Microservices RESTful API using Go with CRUD Operations: A Practical Guide

Introduction:
Microservices architecture has emerged as a preferred approach for developing modern, scalable applications. By breaking down monolithic applications into smaller, independent services, microservices allow developers to build, test, deploy, and scale each component independently. This architecture promotes agility, fault isolation, and continuous delivery, making it an ideal choice for complex and evolving applications.

In this article, we will focus on building a microservices-based RESTful API using the Go programming language. Go, also known as Golang, is renowned for its simplicity, performance, and strong concurrency support. By leveraging Go's strengths, we can create a fast and efficient microservice API that handles CRUD operations for a blog application.

Prerequisites:
To follow this guide, a basic understanding of the Go programming language and RESTful API principles is recommended. Additionally, ensure that you have Go installed on your development environment.

Step 1: Project Structure
Before we start coding, let's define the project structure. In Go, it is common to have a separate directory for each microservice. For this example, we'll create three directories:

- blog-service
    |- main.go
    |- handlers
        |- handlers.go
    |- models
        |- models.go
Enter fullscreen mode Exit fullscreen mode
  • main.go: This file will contain the main function and the server setup.
  • handlers: This directory will hold the API request handlers.
  • models: This directory will contain the data models and database interactions.

Step 2: Setting up Dependencies
In this example, we'll use a lightweight HTTP router called "mux" to handle our API routes. We need to install this dependency before proceeding.

go get -u github.com/gorilla/mux
Enter fullscreen mode Exit fullscreen mode

Step 3: Define the Data Model
In our blog application, we will have a Post data model with basic fields such as ID, Title, and Content. Let's define the data model in the models directory.

// models/models.go
package models

type Post struct {
    ID      int    `json:"id"`
    Title   string `json:"title"`
    Content string `json:"content"`
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Implement the Handlers
Next, we'll create the request handlers in the handlers directory. We need to handle four types of CRUD operations: Create, Read, Update, and Delete. For simplicity, we'll use an in-memory slice as our data storage.

// handlers/handlers.go
package handlers

import (
    "encoding/json"
    "fmt"
    "net/http"
    "strconv"

    "github.com/gorilla/mux"
    "your-module-name/models"
)

var posts []models.Post

func CreatePost(w http.ResponseWriter, r *http.Request) {
    var post models.Post
    _ = json.NewDecoder(r.Body).Decode(&post)
    post.ID = len(posts) + 1
    posts = append(posts, post)
    json.NewEncoder(w).Encode(post)
}

func GetAllPosts(w http.ResponseWriter, r *http.Request) {
    json.NewEncoder(w).Encode(posts)
}

func GetPostByID(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    postID, err := strconv.Atoi(vars["id"])
    if err != nil {
        http.Error(w, "Invalid post ID", http.StatusBadRequest)
        return
    }

    for _, post := range posts {
        if post.ID == postID {
            json.NewEncoder(w).Encode(post)
            return
        }
    }

    http.NotFound(w, r)
}

func UpdatePost(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    postID, err := strconv.Atoi(vars["id"])
    if err != nil {
        http.Error(w, "Invalid post ID", http.StatusBadRequest)
        return
    }

    var updatedPost models.Post
    _ = json.NewDecoder(r.Body).Decode(&updatedPost)

    for i, post := range posts {
        if post.ID == postID {
            updatedPost.ID = postID
            posts[i] = updatedPost
            json.NewEncoder(w).Encode(updatedPost)
            return
        }
    }

    http.NotFound(w, r)
}

func DeletePost(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    postID, err := strconv.Atoi(vars["id"])
    if err != nil {
        http.Error(w, "Invalid post ID", http.StatusBadRequest)
        return
    }

    for i, post := range posts {
        if post.ID == postID {
            posts = append(posts[:i], posts[i+1:]...)
            fmt.Fprintf(w, "Post with ID %d is deleted", postID)
            return
        }
    }

    http.NotFound(w, r)
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Set up the Server
Now that we have our data model and request handlers ready, let's set up the server in the main.go file.

// main.go
package main

import (
    "log"
    "net/http"

    "github.com/gorilla/mux"
    "your-module-name/handlers"
)

func main() {
    // Initialize the router
    router := mux.NewRouter()

    // Create routes and map them to the corresponding handlers
    router.HandleFunc("/posts", handlers.GetAllPosts).Methods("GET")
    router.HandleFunc("/posts/{id}", handlers.GetPostByID).Methods("GET")
    router.HandleFunc("/posts", handlers.CreatePost).Methods("POST")
    router.HandleFunc("/posts/{id}", handlers.UpdatePost).Methods("PUT")
    router.HandleFunc("/posts/{id}", handlers.DeletePost).Methods("DELETE")

    // Start the server on port 8080
    log.Fatal(http.ListenAndServe(":8080", router))
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Test the API
With the server up and running, you can test the API using tools like cURL or Postman. Here are some example requests:

  1. Create a new post:
   curl -X POST -H "Content-Type: application/json" -d '{"title":"New Post", "content":"This is the content of the new post."}' http://localhost:8080/posts
Enter fullscreen mode Exit fullscreen mode
  1. Get all posts:
   curl http://localhost:8080/posts
Enter fullscreen mode Exit fullscreen mode
  1. Get a post by ID (replace {id} with the actual post ID):
   curl http://localhost:8080/posts/{id}
Enter fullscreen mode Exit fullscreen mode
  1. Update a post by ID (replace {id} with the actual post ID):
   curl -X PUT -H "Content-Type: application/json

" -d '{"title":"Updated Post Title", "content":"This is the updated content of the post."}' http://localhost:8080/posts/{id}
Enter fullscreen mode Exit fullscreen mode
  1. Delete a post by ID (replace {id} with the actual post ID):
   curl -X DELETE http://localhost:8080/posts/{id}
Enter fullscreen mode Exit fullscreen mode

Conclusion:
In this article, we have walked through the process of designing a Microservices RESTful API using Go, implementing CRUD operations for a simple blog application. By following this step-by-step guide, developers can gain valuable insights into creating scalable and maintainable microservices with Go. While the example provided here is minimalistic, the principles and practices outlined can be extended to build more complex and feature-rich microservices architectures. Remember to continue exploring Go's rich ecosystem and best practices to build robust and efficient microservices for your own applications.

Top comments (0)