這是一個使用 Go 語言實現的微服務,提供了文章列表查詢和編輯的功能。
- 鏈結串列(Linked List)結構:採用鏈結串列結構來管理文章列表,使資料操作更靈活,並為管理員提供完整的編輯功能,無須擔心傳統分頁帶來的額外負擔。
- gRPC 通訊:透過 gRPC 實現高效、低延遲的服務間通訊,確保資料傳輸快速且穩定。
- 輕量級容器化部署:利用 Docker 將應用容器化,打包後的 image 僅 90MB,減少資源消耗並加速部署流程。
專案想法參考了這篇文章
RESTful API: 允許使用者使用 key 擷取文章清單與個別文章資訊。 gRPC API : 提供管理員強大的編輯操作,包括建立、刪除、修改清單及其元素。 GUI : 編輯文章清單的友善使用者介面,與 gRPC API 相輔相成。
Go:主要程式語言。 PostgreSQL:資料庫,透過 GORM 函式庫進行操作。 Docker:用於容器化部署。 Fiber:高效能的網頁框架。 gRPC:用於服務間高效率、高效能的通訊。
服務部署在 fly.io 上,您可以直接訪問以下連結:
- RESTful API:
- gRPC API:
- GUI:
環境需求:
- Go 1.20
請參考 .env.example
以對 .env
進行設定。
執行以下指令以啟動所有服務:
docker-compose up -d
service | port |
---|---|
RESTful API | 3000 |
gRPC API | 50051 |
GUI | 8080 |
本專案包含使用 stretchr/testify 和 container/list 進行的全面測試。
RESTful API 讓使用者可以透過 key 獲取文章列表及每一篇文章的資訊
獲得文章列表中第一篇文章的 key。
Response:
{
"nextPageKey": "xxx"
}
獲得文章資訊及下一篇文章的 key。
Response:
{
"article": {
"title": "xxx",
"content": "xxx",
"slug": "xxx",
"published": true
},
"nextPageKey": "xxx"
}
gRPC API 提供管理員對列表進行編輯的功能。
- New: 建立一個新的列表
- Delete: 刪除一個列表
- Begin: 獲取第一個元素的 Iterator
- End: 獲取最後一個元素之後的 Iterator
- Clear: 清空列表
- Insert: 於該 Iterator 之前插入新的元素
- Erase: 移除該 Iterator
- Set: 設定該 Iterator 儲存的 Page ID
- PushBack: 列表尾部新增一個元素
- PopBack: 移除列表尾部的元素
- PushFront: 列表首部新增一個元素
- PopFront: 移除列表首部的元素
- Clone: 複製一個列表
TODO: 這部分可以使用 gRPC Bidirectional Streaming 進行優化,讓編輯操作的效率更高。
message Empty {
}
message PageList {
string key = 1;
}
message PageIterator {
string key = 1;
uint32 page_id = 2;
}
message DeleteRequest {
string list_key = 1;
}
message BeginRequest {
string list_key = 1;
}
message EndRequest {
string list_key = 1;
}
message NextRequest {
string iter_key = 1;
}
message PrevRequest {
string iter_key = 1;
}
message ClearRequest {
string list_key = 1;
}
message InsertRequest {
string iter_key = 1;
uint32 page_id = 2;
}
message EraseRequest {
string iter_key = 1;
}
message SetRequest {
string iter_key = 1;
uint32 page_id = 2;
}
message PushRequest {
string list_key = 1;
uint32 page_id = 2;
}
message PopRequest {
string list_key = 1;
}
message CloneRequest {
string list_key = 1;
}
建立一個新的列表。
rpc New(Empty) returns (PageList) {}
刪除一個列表。
rpc Delete(DeleteRequest) returns (Empty) {}
獲取第一個元素的 Iterator。
rpc Begin(BeginRequest) returns (PageIterator) {}
獲取最後一個元素之後的 Iterator。
rpc End(EndRequest) returns (PageIterator) {}
獲取下一個元素的 Iterator。
rpc Next(NextRequest) returns (PageIterator) {}
獲取上一個元素的 Iterator。
rpc Prev(PrevRequest) returns (PageIterator) {}
清空列表。
rpc Clear(ClearRequest) returns (Empty) {}
於該 Iterator 之前插入新的元素。
rpc Insert(InsertRequest) returns (PageIterator) {}
移除該 Iterator。
rpc Erase(EraseRequest) returns (PageIterator) {}
設定該 Iterator 儲存的 Page ID。
rpc Set(SetRequest) returns (PageIterator) {}
列表尾部新增一個元素。
rpc PushBack(PushRequest) returns (PageIterator) {}
移除列表尾部的元素。
rpc PopBack(PopRequest) returns (Empty) {}
列表首部新增一個元素。
rpc PushFront(PushRequest) returns (PageIterator) {}
移除列表首部的元素。
rpc PopFront(PopRequest) returns (Empty) {}
複製一個列表。
rpc Clone(CloneRequest) returns (PageList) {}