- vừa được xem lúc

Viết ứng dụng Microservice với Golang

0 0 89

Người đăng: Cihan Özhan - Dịch 2kvn

Xây dựng ứng dụng Microservice với Go

Các công nghệ chúng tôi sử dụng trong dự án này là:

  • Go
  • Goji : Một bộ ghép kênh yêu cầu tối giản và linh hoạt cho Go
  • MongoDB : Robo 3T có sẵn dưới dạng IDE
  • Postman : Công cụ kiểm tra API

Mục đích của bài viết này;

  • Phát triển các ứng dụng microservice với Go
  • Học Goji với Go
  • Hiểu cách sử dụng MongoDB với Go

Sự chuẩn bị;

  • Bắt đầu dịch vụ MongoDB

Hãy bắt đầu!

Đầu tiên, chúng ta chuẩn bị model;

models / Page.go

package models

type Page struct {
  Title string
  Author string
  Header string
  PageDefinition string
  Content string
  URI string
}

models / Book.go

package models

type Book struct {
  ISBN string `json:"isbn"`
  Title string `json:"title"`
  Authors []string `json:"authors"`
  Price string `json:"price"`
}

Tiếp theo, chúng tôi đang chuẩn bị layer chung;

common / JsonProcesses.go

package common

import (
	"fmt"
	"net/http"
)

func ErrorWithJSON(w http.ResponseWriter, message string, code int) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(code)
	fmt.Fprintf(w, "{message: %q}", message)
}

func ResponseWithJSON(w http.ResponseWriter, json []byte, code int) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(code)
	w.Write(json)
}
Bây giờ, chúng ta đang chuẩn bị lớp dữ liệu để thực hiện các hoạt động trên csdl;

data/PageData.go

package data

import (
	comm "common"
	"encoding/json"
	"goji.io/pat"
	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"log"
	m "models"
	"net/http"
) // Bring all pages.

func AllPages(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		session := s.Copy() // Create a copy of the session.
		// End the session when the process is complete.
		defer session.Close()
		c := session.DB("store").C("pages")
		var pages []m.Page
		// MongoDB query : Bring all pages.
		err := c.Find(bson.M{}).All(&pages)
		if err != nil {
			comm.ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
			log.Println("Failed get all pages: ", err)
			return
		}
		respBody, err := json.MarshalIndent(pages, "", " ") // Format the data.
		if err != nil {
			log.Fatal(err)
		}
		comm.ResponseWithJSON(w, respBody, http.StatusOK)
	}
}

func AddPage(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		session := s.Copy()
		defer session.Close()
		var page m.Page
		decoder := json.NewDecoder(r.Body)
		err := decoder.Decode(&page)
		if err != nil {
			comm.ErrorWithJSON(w, "Incorrect body", http.StatusBadRequest)
			return
		}
		c := session.DB("store").C("pages")
		err = c.Insert(page) // MongoDB query : Add data.
		if err != nil {
			if mgo.IsDup(err) { // Is there a duplicate error? (IsDup)
				comm.ErrorWithJSON(w, "This page already exists", http.StatusBadRequest)
				return
			}
			// For any error...
			comm.ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
			log.Println("Failed insert page: ", err)
			return
		}
		// The output out this process will be JSON.
		w.Header().Set("Content-Type", "application/json")
		w.Header().Set("Location", r.URL.Path+"/"+page.Title)
		// Write header : "Created" status message.
		w.WriteHeader(http.StatusCreated)
	}
}

func PageByID(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		session := s.Copy()
		defer session.Close()
		title := pat.Param(r, "title")
		c := session.DB("store").C("pages")
		var page m.Page
		err := c.Find(bson.M{"title": title}).One(&page)
		if err != nil {
			comm.ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
			log.Println("Failed find page: ", err)
			return
		}
		if page.Title == "" {
			comm.ErrorWithJSON(w, "Page not found", http.StatusNotFound)
			return
		}
		respBody, err := json.MarshalIndent(page, "", " ")
		if err != nil {
			log.Fatal(err)
		}
		comm.ResponseWithJSON(w, respBody, http.StatusOK)
	}
}

func UpdatePage(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		session := s.Copy()
		defer session.Close()
		title := pat.Param(r, "title")
		var page m.Page
		decoder := json.NewDecoder(r.Body)
		err := decoder.Decode(&page)
		if err != nil {
			comm.ErrorWithJSON(w, "Incorrect body", http.StatusBadRequest)
			return
		}
		c := session.DB("store").C("pages")
		err = c.Update(bson.M{"title": title}, &page)
		if err != nil {
			switch err {
			default:
				comm.ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
				log.Println("Failed update page: ", err)
				return
			case mgo.ErrNotFound:
				comm.ErrorWithJSON(w, "Page not found", http.StatusNotFound)
				return
			}
		}
		w.WriteHeader(http.StatusNoContent)
	}
}

func DeletePage(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		session := s.Copy()
		defer session.Close()
		title := pat.Param(r, "title") // Will be deleted with "title" data(So not with ID).
		c := session.DB("store").C("pages")
		err := c.Remove(bson.M{"title": title})
		if err != nil {
			switch err {
			default:
				comm.ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
				log.Println("Failed delete page: ", err)
				return
			case mgo.ErrNotFound:
				comm.ErrorWithJSON(w, "Page not found", http.StatusNotFound)
				return
			}
		}
		w.WriteHeader(http.StatusNoContent)
	}
}

data/BookData.go

package data

import (
	"encoding/json"
	"log"
	"net/http"

	"goji.io/pat"
	mgo "gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"

	comm "common"
	m "models"
)

func AllBooks(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		session := s.Copy()
		defer session.Close()
		c := session.DB("store").C("books")
		var books []m.Book
		err := c.Find(bson.M{}).All(&books)
		if err != nil {
			comm.ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
			log.Println("Failed get all books: ", err)
			return
		}
		respBody, err := json.MarshalIndent(books, "", " ")
		if err != nil {
			log.Fatal(err)
		}
		comm.ResponseWithJSON(w, respBody, http.StatusOK)
	}
}

func AddBook(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		session := s.Copy()
		defer session.Close()
		var book m.Book
		decoder := json.NewDecoder(r.Body)
		err := decoder.Decode(&book)
		if err != nil {
			comm.ErrorWithJSON(w, "Incorrect body", http.StatusBadRequest)
			return
		}
		c := session.DB("store").C("books")

		err = c.Insert(book)
		if err != nil {
			if mgo.IsDup(err) {
				comm.ErrorWithJSON(w, "Book with this ISBN already exists", http.StatusBadRequest)
				return
			}
			comm.ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
			log.Println("Failed insert book: ", err)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.Header().Set("Location", r.URL.Path+"/"+book.ISBN)
		w.WriteHeader(http.StatusCreated)
	}
}

func BookByISBN(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		session := s.Copy()
		defer session.Close()
		isbn := pat.Param(r, "isbn")
		c := session.DB("store").C("books")
		var book m.Book
		err := c.Find(bson.M{"isbn": isbn}).One(&book)
		if err != nil {
			comm.ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
			log.Println("Failed find book: ", err)
			return
		}
		if book.ISBN == "" {
			comm.ErrorWithJSON(w, "Book not found", http.StatusNotFound)
			return
		}
		respBody, err := json.MarshalIndent(book, "", " ")
		if err != nil {
			log.Fatal(err)
		}
		comm.ResponseWithJSON(w, respBody, http.StatusOK)
	}
}

func UpdateBook(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		session := s.Copy()
		defer session.Close()
		isbn := pat.Param(r, "isbn")
		var book m.Book
		decoder := json.NewDecoder(r.Body)
		err := decoder.Decode(&book)
		if err != nil {
			comm.ErrorWithJSON(w, "Incorrect body", http.StatusBadRequest)
			return
		}
		c := session.DB("store").C("books")
		err = c.Update(bson.M{"isbn": isbn}, &book)
		if err != nil {
			switch err {
			default:
				comm.ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
				log.Println("Failed update book: ", err)
				return
			case mgo.ErrNotFound:
				comm.ErrorWithJSON(w, "Book not found", http.StatusNotFound)
				return
			}
		}
		w.WriteHeader(http.StatusNoContent)
	}
}

func DeleteBook(s *mgo.Session) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		session := s.Copy()
		defer session.Close()
		isbn := pat.Param(r, "isbn")
		c := session.DB("store").C("books")
		err := c.Remove(bson.M{"isbn": isbn})
		if err != nil {
			switch err {
			default:
				comm.ErrorWithJSON(w, "Database error", http.StatusInternalServerError)
				log.Println("Failed delete book: ", err)
				return
			case mgo.ErrNotFound:
				comm.ErrorWithJSON(w, "Book not found", http.StatusNotFound)
				return
			}
		}
		w.WriteHeader(http.StatusNoContent)
	}
}
And we complete the project…

main.go

package main

import (
"net/http"

"goji.io"
"goji.io/pat"
"gopkg.in/mgo.v2"
"data"
)

func main() {

	session, err := mgo.Dial("localhost")
	if err != nil {
		panic(err)
	}
	defer session.Close()

	session.SetMode(mgo.Monotonic, true)

	mux := goji.NewMux()

	// Page API
	mux.HandleFunc(pat.Get("/pages"), data.AllPages(session))
	mux.HandleFunc(pat.Post("/pages"), data.AddPage(session))
	mux.HandleFunc(pat.Get("/pages/:title"), data.PageByID(session))
	mux.HandleFunc(pat.Put("/pages/:title"), data.UpdatePage(session))
	mux.HandleFunc(pat.Delete("/pages/:title"), data.DeletePage(session))

	// Book API
	mux.HandleFunc(pat.Get("/books"), data.AllBooks(session))
	mux.HandleFunc(pat.Post("/books"), data.AddBook(session))
	mux.HandleFunc(pat.Get("/books/:isbn"),dt.BookByISBN(session))
	mux.HandleFunc(pat.Put("/books/:isbn"), data.UpdateBook(session))
	mux.HandleFunc(pat.Delete("/books/:isbn"), data.DeleteBook(session))

	http.ListenAndServe("localhost:8080", mux)
}

Tiếp theo chúng ta sẽ hoàn thành project...

main.go

package main

import (
	"net/http"
	"data"
	"goji.io/pat"
)

func main() {

	session, err := mgo.Dial("localhost")
	if err != nil {
		panic(err)
	}
	defer session.Close()

	session.SetMode(mgo.Monotonic, true)

	mux := goji.NewMux()

	// Page API
	mux.HandleFunc(pat.Get("/pages"), data.AllPages(session))
	mux.HandleFunc(pat.Post("/pages"), data.AddPage(session))
	mux.HandleFunc(pat.Get("/pages/:title"), data.PageByID(session))
	mux.HandleFunc(pat.Put("/pages/:title"), data.UpdatePage(session))
	mux.HandleFunc(pat.Delete("/pages/:title"), data.DeletePage(session))

	// Book API
	mux.HandleFunc(pat.Get("/books"), data.AllBooks(session))
	mux.HandleFunc(pat.Post("/books"), data.AddBook(session))
	mux.HandleFunc(pat.Get("/books/:isbn"), dt.BookByISBN(session))
	mux.HandleFunc(pat.Put("/books/:isbn"), data.UpdateBook(session))
	mux.HandleFunc(pat.Delete("/books/:isbn"), data.DeleteBook(session))

	http.ListenAndServe("localhost:8080", mux)
}

Hiện tại chúng ta có thể chạy thử ứng dụng:

go run main.go
Hiện không có bộ sưu tập nào có sẵn trong cơ sở dữ liệu.

Thực hiện các thao tác sau:

  • Create a new ‘page’ data
  • Get and AllPages
  • Put and Update
  • and Delete

Dummy Data:

{
 "Title": "Trainings",
 "Author": "Cihan Özhan",
 "Header": "CihanOzhan.Com - Trainings",
 "PageDefinition": "Kişisel blog sitemdeki eğitimlerimi listelediğim sayfadır.",
 "Content": "I have been researching, training and consulting on software for a long time. I share some of these researches as video training.",
 "URI": "http://www.cihanozhan.com/trainings"
}

Các truy vấn mẫu để lọc:

chúc may mắn!
Cihan Ozhan

Bình luận

Bài viết tương tự

- vừa được xem lúc

gRPC - Nó là gì và có nên sử dụng hay không?

Nhân một ngày rảnh rỗi, mình ngồi đọc lại RPC cũng như gRPC viết lại để nhớ lâu hơn. Vấn đề là gì và tại sao cần nó .

0 0 112

- vừa được xem lúc

Embedded Template in Go

Getting Start. Part of developing a web application usually revolves around working with HTML as user interface.

0 0 40

- vừa được xem lúc

Tạo Resful API đơn giản với Echo framework và MySQL

1. Giới thiệu.

0 0 44

- vừa được xem lúc

Sử dụng goquery trong golang để crawler thông tin các website Việt Nam bị deface trên mirror-h.org

. Trong bài viết này, mình sẽ cùng mọi người khám phá một package thu thập dữ liệu có tên là goquery của golang. Mục tiêu chính của chương trình crawler này sẽ là lấy thông tin các website Việt Nam bị deface (là tấn công, phá hoại website, làm thay đổi giao diện hiển thị của một trang web, khi người

0 0 218

- vừa được xem lúc

Tạo ứng dụng craw dữ liệu bing với Golang, Mysql driver

Chào mọi người . Lâu lâu ta lại gặp nhau 1 lần, để tiếp tục series chia sẻ kiến thức về tech, hôm nay mình sẽ tìm hiểu và chia sẻ về 1 ngôn ngữ đang khá hot trong cộng đồng IT đó là Golang.

0 0 59

- vừa được xem lúc

Golang: Rest api and routing using MUX

Routing with MUX. Let's create a simple CRUD api for a blog site. # All . GET articles/ .

0 0 39