欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go快速開發(fā)一個RESTful API服務

 更新時間:2022年06月21日 10:31:34   作者:萬俊峰Kevin  
這篇文章主要為大家介紹了Go快速開發(fā)一個RESTful API服務,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

何時使用單體 RESTful 服務

對于很多初創(chuàng)公司來說,業(yè)務的早期我們更應該關注于業(yè)務價值的交付,而單體服務具有架構簡單,部署簡單,開發(fā)成本低等優(yōu)點,可以幫助我們快速實現(xiàn)產品需求。我們在使用單體服務快速交付業(yè)務價值的同時,也需要為業(yè)務的發(fā)展預留可能性,所以我們一般會在單體服務中清晰的拆分不同的業(yè)務模塊。

商城單體 RESTful 服務

我們以商城為例來構建單體服務,商城服務一般來說相對復雜,會由多個模塊組成,比較重要的模塊包括賬號模塊、商品模塊和訂單模塊等,每個模塊會有自己獨立的業(yè)務邏輯,同時每個模塊間也會相互依賴,比如訂單模塊和商品模塊都會依賴賬號模塊,在單體應用中這種依賴關系一般是通過模塊間方法調用來完成。一般單體服務會共享存儲資源,比如 MySQL 和 Redis 等。

單體服務的整體架構比較簡單,這也是單體服務的優(yōu)點,客戶請求通過 DNS 解析后通過 Nginx 轉發(fā)到商城的后端服務,商城服務部署在 ECS 云主機上,為了實現(xiàn)更大的吞吐和高可用一般會部署多個副本,這樣一個簡單的平民架構如果優(yōu)化好的話也是可以承載較高的吞吐的。

商城服務內部多個模塊間存在依賴關系,比如請求訂單詳情接口 /order/detail,通過路由轉發(fā)到訂單模塊,訂單模塊會依賴賬號模塊和商品模塊組成完整的訂單詳情內容返回給用戶,在單體服務中多個模塊一般會共享數(shù)據(jù)庫和緩存。

單體服務實現(xiàn)

接下來介紹如何基于 go-zero 來快速實現(xiàn)商城單體服務。使用過 go-zero 的同學都知道,我們提供了一個 API 格式的文件來描述 Restful API,然后可以通過 goctl 一鍵生成對應的代碼,我們只需要在 logic 文件里填寫對應的業(yè)務邏輯即可。商城服務包含多個模塊,為了模塊間相互獨立,所以不同模塊由單獨的 API 定義,但是所有的 API 的定義都是在同一個 service (mall-api) 下。

在 api 目錄下分別創(chuàng)建 user.api, order.api, product.api 和 mall.api,其中 mall.api 為聚合的 api 文件,通過 import 導入,文件列表如下:

api
|-- mall.api
|-- order.api
|-- product.api
|-- user.api

Mall API 定義

mall.api 的定義如下,其中 syntax = “v1” 表示這是 zero-api 的 v1 語法

syntax = "v1"
import "user.api"
import "order.api"
import "product.api"

賬號模塊 API 定義

  • 查看用戶詳情
  • 獲取用戶所有訂單
syntax = "v1"
type (
    UserRequest {
        ID int64 `path:"id"`
    }
    UserReply {
        ID      int64   `json:"id"`
        Name    string  `json:"name"`
        Balance float64 `json:"balance"`
    }
    UserOrdersRequest {
        ID int64 `path:"id"`
    }
    UserOrdersReply {
        ID       string `json:"id"`
        State    uint32 `json:"state"`
        CreateAt string `json:"create_at"`
    }
)
service mall-api {
    @handler UserHandler
    get /user/:id (UserRequest) returns (UserReply)
    @handler UserOrdersHandler
    get /user/:id/orders (UserOrdersRequest) returns (UserOrdersReply)
}

訂單模塊 API 定義

  • 獲取訂單詳情
  • 生成訂單
syntax = "v1"
type (
    OrderRequest {
        ID string `path:"id"`
    }
    OrderReply {
        ID       string `json:"id"`
        State    uint32 `json:"state"`
        CreateAt string `json:"create_at"`
    }
    OrderCreateRequest {
        ProductID int64 `json:"product_id"`
    }
    OrderCreateReply {
        Code int `json:"code"`
    }
)
service mall-api {
    @handler OrderHandler
    get /order/:id (OrderRequest) returns (OrderReply)
    @handler OrderCreateHandler
    post /order/create (OrderCreateRequest) returns (OrderCreateReply)
}

商品模塊 API 定義

  • 查看商品詳情
syntax = "v1"
type ProductRequest {
    ID int64 `path:"id"`
}
type ProductReply {
    ID    int64   `json:"id"`
    Name  string  `json:"name"`
    Price float64 `json:"price"`
    Count int64   `json:"count"`
}
service mall-api {
    @handler ProductHandler
    get /product/:id (ProductRequest) returns (ProductReply)
}

生成單體服務

已經定義好了 API,接下來用 API 生成服務就會變得非常簡單,我們使用 goctl 生成單體服務代碼。

$ goctl api go -api api/mall.api -dir .

生成的代碼結構如下:

.
├── api
│   ├── mall.api
│   ├── order.api
│   ├── product.api
│   └── user.api
├── etc
│   └── mall-api.yaml
├── internal
│   ├── config
│   │   └── config.go
│   ├── handler
│   │   ├── ordercreatehandler.go
│   │   ├── orderhandler.go
│   │   ├── producthandler.go
│   │   ├── routes.go
│   │   ├── userhandler.go
│   │   └── userordershandler.go
│   ├── logic
│   │   ├── ordercreatelogic.go
│   │   ├── orderlogic.go
│   │   ├── productlogic.go
│   │   ├── userlogic.go
│   │   └── userorderslogic.go
│   ├── svc
│   │   └── servicecontext.go
│   └── types
│       └── types.go
└── mall.go

解釋一下生成的代碼結構:

  • api:存放 API 描述文件
  • etc:用來定義項目配置,所有的配置項都可以寫在 mall-api.yaml 中
  • internal/config:服務的配置定義
  • internal/handler:API 文件中定義的路由對應的 handler 的實現(xiàn)
  • internal/logic:用來放每個路由對應的業(yè)務邏輯,之所以區(qū)分 handler 和 logic 是為了讓業(yè)務處理部分盡可能減少依賴,把 HTTP requests 和邏輯處理代碼隔離開,便于后續(xù)拆分成 RPC service
  • internal/svc:用來定義業(yè)務邏輯處理的依賴,我們可以在 main 函數(shù)里面創(chuàng)建依賴的資源,然后通過 ServiceContext 傳遞給 handler 和 logic
  • internal/types:定義了 API 請求和返回數(shù)據(jù)結構
  • mall.go:main 函數(shù)所在文件,文件名和 API 定義中的 service 同名,去掉了后綴 -api

生成的服務不需要做任何修改就可以運行:

$ go run mall.go
Starting server at 0.0.0.0:8888...

實現(xiàn)業(yè)務邏輯

接下來我們來一起實現(xiàn)一下業(yè)務邏輯,出于演示目的邏輯會比較簡單,并非真正業(yè)務邏輯。

首先,我們先來實現(xiàn)用戶獲取所有訂單的邏輯,因為在用戶模塊并沒有訂單相關的信息,所以我們需要依賴訂單模塊查詢用戶的訂單,所以我們在 UserOrdersLogic 中添加對 OrderLogic 依賴

type UserOrdersLogic struct {
    logx.Logger
    ctx        context.Context
    svcCtx     *svc.ServiceContext
    orderLogic *OrderLogic
}
func NewUserOrdersLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserOrdersLogic {
    return &UserOrdersLogic{
        Logger:     logx.WithContext(ctx),
        ctx:        ctx,
        svcCtx:     svcCtx,
        orderLogic: NewOrderLogic(ctx, svcCtx),
    }
}

在 OrderLogic 中實現(xiàn)根據(jù) 用戶id 查詢所有訂單的方法

func (l *OrderLogic) ordersByUser(uid int64) ([]*types.OrderReply, error) {
    if uid == 123 {
        // It should actually be queried from database or cache
        return []*types.OrderReply{
            {
                ID:       "236802838635",
                State:    1,
                CreateAt: "2022-5-12 22:59:59",
            },
            {
                ID:       "236802838636",
                State:    1,
                CreateAt: "2022-5-10 20:59:59",
            },
        }, nil
    }
    return nil, nil
}

在 UserOrdersLogic 的 UserOrders 方法中調用 ordersByUser 方法

func (l *UserOrdersLogic) UserOrders(req *types.UserOrdersRequest) (*types.UserOrdersReply, error) {
    orders, err := l.orderLogic.ordersByUser(req.ID)
    if err != nil {
        return nil, err
    }
    return &types.UserOrdersReply{
        Orders: orders,
    }, nil
}

這時候我們重新啟動 mall-api 服務,在瀏覽器中請求獲取用戶所有訂單接口

http://localhost:8888/user/123/orders

返回結果如下,符合我們的預期

{
    "orders": [
        {
            "id": "236802838635",
            "state": 1,
            "create_at": "2022-5-12 22:59:59"
        },
        {
            "id": "236802838636",
            "state": 1,
            "create_at": "2022-5-10 20:59:59"
        }
    ]
}

接下來我們再來實現(xiàn)創(chuàng)建訂單的邏輯,創(chuàng)建訂單首先需要查看該商品的庫存是否足夠,所以在訂單模塊中需要依賴商品模塊。

type OrderCreateLogic struct {
    logx.Logger
    ctx    context.Context
    svcCtx *svc.ServiceContext
    productLogic *ProductLogic
}
func NewOrderCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *OrderCreateLogic {
    return &OrderCreateLogic{
        Logger:       logx.WithContext(ctx),
        ctx:          ctx,
        svcCtx:       svcCtx,
        productLogic: NewProductLogic(ctx, svcCtx),
    }
}

創(chuàng)建訂單的邏輯如下

const (
    success = 0
    failure = -1
)
func (l *OrderCreateLogic) OrderCreate(req *types.OrderCreateRequest) (*types.OrderCreateReply, error) {
    product, err := l.productLogic.productByID(req.ProductID)
    if err != nil {
        return nil, err
    }
    if product.Count > 0 {
        return &types.OrderCreateReply{Code: success}, nil
    }
    return &types.OrderCreateReply{Code: failure}, nil
}

依賴的商品模塊邏輯如下

func (l *ProductLogic) Product(req *types.ProductRequest) (*types.ProductReply, error) {
    return l.productByID(req.ID)
}
func (l *ProductLogic) productByID(id int64) (*types.ProductReply, error) {
    return &types.ProductReply{
        ID:    id,
        Name:  "apple watch 3",
        Price: 3333.33,
        Count: 99,
    }, nil
}

以上可以看出使用 go-zero 開發(fā)單體服務還是非常簡單的,有助于我們快速開發(fā)上線,同時我們還做了模塊的劃分,為以后做微服務的拆分也打下了基礎。

總結

通過以上的示例可以看出使用 go-zero 實現(xiàn)單體服務非常簡單,只需要定義 api 文件,然后通過 goctl 工具就能自動生成項目代碼,我們只需要在logic中填寫業(yè)務邏輯即可,這里只是為了演示如何基于 go-zero 快速開發(fā)單體服務并沒有涉及數(shù)據(jù)庫和緩存的操作,其實我們的 goctl 也可以一鍵生成 CRUD 代碼和 cache 代碼,對于開發(fā)單體服務來說可以起到事半功倍的效果。

并且針對不同的業(yè)務場景,定制化的需求也可以通過自定義模板來實現(xiàn),還可以在團隊內通過遠程 git 倉庫共享自定義業(yè)務模板,可以很好的實現(xiàn)團隊協(xié)同。

項目地址 github.com/zeromicro/g…

以上就是Go快速開發(fā)一個RESTful API服務的詳細內容,更多關于Go開發(fā)RESTful API服務的資料請關注腳本之家其它相關文章!

相關文章

  • Go定時器的三種實現(xiàn)方式示例詳解

    Go定時器的三種實現(xiàn)方式示例詳解

    這篇文章主要為大家介紹了Go定時器的三種實現(xiàn)方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • HTTP服務壓力測試工具及相關術語講解

    HTTP服務壓力測試工具及相關術語講解

    這篇文章主要為大家介紹了HTTP服務壓力測試工具使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-04-04
  • Go語言使用net/http實現(xiàn)簡單登錄驗證和文件上傳功能

    Go語言使用net/http實現(xiàn)簡單登錄驗證和文件上傳功能

    這篇文章主要介紹了Go語言使用net/http實現(xiàn)簡單登錄驗證和文件上傳功能,使用net/http模塊編寫了一個簡單的登錄驗證和文件上傳的功能,在此做個簡單記錄,需要的朋友可以參考下
    2023-07-07
  • Go語言中的Struct結構體

    Go語言中的Struct結構體

    這篇文章介紹了Go語言中的Struct結構體,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • Golang的第一個程序-Hello?World

    Golang的第一個程序-Hello?World

    這篇文章主要介紹了第一個Go程序-Hello?World,在編寫第一個go程序之前,我們要將系統(tǒng)的環(huán)境變量配好,下面來看具體的編一過程吧,需要的小伙伴可以參考一下
    2022-01-01
  • Golang之sync.Pool對象池對象重用機制總結

    Golang之sync.Pool對象池對象重用機制總結

    這篇文章主要對Golang的sync.Pool對象池對象重用機制做了一個總結,文中有相關的代碼示例和圖解,具有一定的參考價值,需要的朋友可以參考下
    2023-07-07
  • golang圖片處理庫image基本操作

    golang圖片處理庫image基本操作

    這篇文章主要介紹了golang圖片處理庫image簡介,主要包括圖片的基本讀取與保存及圖片的修改,本文通過通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-07-07
  • 完美解決golang go get私有倉庫的問題

    完美解決golang go get私有倉庫的問題

    這篇文章主要介紹了完美解決golang go get私有倉庫的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Go語言實現(xiàn)遍歷文件夾

    Go語言實現(xiàn)遍歷文件夾

    這篇文章主要為大家詳細介紹了Go語言實現(xiàn)遍歷文件夾的相關方法,文中的示例代碼講解詳細,具有一定的參考價值,感興趣的小伙伴可以了解一下
    2023-05-05
  • go語言中json數(shù)據(jù)的讀取和寫出操作

    go語言中json數(shù)據(jù)的讀取和寫出操作

    這篇文章主要介紹了go語言中json數(shù)據(jù)的讀取和寫出操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04

最新評論