Created
July 30, 2025 05:44
-
-
Save Kuniwak/d7b60901faf1729b1eb4f2b891e25c32 to your computer and use it in GitHub Desktop.
Miro API Client Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "encoding/json" | |
| "fmt" | |
| "net/http" | |
| "os" | |
| "strconv" | |
| ) | |
| type ItemID string | |
| type Item struct { | |
| ID ItemID `json:"id"` | |
| Name string `json:"name"` | |
| Data map[string]interface{} `json:"data"` | |
| } | |
| type BoardID string | |
| type Board struct { | |
| ID BoardID `json:"id"` | |
| Name string `json:"name"` | |
| } | |
| type Client struct { | |
| accessToken string | |
| httpClient *http.Client | |
| } | |
| func (c *Client) GetBoards() ([]Board, error) { | |
| req, err := http.NewRequest("GET", "https://api.miro.com/v2/boards", nil) | |
| if err != nil { | |
| return nil, err | |
| } | |
| return DoJSONWithOffsetPagination[Board](c, 50, req) | |
| } | |
| func (c *Client) GetItems(boardID BoardID) ([]Item, error) { | |
| req, err := http.NewRequest("GET", "https://api.miro.com/v2/boards/"+string(boardID)+"/items", nil) | |
| if err != nil { | |
| return nil, err | |
| } | |
| return DoJSONWithCursorPagination[Item](c, 50, req) | |
| } | |
| func (c *Client) GetStickyNotes(boardID BoardID) ([]Item, error) { | |
| req, err := http.NewRequest("GET", "https://api.miro.com/v2/boards/"+string(boardID)+"/items", nil) | |
| if err != nil { | |
| return nil, err | |
| } | |
| q := req.URL.Query() | |
| q.Add("type", "sticky_note") | |
| req.URL.RawQuery = q.Encode() | |
| return DoJSONWithCursorPagination[Item](c, 50, req) | |
| } | |
| func DoJSON[T any](c *Client, req *http.Request) (int, T, error) { | |
| var v T | |
| req.Header.Set("Authorization", "Bearer "+c.accessToken) | |
| req.Header.Set("Content-Type", "application/json") | |
| req.Header.Set("Accept", "application/json") | |
| resp, err := c.httpClient.Do(req) | |
| if err != nil { | |
| return resp.StatusCode, v, err | |
| } | |
| defer resp.Body.Close() | |
| err = json.NewDecoder(resp.Body).Decode(&v) | |
| if err != nil { | |
| return resp.StatusCode, v, err | |
| } | |
| return resp.StatusCode, v, nil | |
| } | |
| type CursorPaginatedResponse[T any] struct { | |
| Data []T `json:"data"` | |
| Cursor string `json:"cursor,omitempty"` | |
| } | |
| func DoJSONWithCursorPagination[T any](c *Client, itemsPerPage int, req *http.Request) ([]T, error) { | |
| var items []T | |
| var cursor *string | |
| limit := itemsPerPage | |
| for { | |
| var req2 = *req | |
| q := req2.URL.Query() | |
| q.Set("limit", strconv.Itoa(limit)) | |
| if cursor != nil { | |
| q.Set("cursor", *cursor) | |
| } | |
| req2.URL.RawQuery = q.Encode() | |
| statusCode, items2, err := DoJSON[CursorPaginatedResponse[T]](c, &req2) | |
| if err != nil { | |
| return nil, err | |
| } | |
| items = append(items, items2.Data...) | |
| if statusCode != http.StatusOK { | |
| return nil, fmt.Errorf("status code: %d", statusCode) | |
| } | |
| if items2.Cursor == "" { | |
| return items, nil | |
| } | |
| cursor = &items2.Cursor | |
| } | |
| } | |
| type OffsetPaginatedResponse[T any] struct { | |
| Data []T `json:"data"` | |
| } | |
| func DoJSONWithOffsetPagination[T any](c *Client, itemsPerPage int, req *http.Request) ([]T, error) { | |
| var items []T | |
| limit := itemsPerPage | |
| for { | |
| var req2 = *req | |
| q := req2.URL.Query() | |
| q.Set("limit", strconv.Itoa(limit)) | |
| q.Set("offset", strconv.Itoa(len(items))) | |
| req2.URL.RawQuery = q.Encode() | |
| statusCode, items2, err := DoJSON[OffsetPaginatedResponse[T]](c, &req2) | |
| if err != nil { | |
| return nil, err | |
| } | |
| items = append(items, items2.Data...) | |
| if statusCode != http.StatusOK { | |
| return nil, fmt.Errorf("status code: %d", statusCode) | |
| } | |
| if len(items2.Data) < limit { | |
| return items, nil | |
| } | |
| } | |
| } | |
| func main() { | |
| accessToken := os.Getenv("MIRO_ACCESS_TOKEN") | |
| client := &Client{ | |
| accessToken: accessToken, | |
| httpClient: http.DefaultClient, | |
| } | |
| items, err := client.GetBoards() | |
| if err != nil { | |
| fmt.Println(err.Error()) | |
| } | |
| for _, item := range items { | |
| fmt.Printf("%s: %+v\n", item.ID, items) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment