滴答清单官方并没有给出API的官方入口,但是从TickTick的API文档直接替换域名为dida365即可看到API文档;
官方文档,可以查找到对应的API调用方法: dida365 API doc
调用前需要创建Client ID和Client Secret;
调用过程:先获取 Code => Token => 然后读写操作
Manage Apps
截图是创建页面,填写Name
之后,最重要的就是OAuth redirect URL
需要添自己的重定向地址;
通过Gin写了一个简单的测试,可以根据需求做调整,贴上代码:
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"io"
"log"
"net/http"
"net/url"
"strings"
)
const (
clientID = "client_id"
clientSecret = "client_secret"
redirectURI = "http://127.0.0.1:8080/callback"
)
var token string
func main() {
r := gin.Default()
// 会跳转到授权许可
// https://dida365.com/oauth/authorize?scope=tasks:write tasks:read&client_id=client_id&response_type=code&redirect_uri=redirect_uri&state=state
r.GET("/", func(c *gin.Context) {
authURL := fmt.Sprintf("https://dida365.com/oauth/authorize?scope=tasks:write tasks:read&client_id=%s&redirect_uri=%s&response_type=code&state=state", clientID, redirectURI)
c.Redirect(http.StatusFound, authURL)
})
// 允许授权后,重定向到预留的重定向地址,附带需要获取的Code
// http://http://127.0.0.1:8080/callback?code=T8GOXx&state=state
r.GET("/callback", func(c *gin.Context) {
code := c.Query("code")
if code == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "code not found"})
return
}
data := url.Values{
"client_id": {clientID},
"client_secret": {clientSecret},
"redirect_uri": {redirectURI},
"grant_type": {"authorization_code"},
"scope": {"tasks:write tasks:read"},
"code": {code},
}
req, err := http.NewRequest("POST", "https://dida365.com/oauth/token", strings.NewReader(data.Encode()))
if err != nil {
log.Fatal(err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
var tokenResponse map[string]interface{}
if err := json.Unmarshal(body, &tokenResponse); err != nil {
log.Fatal(err)
}
accessToken, ok := tokenResponse["access_token"].(string)
if !ok {
log.Fatal("access_token not found in response")
}
token = accessToken
c.JSON(http.StatusOK, gin.H{"message": "Authorization successful", "token": token})
})
// http://127.0.0.1:8080/create-task 尝试创建一个任务
r.GET("/create-task", func(c *gin.Context) {
if token == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}
task := map[string]interface{}{
"title": "New Task",
"content": "This is the content of the task.",
"desc": "This is a new task.",
"dueDate": "2024-06-6",
// Add other required fields for the task creation
}
taskData, err := json.Marshal(task)
if err != nil {
log.Fatal(err)
}
client := &http.Client{}
req, err := http.NewRequest("POST", "https://api.dida365.com/open/v1/task", bytes.NewBuffer(taskData))
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
var createResponse map[string]interface{}
if err := json.Unmarshal(body, &createResponse); err != nil {
log.Fatal(err)
}
if resp.StatusCode != http.StatusOK || createResponse["errorCode"] != nil {
c.JSON(resp.StatusCode, gin.H{
"message": "Failed to create task",
"errorCode": createResponse["errorCode"],
"errorId": createResponse["errorId"],
"errorMsg": createResponse["errorMessage"],
"data": createResponse["data"],
})
return
}
c.JSON(http.StatusOK, gin.H{"message": "Task created successfully", "response": createResponse})
})
r.Run() // 在 127.0.0.1:8080 上监听
}
上面是通过gin创建的一个简单的测试流程,可以根据自己的需要修改;