用Go Encore加速API開發
Encore是什麼?
Encore是一個很潮的API框架,主要是用來開發微服務,他獨特的API開發方式,讓你可以更快速的開發API,一個API不用幾秒就可以有個原型,讓整體的開發流程可以更快速,也讓你可以更專注在API的邏輯上,再加上他的特色就是type-safe的撰寫風格,讓你可以更容易的debug,減少一些不必要的錯誤。
除此之外,他還提供管理部署階段的雲端平台,只要擁有一個帳號就可以部署你的服務到雲端,並支援AWS,GCP,讓你連結你的服務到雲端更加的方便。
目前支援的語言有Go和TypeScript,還在不斷的更新中,大家可以期待一下。
其實我是在做一個小專案的時候,發現了Encore,看他們Demo影片覺得好酷,就想試一下這個酷東西。
可以去官網看看他們的介紹,還有一些Demo影片,讓你更了解他們的特色。
雖然我才用Encore沒多久,只有用它開發一個小小的專案,但API開發常用的幾個功能都有用到,所以本篇主要會用我的使用經驗帶大家了解用Encore開發大概有甚麼地方要注意,還有一些我覺得Encore可以進步的地方。
重點整理
專案結構
1 | |── api/ |
Encore的專案結構大概長這樣,其中api是我們這個專案的名字,v1和v2是兩個不同的服務,裡面有各自的API邏輯和測試,整個架構一看就知道有哪些服務。
每個服務都可以再繼續增加子服務,比如說v1服務裡面還可以有user, post等等,只要在v1資料夾裡面再增加子服務名稱的資料夾就可以了,但是子服務無法定義API。這種結構充分運用到Go的package特性,也可以切分helper function到子資料夾,讓整個專案的結構更加清晰。
API Schema
Encore的API Schema是用來定義API傳入的格式還有輸出的格式,這些都用Go struct來定義,開發起來相對直觀,也保持了type-safe的特性
這是一個簡單的Hello World API
1 | type HelloParams struct { |
這裡定義了一個HelloParams和HelloResponse,分別是傳入的參數和輸出的格式,再來就是定義Hello這個API,這裡的註解是用來定義這個API的method和path,這樣Encore就可以知道這個API是什麼method和path了。
我覺得Encore這樣設計是可以解決團隊開發時候帶來的一些問題,比如說API的格式不一致,或是API的path不一致,這樣就可以在開發的時候就定義好,讓大家都可以遵守這個規範。如果自己開發的話可能就會覺得有點麻煩,但是這樣的好處是可以讓你的API更加的一致,也讓你的API更加的易於維護。
這些struct也可以取得http header的資訊,像這樣
1 | type HelloParams struct { |
這樣就可以取得User-Agent和Authorization的資訊了,給開發者很大的彈性。
可以去官網看看更多的API Schema的用法。
另外,跟大家分享我踩到小小的坑
1 | type GetParams struct { |
encore run之後會給你一個測試API的平台,如果你GET請求的API schema長這樣,測試平台上面預設的query string欄位會有Limit和Offset給你填入,但依照官方文件的說法
For GET, HEAD and DELETE requests, parameters are read from the query string by default. The query parameter name defaults to the snake-case encoded name of the corresponding struct field (e.g. BlogPost becomes blog_post).
query string的參數名稱是會變snake case的,所以Limit和Offset會變成limit和offset。我當初一直用dashboard測API結果都一樣,後來才發現這個問題。改成這樣就可以了
1 | type GetParams struct { |
資料庫使用
Encore有自己一套資料庫連線方式,我直接給大家一個範例
1 | var DB = sqldb.NewDatabase("api", sqldb.DatabaseConfig{ |
sqldb是Encore提供的資料庫連線包,用encore run執行NewDatabase那行之後,Encore就會知道你的migration資料在哪裡(在這個例子是./migration資料夾),並自動用Docker建立資料庫,想確認資料的話就執行encoer db shell <你專案的名字>,就可以進入資料庫的shell了。
剛剛提到Encore可以在一個專案定義很多服務,Encore預設是每個有用到資料庫的服務都是獨立的,他們會有自己的資料庫,不會互相污染資料,當然也可以在服務之間共享資料庫,取決於開發者。
我自己覺得Encore這樣query資料會不太好用,而且沒有內建query placeholder,沒把輸入欄位清乾淨的話可能會有SQL injection的問題,於是我就改用Gorm來操作資料庫,寫法是用Encore service把資料庫包起來,然後把會用到資料庫的API都放在Service裡面。
1 | //encore:service |
這裡需要import
"gorm.io/driver/postgres"
"gorm.io/gorm"
"encore.dev/storage/sqldb"這些package
這樣就可以用Gorm來操作資料庫了,寫法比較乾淨,也比較不會有SQL injection的問題,也可以用Gorm的一些特性,比如說Preload,Create,Update等等,讓資料庫操作更加的方便。
快取功能
Encore有內建的快取API,是用Redis來實作的,支援多種資料類型,像是string, int, floats還有struct,這些類型也可以以set或ordered-list的方式存進Redis,還蠻方便的。
這是一個簡單的快取API
1 | var Cluster = cache.NewCluster("api", cache.ClusterConfig{ |
Encore裡面的快取都是用KeySpace來定義,這樣可以把相同類型的快取放在一起,也可以用KeyPattern來定義快取的key。
這裡跟大家講個我在實作struct型態的快取遇到的bug,如果你有一個像這樣的keySpace
1 | type Person struct { |
不知道是Encore沒有把一個struct marshal成string的方式寫好還是甚麼原因,我把一個Person struct存到testKeySpace的時候再拿出來,Person裡面的Name和Age都變成了空值,我怎麼試都試不出來,最後只好放棄用struct存快取,改用string的方式存,這樣就沒有問題了。
解法:
1 | func SetTest(ctx context.Context, key string, value Person) error { |
結語
其實有Encore這個方便的框架真的可以讓API開發更加的快速,也讓API的開發更加的一致,也讓API的開發更加的專注在API的邏輯上,而不是一些不必要的事情上,Encore直接幫後端解決了部署的麻煩,也自帶CI/CD,這個框架這一兩年才出來,StackOverflow還沒有太多的人分享遇到的坑,所以我在寫這篇文章的時候也是希望可以幫助到一些人,也希望Encore越來越好。