現在就一隻一隻API在做,這邊就順便紀錄
今天處理的事Create Notion Database,這隻之前已經有講過了,但這次把內容修改了一下
先上API spec,會盡量照著這邊的內容來改code
/notion/createNotionDatabase/{pageId}:
post:
summary: Create a Notion database
parameters:
- name: pageId
in: path
required: true
description: ID of the Notion page to create the database under
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
type: array
items:
type: string
properties:
type: object
description: JSON object defining database properties
responses:
'201':
description: Notion database created successfully
'400':
description: Invalid input
首先是secret,之前取得secret的方法是這樣
controller/notion.go
func (c *Controller) CreateNotionDatabase(ctx *gin.Context) {
viper.AddConfigPath("./config") // config所在的目錄路徑
viper.SetConfigName("secret")
err := viper.ReadInConfig()
if err != nil {
log.Fatalln(err)
}
auth := viper.Get("Authorization")
}
因為這個function會很多地方都用到,所以寫成一個common的function
util/configHandler.go
package util
import (
"github.com/spf13/viper"
)
type ConfigHandler struct {
}
func NewConfigHandler() *ConfigHandler {
return &ConfigHandler{}
}
func (c *ConfigHandler) GetSecretConfig() *viper.Viper {
viper.AddConfigPath("./config") // config所在的目錄路徑
viper.SetConfigName("secret")
err := viper.ReadInConfig()
if err != nil {
panic(err)
}
return viper.GetViper()
}
這樣寫的話只要在code中new一個新的物件就可以取得secret了,所以原本的code會改成
controller/notion.go
func (c *Controller) CreateNotionDatabase(ctx *gin.Context) {
// Get Authorization from config
configHandler := util.NewConfigHandler()
auth := configHandler.GetSecretConfig().Get("Authorization")
...
}
接著要處理這隻api的request,這邊的request照上面的內容來看的話,在path的地方會需要一個pageId,在body的地方會需要title(array)跟properties(json)
這邊就需要創建一個model,來存這兩個body的資訊
model/requestModel/notionRequest.go
package requestModel
type NotionCreateDatabaseRequest struct {
Title []map[string]interface{} `json:"title"`
Properties map[string]interface{} `json:"properties"`
}
用這樣的結構就可以傳入這兩個參數到api中了
接著要來設定swagger的內容
controller/notion.go
// CreateNotionDatabase godoc
//
// @Summary Create a new Notion Database
// @Description Creates a database as a subpage in the specified parent page, with the specified properties schema. Currently, the parent of a new database must be a Notion page or a wiki database.
// @Tags notion
// @Accept json
// @Produce json
// @Param pageId path string true "Page ID"
// @Param request body requestModel.NotionCreateDatabaseRequest true "Request Body"
// @Success 200 {array} responseModel.NotionCreateDatabaseResponse
// @Failure 400 {string} string "Invalid input"
// @Router /api/v1/notion/createDatabase/{pageId} [post]
func (c *Controller) CreateNotionDatabase(ctx *gin.Context) {
...
這邊主要有加上幾個東西,Param試用來設定要傳入的參數,這邊來解釋一些內容
另外一個則是傳入的資料型態為requestModel.NotionCreateDatabaseRequest
,param的型態為body
還有一個改變的部分就是Router的部分,這邊最後面加上/{pageId}
,就是要讓這個參數傳進來
接下來來改一下main.go裡面的router
main.go
func main() {
r := gin.Default()
c := controller.NewController()
v1 := r.Group("/api/v1")
{
notion := v1.Group("/notion")
{
notion.POST("/createDatabase/:pageId", c.CreateNotionDatabase)
}
}
...
}
這邊最後面加上/:pageId
,就會接到這個參數了
接著才要講Controller的內容,code的部分一點一點上
func (c *Controller) CreateNotionDatabase(ctx *gin.Context) {
// Get Authorization from config
configHandler := util.NewConfigHandler()
auth := configHandler.GetSecretConfig().Get("Authorization")
pageId := ctx.Param("pageId")
// Bind the request body to struct
var requests requestModel.NotionCreateDatabaseRequest
if err := ctx.ShouldBindJSON(&requests); err != nil {
ctx.JSON(400, gin.H{"error": err.Error()})
return
}
...
}
上面接到secret後,下面這邊是要處理傳入的參數
用ctx.Param("pageId")
可以取得pageId
然後用ShouldBindJSON(&requests)
可以把body的內容傳進去requests中,並且這邊順便做一個error handling
接著裡面的兩塊內容(title, properties)要轉成json
func (c *Controller) CreateNotionDatabase(ctx *gin.Context) {
...
// Marshal the struct to json
titleJson, err := json.Marshal(requests.Title)
if err != nil {
log.Fatalln(err)
}
propertiesJson, err := json.Marshal(requests.Properties)
if err != nil {
log.Fatalln(err)
}
...
}
再來要小改一下之前的body內容,把這兩個json傳入
func (c *Controller) CreateNotionDatabase(ctx *gin.Context) {
...
// Send the request to Notion API
client := handler.NewClient()
header := map[string]string{
"Authorization": auth.(string),
"Notion-Version": "2022-06-28",
"Content-Type": "application/json",
}
bodyString := `{
"is_inline": true,
"parent": {
"type": "page_id",
"page_id": "` + pageId + `"
},
"title": ` + string(titleJson) + `,
"properties": ` + string(propertiesJson) + `
}`
body := []byte(bodyString)
...
}
所以把現在body的內容刪減到只剩is_inline、parent、title、properties這幾個內容
剩下的地方就是把接response的地方改一下就好了
這邊上一下完整的code
// CreateNotionDatabase godoc
//
// @Summary Create a new Notion Database
// @Description Creates a database as a subpage in the specified parent page, with the specified properties schema. Currently, the parent of a new database must be a Notion page or a wiki database.
// @Tags notion
// @Accept json
// @Produce json
// @Param pageId path string true "Page ID"
// @Param request body requestModel.NotionCreateDatabaseRequest true "Request Body"
// @Success 200 {array} responseModel.NotionCreateDatabaseResponse
// @Failure 400 {string} string "Invalid input"
// @Router /api/v1/notion/createDatabase/{pageId} [post]
func (c *Controller) CreateNotionDatabase(ctx *gin.Context) {
// Get Authorization from config
configHandler := util.NewConfigHandler()
auth := configHandler.GetSecretConfig().Get("Authorization")
pageId := ctx.Param("pageId")
// Bind the request body to struct
var requests requestModel.NotionCreateDatabaseRequest
if err := ctx.ShouldBindJSON(&requests); err != nil {
ctx.JSON(400, gin.H{"error": err.Error()})
return
}
// Marshal the struct to json
titleJson, err := json.Marshal(requests.Title)
if err != nil {
log.Fatalln(err)
}
propertiesJson, err := json.Marshal(requests.Properties)
if err != nil {
log.Fatalln(err)
}
// Send the request to Notion API
client := handler.NewClient()
header := map[string]string{
"Authorization": auth.(string),
"Notion-Version": "2022-06-28",
"Content-Type": "application/json",
}
bodyString := `{
"is_inline": true,
"parent": {
"type": "page_id",
"page_id": "` + pageId + `"
},
"title": ` + string(titleJson) + `,
"properties": ` + string(propertiesJson) + `
}`
body := []byte(bodyString)
response, err := client.Post("https://api.notion.com/v1/databases", header, body)
if err != nil {
log.Fatalln(err)
}
defer response.Body.Close()
// Change the response body to []byte type
responseBody, err := io.ReadAll(response.Body)
if err != nil {
log.Fatalln(err)
}
bodyStr := string(responseBody)
var data []byte = []byte(bodyStr)
// Unmarshal the response body to struct
var responseCreateNotionDatabase responseModel.NotionCreateDatabaseResponse
json.Unmarshal(data, &responseCreateNotionDatabase)
ctx.JSON(http.StatusOK, responseCreateNotionDatabase)
}
其實不用動太多,只要改一下資料結構就好了
model/responseModel/notionResponse.go
package responseModel
type NotionCreateDatabaseResponse struct {
Object string `json:"object"`
ID string `json:"id"`
CreatedTime string `json:"created_time"`
LastEditedTime string `json:"last_edited_time"`
URL string `json:"url"`
Title []map[string]interface{} `json:"title"`
Properties map[string]interface{} `json:"properties"`
Parent struct {
Type string `json:"type"`
PageID string `json:"page_id"`
} `json:"parent"`
Archived bool `json:"archived"`
IsInline bool `json:"is_inline"`
}
這隻之前叫做model/notion.go,因為這邊是要處理response的內容所以就換了一個資料夾
將這些內容改好後,用bash update-swagger.sh
更新一下swagger的內容
swagger的畫面現在會長這樣
PageId在Day 7的時候有講過,可以去那邊看
在來給一下這邊Request Body的內容
{
"properties":{
"Title":{
"id":"title",
"name":"Title",
"type":"title",
"title":{
}
},
"Date":{
"id":"date",
"name":"DateTime",
"type":"date",
"date":{
}
}
},
"title":[
{
"type":"text",
"text":{
"content":"Google Calendar Sync",
"link":null
}
}
]
}
昨天有講到這個db現在只需要兩個欄位,一個叫Title,另一個叫做DateTime
將這些資訊都打上之後,執行後會在Notion上面看到這樣
然後這邊是Response接回來的內容
{
"object": "database",
"id": "",
"created_time": "2023-10-07T14:49:00.000Z",
"last_edited_time": "2023-10-07T14:49:00.000Z",
"url": "",
"title": [
{
"annotations": {
"bold": false,
"code": false,
"color": "default",
"italic": false,
"strikethrough": false,
"underline": false
},
"href": null,
"plain_text": "Google Calendar Sync",
"text": {
"content": "Google Calendar Sync",
"link": null
},
"type": "text"
}
],
"properties": {
"Date": {
"date": {},
"id": "s%7D%5CP",
"name": "Date",
"type": "date"
},
"Title": {
"id": "title",
"name": "Title",
"title": {},
"type": "title"
}
},
"parent": {
"type": "page_id",
"page_id": ""
},
"archived": false,
"is_inline": true
}
明天再繼續用下一隻API