Friday, September 30, 2022
Cloud Run Firestore GCP

Developing a REST API with Go and Cloud Run

REST

“Developing a REST API with Go and Cloud Run”

Pengantar

Dua belas tahun yang lalu, Lily memulai rantai klinik hewan Teori Hewan Peliharaan. Seiring berkembangnya rantai klinik, Lily menghabiskan lebih banyak waktu di telepon dengan perusahaan asuransi daripada merawat hewan peliharaan. Andai saja perusahaan asuransi dapat melihat total perawatan secara online.

Di lab sebelumnya dalam seri ini, Ruby, konsultan komputer, dan Patrick, Insinyur DevOps, memindahkan basis data pelanggan Pet Theory ke basis data Firestore tanpa server di cloud, lalu membuka akses sehingga pelanggan dapat membuat janji temu secara online. Karena tim Ops Pet Theory adalah satu orang, mereka membutuhkan solusi tanpa server yang tidak memerlukan banyak pemeliharaan berkelanjutan.

Enable Google APIs

Developing the REST API

  • Aktifkan project
gcloud config set project $(gcloud projects list --format='value(PROJECT_ID)' --filter='qwiklabs-gcp')
  • Clone repository
git clone https://github.com/rosera/pet-theory.git && cd pet-theory/lab08
  • Buat file main.go
nano main.go

package main
import (
  "fmt"
  "log"
  "net/http"
  "os"
)
func main() {
  port := os.Getenv("PORT")
  if port == "" {
      port = "8080"
  }
  http.HandleFunc("/v1/", func(w http.ResponseWriter, r *http.Request) {
      fmt.Fprintf(w, "{status: 'running'}")
  })
  log.Println("Pets REST API listening on port", port)
  if err := http.ListenAndServe(":"+port, nil); err != nil {
      log.Fatalf("Error launching Pets REST API server: %v", err)
  }
}
nano Dockerfile

FROM gcr.io/distroless/base-debian10
WORKDIR /usr/src/app
COPY server .
CMD [ "/usr/src/app/server" ]
go build -o server
  • Deploy simple rest API
gcloud builds submit \
  --tag gcr.io/$GOOGLE_CLOUD_PROJECT/rest-api:0.1
  • Cek via Navigation menu > Container Registry
  • deploy
gcloud run deploy rest-api \
  --image gcr.io/$GOOGLE_CLOUD_PROJECT/rest-api:0.1 \
  --platform managed \
  --region us-central1 \
  --allow-unauthenticated \
  --max-instances=2

Import test customer data

  • Masuk ke Navigation Menu > Firestore.
  • Pilih native mode
  • Pilih “nam5” (United States) multi-region
  • Pilih Create Database
  • Buat bucket
  • Import ke bucket
gsutil cp -r gs://spls/gsp645/2019-10-06T20:10:37_43617 gs://$GOOGLE_CLOUD_PROJECT-customer
  • Import data ke firestore
gcloud beta firestore import gs://$GOOGLE_CLOUD_PROJECT-customer/2019-10-06T20:10:37_43617/

Connect the REST API to the Firestore database

  • cek project
echo $GOOGLE_CLOUD_PROJECT
  • Buka main.go . dan replace dengan code berikut -> ganti project ID dengan yang di atas
package main
import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"cloud.google.com/go/firestore"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"google.golang.org/api/iterator"
)
var client *firestore.Client
func main() {
	var err error
	ctx := context.Background()
	client, err = firestore.NewClient(ctx, "PROJECT_ID")
	if err != nil {
	log.Fatalf("Error initializing Cloud Firestore client: %v", err)
	}
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	r := mux.NewRouter()
	r.HandleFunc("/v1/", rootHandler)
	r.HandleFunc("/v1/customer/{id}", customerHandler)
	log.Println("Pets REST API listening on port", port)
	cors := handlers.CORS(
		handlers.AllowedHeaders([]string{"X-Requested-With", "Authorization", "Origin"}),
		handlers.AllowedOrigins([]string{"https://storage.googleapis.com"}),
		handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "OPTIONS", "PATCH", "CONNECT"}),
	)
	if err := http.ListenAndServe(":"+port, cors(r)); err != nil {
		log.Fatalf("Error launching Pets REST API server: %v", err)
	}
}
  • Tambahkan code berikut di paling bawah
func rootHandler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "{status: 'running'}")
}
func customerHandler(w http.ResponseWriter, r *http.Request) {
  id := mux.Vars(r)["id"]
  ctx := context.Background()
  customer, err := getCustomer(ctx, id)
  if err != nil {
    w.WriteHeader(http.StatusInternalServerError)
    fmt.Fprintf(w, `{"status": "fail", "data": '%s'}`, err)
    return
  }
  if customer == nil {
    w.WriteHeader(http.StatusNotFound)
    msg := fmt.Sprintf("`Customer \"%s\" not found`", id)
    fmt.Fprintf(w, fmt.Sprintf(`{"status": "fail", "data": {"title": %s}}`, msg))
    return
  }
  amount, err := getAmounts(ctx, customer)
  if err != nil {
    w.WriteHeader(http.StatusInternalServerError)
    fmt.Fprintf(w, `{"status": "fail", "data": "Unable to fetch amounts: %s"}`, err)
    return
  }
  data, err := json.Marshal(amount)
  if err != nil {
    w.WriteHeader(http.StatusInternalServerError)
    fmt.Fprintf(w, `{"status": "fail", "data": "Unable to fetch amounts: %s"}`, err)
    return
  }
  fmt.Fprintf(w, fmt.Sprintf(`{"status": "success", "data": %s}`, data))
}

type Customer struct {
  Email string `firestore:"email"`
  ID    string `firestore:"id"`
  Name  string `firestore:"name"`
  Phone string `firestore:"phone"`
}
func getCustomer(ctx context.Context, id string) (*Customer, error) {
  query := client.Collection("customers").Where("id", "==", id)
  iter := query.Documents(ctx)
  var c Customer
  for {
    doc, err := iter.Next()
    if err == iterator.Done {
	break
    }
    if err != nil {
	return nil, err
    }
    err = doc.DataTo(&c)
    if err != nil {
	return nil, err
    }
  }
  return &c, nil
}
func getAmounts(ctx context.Context, c *Customer) (map[string]int64, error) {
  if c == nil {
    return map[string]int64{}, fmt.Errorf("Customer should be non-nil: %v", c)
  }
  result := map[string]int64{
    "proposed": 0,
    "approved": 0,
    "rejected": 0,
  }
  query := client.Collection(fmt.Sprintf("customers/%s/treatments", c.Email))
  if query == nil {
    return map[string]int64{}, fmt.Errorf("Query is nil: %v", c)
  }
  iter := query.Documents(ctx)
  for {
    doc, err := iter.Next()
    if err == iterator.Done {
	break
    }
    if err != nil {
	return nil, err
    }
    treatment := doc.Data()
    result[treatment["status"].(string)] += treatment["cost"].(int64)
  }
  return result, nil
}

Deploying a new Revision

  • Rebuild code
go build -o server
  • Build new image
gcloud builds submit \
  --tag gcr.io/$GOOGLE_CLOUD_PROJECT/rest-api:0.2
gcloud run deploy rest-api \
  --image gcr.io/$GOOGLE_CLOUD_PROJECT/rest-api:0.2 \
  --platform managed \
  --region us-central1 \
  --allow-unauthenticated \
  --max-instances=2
  • akses browser

Penutup

Sahabat Blog Learning & Doing demikianlah penjelasan mengenai Developing a REST API with Go and Cloud Run. Semoga Bermanfaat . Sampai ketemu lagi di postingan berikut nya.

(Visited 82 times, 1 visits today)
Klik untuk berbagi dengan orang lain
Baca Juga :  Pengenalan dan Pengertian Google Kubernetes Engine (GKE)

Similar Posts