<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Agust Rinaldo Kurniawan</title>
    <description>The latest articles on DEV Community by Agust Rinaldo Kurniawan (@agustrinaldokurniawan).</description>
    <link>https://dev.to/agustrinaldokurniawan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F607542%2F04230752-347e-4e87-93d8-0eb488ad630f.jpg</url>
      <title>DEV Community: Agust Rinaldo Kurniawan</title>
      <link>https://dev.to/agustrinaldokurniawan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/agustrinaldokurniawan"/>
    <language>en</language>
    <item>
      <title>Build basic microservice online store backend with Golang use Api Gateway Pattern - Part 1</title>
      <dc:creator>Agust Rinaldo Kurniawan</dc:creator>
      <pubDate>Fri, 30 Aug 2024 14:32:44 +0000</pubDate>
      <link>https://dev.to/agustrinaldokurniawan/build-basic-microservice-online-store-backend-with-golang-use-api-gateway-pattern-1bf</link>
      <guid>https://dev.to/agustrinaldokurniawan/build-basic-microservice-online-store-backend-with-golang-use-api-gateway-pattern-1bf</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hey, fellow developers! 👋 Ever thought about building a microservices architecture but felt overwhelmed by where to start? Worry no more! In this article, we'll build a basic microservices setup using the API Gateway pattern for an online store. And guess what? We'll do it all in Go (Golang)! 🦦&lt;/p&gt;

&lt;h2&gt;
  
  
  What You'll Learn
&lt;/h2&gt;

&lt;p&gt;By the end of this guide, you’ll know how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement the API Gateway pattern in a microservices architecture.&lt;/li&gt;
&lt;li&gt;Use gRPC for seamless communication between services.&lt;/li&gt;
&lt;li&gt;Set up multiple microservices in Go with Docker.&lt;/li&gt;
&lt;li&gt;Connect the dots and make everything work smoothly together!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why &lt;strong&gt;Microservices&lt;/strong&gt;? Why &lt;strong&gt;Go&lt;/strong&gt;? Why &lt;strong&gt;API Gateway&lt;/strong&gt;? 🤔
&lt;/h2&gt;

&lt;p&gt;Before we dive into the code, let’s talk about why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Microservices&lt;/strong&gt;: Scalability, independent deployment, and flexibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go&lt;/strong&gt;: Fast, efficient, and ideal for building microservices.&lt;/li&gt;
&lt;li&gt;**API **Gateway: Centralized entry point to handle all client requests and route them to the appropriate microservice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Who said that? Me 😂. Just kidding, but you'll soon be quoting this too when your app handles a gazillion users without breaking a sweat! Imagine your API dancing through the traffic while sipping coffee ☕. Yes, that’s the power of Microservices with Go and an API Gateway.&lt;/p&gt;

&lt;p&gt;Oke, without further ado let's start it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Setting Up Your Environment 🛠️
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install and download Go &lt;a href="https://go.dev/doc/install" rel="noopener noreferrer"&gt;https://go.dev/doc/install&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Use docker for your microservices &lt;a href="https://docs.docker.com/engine/install/" rel="noopener noreferrer"&gt;https://docs.docker.com/engine/install/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Just use IDE that you want&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Setup you project
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/online-store
├── api-gateway/
├──── cmd/
├────── main.go
├──── internal/
├────── handler/
├──────── handler.go
├── services/
├──── user-service/
├────── cmd/
├──────── main.go
├────── internal/
├──────── handler/
├────────── handler.go
├────── proto/
├──────── user-proto
├────── Dockerfile
├──── &amp;lt;you can add more services&amp;gt;/
├── docker-compose.yml
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's will be the dir structure the project, you can tweak it as you want, later we will also create pb directory do store generated pb file from our proto file.&lt;/p&gt;

&lt;p&gt;Clone googleapis &lt;a href="https://github.com/googleapis/googleapis" rel="noopener noreferrer"&gt;https://github.com/googleapis/googleapis&lt;/a&gt;, we will need that for our proto later. Just clone in root dir under &lt;code&gt;online-store&lt;/code&gt; dir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/googleapis/googleapis.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Building the User Service 👤
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Initiate Go Mod&lt;br&gt;
Let's use our terminal and initiate our user-service go mod init&lt;br&gt;
&lt;code&gt;go mod init user-service&lt;/code&gt;&lt;br&gt;
you can change "user-service" with your github url, but we will use it for now.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create our first proto file for user&lt;br&gt;
create a new file under &lt;code&gt;user-service/proto&lt;/code&gt; dir with name &lt;code&gt;user.proto&lt;/code&gt;, let's use this proto code:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;syntax = "proto3";

package order;

option go_package = ".";

import "google/api/annotations.proto";

service OrderService {
    rpc GetMyOrder(GetMyOrderRequest) returns (GetMyOrderResponse) {
        option (google.api.http) = {
            get: "/v1/order/my"
        };
    }
}

message GetMyOrderRequest {
    string user_id = 1;
}

message GetMyOrderResponse {
    string  user_id = 1;
    string order_id = 2;
    string product_id = 3;
    int32 quantity = 4;
    float price = 5;
    string status = 6;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Use protoc to generate gRPC
First, we need to create pb dir under &lt;code&gt;service/user-service&lt;/code&gt; to store our generated grpc files and run this command to generate our gRPC:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protoc --proto_path="services/user-service/proto" \
        --go_out="services/user-service/pb" \
        --go-grpc_out="services/user-service/pb" \
        --grpc-gateway_out="services/user-service/pb" \
        "services/user-service/proto/user.proto"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that command we will generate 3 files (user_grpc.pb.go, user_pb.go, and user.pb.gw.go) and will place them into services/user-service/pb directory.&lt;/p&gt;

&lt;p&gt;But, because we want use the same grpc to our Api Gateway, we need to copy them too into &lt;code&gt;api-gateway/pb&lt;/code&gt; directory. You can copy it manually each time you generate grpc, but let's just use script for it.&lt;/p&gt;

&lt;p&gt;I create a new dir &lt;code&gt;online-store/scripts&lt;/code&gt; to store all scripts. Let's create a new file &lt;code&gt;generate-proto.sh&lt;/code&gt;, and put this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

# Error handling function
handle_error() {
  echo "Error occurred in script at line: $1"
  exit 1
}

# Trap any error and call the handle_error function
trap 'handle_error $LINENO' ERR

# Declare an associative array to map proto directories to their corresponding pb directories
declare -A dir_map=(
  ["services/user-service/proto"]="services/user-service/pb"
  # you can add another directory here
  # e.g ["services/order-service/proto"]="services/order-service/pb"
)

# Define Static Dir Path
GOOGLEAPIS_DIR="googleapis"
API_GATEWAY_PB_DIR="api-gateway/pb"

# Ensure the API_GATEWAY_PB_DIR exists
if [ ! -d "$API_GATEWAY_PB_DIR" ]; then
  mkdir -p "$API_GATEWAY_PB_DIR"
  echo "Directory $API_GATEWAY_PB_DIR created."
else 
  echo "Directory $API_GATEWAY_PB_DIR already exists."
fi

# Loop through the associative array and generate Go code for each proto directory
for proto_dir in "${!dir_map[@]}"; do
  pb_dir="${dir_map[$proto_dir]}"

  # Check if the pb directory exists, if not, create it
  if [ ! -d "$pb_dir" ]; then
    mkdir -p "$pb_dir"
    echo "Directory $pb_dir created."
  else
    echo "Directory $pb_dir already exists."
  fi

  # Process each .proto file in the proto directory
  for proto_file in "$proto_dir"/*.proto; do
    # Ensure the proto file exists
    if [ -f "$proto_file" ]; then
      # Generate Go code for the current proto file
      protoc --proto_path="$proto_dir" \
        --proto_path="$GOOGLEAPIS_DIR" \
        --go_out="$pb_dir" \
        --go-grpc_out="$pb_dir" \
        --grpc-gateway_out="$pb_dir" \
        "$proto_file"
      echo "Generated Go code for $proto_file"

      # Copy the generated Go code to the API Gateway directory
      cp -auv "$pb_dir"/* "$API_GATEWAY_PB_DIR/"
      echo "Copied generated Go code to $API_GATEWAY_PB_DIR from $pb_dir"
    else
      echo "No .proto files found in $proto_dir."
    fi
  done
done

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That script will create you a new pb directory if it's does not exist.&lt;/p&gt;

&lt;p&gt;Now, lets execute our script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./scripts/generate-proto.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will need to install some packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/grpc-ecosystem/grpc-gateway/v2
go get google.golang.org/genproto/googleapis/api
go get .golang.org/protobuf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get some error regarding import, do this comman &lt;code&gt;go mod tidy&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create our user handler code
create a &lt;code&gt;user-handler.go&lt;/code&gt; file under &lt;code&gt;services/user-services/internal/handler&lt;/code&gt; directory, use let's use this simple code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package handler

import (
    "context"
    "log"

    pb "user-service/pb"

    "google.golang.org/grpc"
)

// server implements the UserServiceServer interface
type server struct {
    pb.UnimplementedUserServiceServer
}

// NewServer creates a new instance of server
func NewServer() pb.UserServiceServer {
    return &amp;amp;server{}
}

// Implement the methods defined in your proto file here
func (s *server) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) {
    // Log the request details
    log.Printf("Received GetUser request with ID: %s", req.GetId())

    // Implement your logic to get user information
    response := &amp;amp;pb.GetUserResponse{
        Id:    req.GetId(),
        Name:  "John Doe",
        Email: "john.doe@example.com",
    }

    // Log the response details
    log.Printf("Returning GetUser response: %+v", response)

    return response, nil
}

// Implement GetUserProfile method
func (s *server) GetUserProfile(ctx context.Context, req *pb.GetUserProfileRequest) (*pb.GetUserProfileResponse, error) {
    // Log the request details
    log.Printf("Received GetUserProfile request with ID: %s", req.GetId())

    response := &amp;amp;pb.GetUserProfileResponse{
        Id:      req.GetId(),
        Name:    "John Doe",
        Email:   "john.doe@example.com",
        Phone:   "1234567890",
        Address: "123 Main St",
    }

    // Log the response details
    log.Printf("Returning GetUserProfile response: %+v", response)

    return response, nil
}

// RegisterServices registers the gRPC services with the server
func RegisterServices(s *grpc.Server) {
    pb.RegisterUserServiceServer(s, NewServer())
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will need to install some package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get google.golang.org/grpc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create our main.go file in &lt;code&gt;user-service/cmd/main.go&lt;/code&gt;
We use this simple code for our main code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "log"
    "net"

    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"

    "user-service/internal/handler"
)

func main() {
    // Create a new gRPC server
    s := grpc.NewServer()

    // Register the server with the gRPC server
    handler.RegisterServices(s)

    // Register reflection service on gRPC server
    reflection.Register(s)

    // Listen on port 50051
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }

    // Start the gRPC server
    log.Println("Starting gRPC server on :50051")
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to install &lt;code&gt;google.golang.org/grpc/reflection&lt;/code&gt;, with this package we can look into our services.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create Dockerfile for user-service
create a new file in user-service directory with name Dockerfile, use this for our Dockerfile:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Stage 1: Build
FROM golang:1.23 AS builder

WORKDIR /app

# Copy go mod and sum files
COPY go.mod go.sum ./
RUN go mod download

# Copy the application code
COPY . .

# Build the Go application
RUN go build -o user-service ./cmd

# Stage 2: Run
FROM ubuntu:22.04

# Install necessary libraries
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
    ca-certificates \
    libc6 \
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Copy the binary from the build stage
COPY --from=builder /app/user-service /app/user-service

ENTRYPOINT ["/app/user-service"]

# Expose port
EXPOSE 50051
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Build Api Gateway
&lt;/h2&gt;

&lt;p&gt;Because we already have pb files generated under &lt;code&gt;api-gateway/pb&lt;/code&gt; directory. Now, we can create handler for our api-gateway, create a new file &lt;code&gt;api-gateway/internal/handler/service-regitry.go&lt;/code&gt;, use this code to register our services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package handler

import (
    "context"
    "log"

    "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    "google.golang.org/grpc"

    pb "api-gateway/pb"
)

// ServiceConfig holds the configuration for each service.
type ServiceConfig struct {
    Name    string
    Address string
}

// RegisterServices registers all services with the mux based on the given service configurations.
func RegisterServices(ctx context.Context, mux *runtime.ServeMux, services []ServiceConfig) error {
    for _, svc := range services {
        opts := []grpc.DialOption{grpc.WithInsecure()}
        var err error
        switch svc.Name {
        case "UserService":
            err = pb.RegisterUserServiceHandlerFromEndpoint(ctx, mux, svc.Address, opts)
        // We can create another cases for another services
        default:
            log.Printf("No handler implemented for service %s", svc.Name)
            continue
        }
        if err != nil {
            return err
        }
        log.Printf("Registered service %s at %s", svc.Name, svc.Address)
    }
    return nil
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will also need to install these in &lt;code&gt;api-gateway&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/grpc-ecosystem/grpc-gateway
go get google.golang.org/grpc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create our main.go in Api Gateway
Now, create a new file &lt;code&gt;api-gateway/cmd/main.go&lt;/code&gt; for our main code, use this code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "context"
    "log"
    "net/http"

    "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"

    "api-gateway/internal/handler"
)

func main() {
    // Define service configurations
    services := []handler.ServiceConfig{
        {Name: "UserService", Address: "user-service:50051"},
        // You can add another services here
    }

    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()

    mux := runtime.NewServeMux()

    // Register services
    if err := handler.RegisterServices(ctx, mux, services); err != nil {
        log.Fatalf("Failed to register services: %v", err)
    }

    // Start the HTTP server
    if err := http.ListenAndServe(":8080", mux); err != nil {
        log.Fatalf("Failed to start HTTP server: %v", err)
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create Dockerfile for Api Gateway
We also need Dockerfile for Api Gateway, create a new file &lt;code&gt;api-gateway/Dockerfile&lt;/code&gt; and use this config:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Stage 1: Build
FROM golang:1.23 AS builder

WORKDIR /app

# Copy go mod and sum files
COPY go.mod go.sum ./
RUN go mod download

# Copy the application code
COPY . .

# Build the Go application
RUN go build -o main ./cmd

# Stage 2: Run
FROM ubuntu:22.04

# Install necessary libraries
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
    ca-certificates \
    libc6 \
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Copy the binary from the build stage
COPY --from=builder /app/main /app/main

ENTRYPOINT ["/app/main"]

# Expose port (if necessary)
EXPOSE 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create docker-compose.yml
Oke, we also need to create a &lt;code&gt;online-store/docker-compose.yml&lt;/code&gt; file, use use copy:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '4.0'
services:
  api-gateway:
    build: ./api-gateway
    ports:
      - "8080:8080"
    depends_on:
      - user-service

  user-service:
    build: 
      context: ./services/user-service
      dockerfile: Dockerfile
    ports:
      - "50051:50051"

  # Can put another service here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Start our Microservice
&lt;/h3&gt;

&lt;p&gt;Because we use docker, make sure your docker already active.&lt;br&gt;
And we can run with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose up --build -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see your services already up. (I use windows)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8v7w5qavdpd36fenvxi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj8v7w5qavdpd36fenvxi.png" alt="Image description" width="800" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also use this command to see active service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjr8bjb6gj16ln62wc3eq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjr8bjb6gj16ln62wc3eq.png" alt="Image description" width="800" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You see that i also have another services, you can also add it to your code.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Hit our endpoint
&lt;/h3&gt;

&lt;p&gt;I use postman to hit user-service endpoint&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8w4850pzs7j9l7rmtov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8w4850pzs7j9l7rmtov.png" alt="Image description" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because we also put log code in our user-service, we can do this command to look into our service logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker logs --follow user-service-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure service name by looks into our active service &lt;code&gt;docker ps&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then you will see this log:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9ue1pjv3lekoz8s290i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz9ue1pjv3lekoz8s290i.png" alt="Image description" width="739" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion 🏁
&lt;/h3&gt;

&lt;p&gt;Congratulations! 🎉 You've just built a basic microservices architecture for an online store using Go, gRPC, Docker. Keep experimenting and improving your setup. We will continue to build our online-store until finish, stay tune 🧑‍💻🚀&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/agustrinaldokurniawan/online-store/tree/main/backend" rel="noopener noreferrer"&gt;https://github.com/agustrinaldokurniawan/online-store/tree/main/backend&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>microservices</category>
      <category>docker</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build Simple Rest API Nodejs From Scratch</title>
      <dc:creator>Agust Rinaldo Kurniawan</dc:creator>
      <pubDate>Tue, 28 Sep 2021 06:38:08 +0000</pubDate>
      <link>https://dev.to/agustrinaldokurniawan/build-simple-rest-api-nodejs-from-scratch-5eh7</link>
      <guid>https://dev.to/agustrinaldokurniawan/build-simple-rest-api-nodejs-from-scratch-5eh7</guid>
      <description>&lt;p&gt;&lt;a href="https://medium.com/@agustkurniawan010899/build-simple-rest-api-with-nodejs-without-any-framework-like-expressjs-part-1-fd570b2892ba" rel="noopener noreferrer"&gt;https://medium.com/@agustkurniawan010899/build-simple-rest-api-with-nodejs-without-any-framework-like-expressjs-part-1-fd570b2892ba&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
