Trello API wrapper for Go

Go Trello API

Trello Logo

GoDoc Build Status Coverage Status

A #golang package to access the Trello API. Nearly 100% of the read-only surface area of the API is covered, as is creation and modification of Cards. Low-level infrastructure for features to modify Lists and Boards are easy to add... just not done yet.

Pull requests are welcome for missing features.

My current development focus is documentation, especially enhancing this README.md with more example use cases.

Installation

The Go Trello API has been Tested compatible with Go 1.7 on up. Its only dependency is the github.com/pkg/errors package. It otherwise relies only on the Go standard library.

go get github.com/adlio/trello

Basic Usage

All interaction starts with a trello.Client. Create one with your appKey and token:

client := trello.NewClient(appKey, token)

All API requests accept a trello.Arguments object. This object is a simple map[string]string, converted to query string arguments in the API call. Trello has sane defaults on API calls. We have a trello.Defaults() utility function which can be used when you desire the default Trello arguments. Internally, trello.Defaults() is an empty map, which translates to an empty query string.

board, err := client.GetBoard("bOaRdID", trello.Defaults())
if err != nil {
  // Handle error
}

Client Longevity

When getting Lists from Boards or Cards from Lists, the original trello.Client pointer is carried along in returned child objects. It's important to realize that this enables you to make additional API calls via functions invoked on the objects you receive:

client := trello.NewClient(appKey, token)
board, err := client.GetBoard("ID", trello.Defaults())

// GetLists makes an API call to /boards/:id/lists using credentials from `client`
lists, err := board.GetLists(trello.Defaults())

for _, list := range lists {
  // GetCards makes an API call to /lists/:id/cards using credentials from `client`
  cards, err := list.GetCards(trello.Defaults())
}

Get Trello Boards for a User

Boards can be retrieved directly by their ID (see example above), or by asking for all boards for a member:

member, err := client.GetMember("usernameOrId", trello.Defaults())
if err != nil {
  // Handle error
}

boards, err := member.GetBoards(trello.Defaults())
if err != nil {
  // Handle error
}

Get Trello Lists on a Board

board, err := client.GetBoard("bOaRdID", trello.Defaults())
if err != nil {
  // Handle error
}

lists, err := board.GetLists(trello.Defaults())
if err != nil {
  // Handle error
}

Get Trello Cards on a Board

board, err := client.GetBoard("bOaRdID", trello.Defaults())
if err != nil {
  // Handle error
}

cards, err := board.GetCards(trello.Defaults())
if err != nil {
  // Handle error
}

Get Trello Cards on a List

list, err := client.GetList("lIsTID", trello.Defaults())
if err != nil {
  // Handle error
}

cards, err := list.GetCards(trello.Defaults())
if err != nil {
  // Handle error
}

Creating and deleting a Board

A board can be created or deleted on the Board struct for the user whose credentials are being used.

  board := trello.NewBoard("My bucket list")

  // POST
  err := client.CreateBoard(&board, trello.Defaults())

  // DELETE
  err := board.Delete(trello.Defaults())
  if err != nil {
    fmt.Println(err)
  }
}

Adding a new Member to the Board

  board, err := client.GetBoard("bOaRdID", trello.Defaults())
  if err != nil {
    // Handle error
  }

  member := Member{Email: "[email protected]"}
  _, err := board.AddMember(&member, trello.Defaults()) 

  if err != nil {
    // Handle error
  }

Archiving, Unarchiving & Deleting a Card

// archive
err := card.Archive()

// unarchive
err := card.Unarchive()

// delete
err := card.Delete()

Creating a Card

The API provides several mechanisms for creating new cards.

Creating Cards from Scratch on the Client

This approach requires the most input data on the card:

card := trello.Card{
  Name: "Card Name",
  Desc: "Card description",
  Pos: 12345.678,
  IDList: "iDOfaLiSt",
  IDLabels: []string{"labelID1", "labelID2"},
}
err := client.CreateCard(card, trello.Defaults())

Creating Cards On a List

list, err := client.GetList("lIsTID", trello.Defaults())
list.AddCard(&trello.Card{ Name: "Card Name", Desc: "Card description" }, trello.Defaults())

Creating a Card by Copying Another Card

err := card.CopyToList("listIdNUmber", trello.Defaults())

Get Actions on a Board

board, err := client.GetBoard("bOaRdID", trello.Defaults())
if err != nil {
  // Handle error
}

actions, err := board.GetActions(trello.Defaults())
if err != nil {
  // Handle error
}

Get Actions on a Card

card, err := client.GetCard("cArDID", trello.Defaults())
if err != nil {
  // Handle error
}

actions, err := card.GetActions(trello.Defaults())
if err != nil {
  // Handle error
}

Rearrange Cards Within a List

err := card.MoveToTopOfList()
err = card.MoveToBottomOfList()
err = card.SetPos(12345.6789)

Moving a Card to Another List

err := card.MoveToList("listIdNUmber", trello.Defaults())

Card Ancestry

Trello provides ancestry tracking when cards are created as copies of other cards. This package provides functions for working with this data:

// ancestors will hold a slice of *trello.Cards, with the first
// being the card's parent, and the last being parent's parent's parent...
ancestors, err := card.GetAncestorCards(trello.Defaults())

// GetOriginatingCard() is an alias for the last element in the slice
// of ancestor cards.
ultimateParentCard, err := card.GetOriginatingCard(trello.Defaults())

Debug Logging

If you'd like to see all API calls logged, you can attach a .Logger (implementing Debugf(string, ...interface{})) to your client. The interface for the logger mimics logrus. Example usage:

logger := logrus.New()
logger.SetLevel(logrus.DebugLevel)
client := trello.NewClient(appKey, token)
client.Logger = logger
Owner
Aaron Longwell
Independent software consultant based in Portland, OR. Former CTO, @culturefoundry.
Aaron Longwell
Comments
  • Client does not get cleaned up properly

    Client does not get cleaned up properly

    Hi there,

    I have built an application using this library - it works really well, so thanks for creating it! I have a background goroutine that tries to sync some data between Trello and another service every couple of minutes. In my loop, I create a new trello.Client via NewClient and noticed that over time, my CPU usage becomes really high. I think it might be related to the throttling built into the library, because time.Tick does not get cleaned up properly (apparently you're supposed to use time.NewTicker and stop it, ref). I'm not 100% sure that this is the exact cause, but if I do not create a trello client in my loop, the CPU usage stays the same over time.

    I'm not sure if there is some sort of best practice on how to resolve this so I wanted to open an issue first - maybe there can be an option to disable the throttling or expose the ticker so that I can stop it myself when I know I won't need the Client anymore? Happy to help out with the solution.

    Cheers and thanks again for the library!

    Example code (might not work, I removed some parts of my application)

    
    		for {
    			time.Sleep(5 * time.Minute)
    
    			for _, user := range s.Users {
    				trelloClient := trello.NewClient(user.TrelloAppKey, user.TrelloToken)
    
    				// ... do things with the client
    			}
    		}
    
  • Support for adding URL Attachments to a card

    Support for adding URL Attachments to a card

    I find your library really useful, but seems to lack API calls to add attachments onto cards.

    This PR covers my use case, which is to link Trello cards with GitHub issues via the GitHub Power-up: https://trello.com/power-ups/55a5d916446f517774210004/github

  • Allow getting a new client with a context.Context

    Allow getting a new client with a context.Context

    Context is great to allow for cancellation of requests.

    With this change it will be possible to get a new client which will set a different context for all its requests.

    This solution is backwards-compatible. However, since this package always embeds itself to provide methods like *Board.GetLists(). The current solution could lead to memory leaks or using old contexts if the user is holding the responses in memory.

  • Add functions to archive & unarchive a card

    Add functions to archive & unarchive a card

    This PR adds shorthands for archiving and unarchiving a card.

    Even though both actions can be done using the existing Update method, having explicit methods for these actions would increase the ease of use IMHO.

    Also, it was one of the items in TODO.txt

  • Golint 2

    Golint 2

    This PR replaces https://github.com/adlio/trello/pull/32.

    This PR makes the repo pass golint and adds linting to the Travis config.

    Comments have been added or their style fixed. A few variables have been renamed.

  • Support the idLabels field on card

    Support the idLabels field on card

    This should all you to assign labels to a card when creating it by giving a list of the label IDs.

    Relevant docs: https://developers.trello.com/reference/#cards-2

  • re-add client on search endpoint

    re-add client on search endpoint

    Currently, if a list of Board objects is retrieved via the search endpoint, we're not re-adding the client variable back into the board, which results in nil pointer errors:

    panic: runtime error: invalid memory address or nil pointer dereference
    [signal SIGSEGV: segmentation violation code=0x1 addr=0x50 pc=0x135f332]
    
    goroutine 1 [running]:
    github.com/luccacabra/trello.(*Client).Throttle(...)
    	github.com/luccacabra/trello/client.go:56
    github.com/luccacabra/trello.(*Client).Get(0x0, 0xc42001c360, 0x25, 0xc42010dd30, 0x1393980, 0xc4201e2240, 0x0, 0x0)
    	github.com/luccacabra/trello/client.go:64 +0x52
    github.com/luccacabra/trello.(*Board).GetLists(0xc4200926c0, 0xc42010dd30, 0xc42010dd30, 0xc42010dd60, 0xc42010dd30, 0x0, 0x13ab2e0)
    	github.com/luccacabra/trello/list.go:40 +0x107
    main.TrelloBoard(0xc420014900, 0x20, 0xc420018280, 0x40, 0xc420016958, 0x4, 0x0, 0x0, 0x0, 0x0, ...)
    ...
    
  • update searchOptions Modifiers type

    update searchOptions Modifiers type

    I can't find this exactly in documentation as Trello doesn't document expected API responses (🤦‍♂️ ), but when calling the search endpoint locally and via this repo, I'm getting JSON errors:

    json: cannot unmarshal object into Go struct field SearchOptions.modifiers of type string
    

    and upon further inspection of the data returned by that endpoint:

    $ > curl "https://api.trello.com/1/search?query=board:test&key=XXX&token=XXX" | jq .
    {
      "options": {
        "terms": [],
        "modifiers": [
          {
            "text": "board:test"
          }
        ],
        "modelTypes": [],
        "partial": false
      }
    }
    

    it appears that the modifiers data type is indeed no longer an array of strings, but an array of map[string][string]s. I've updated the SearchOptions.modifiers type to reflect that change.

  • update searchOptions Modifiers type

    update searchOptions Modifiers type

    I can't find this exactly in documentation as Trello doesn't document expected API responses (🤦‍♂️ ), but when calling the search endpoint locally and via this repo, I'm getting JSON errors:

    json: cannot unmarshal object into Go struct field SearchOptions.modifiers of type string
    

    and upon further inspection of the data returned by that endpoint:

    $ > curl "https://api.trello.com/1/search?query=board:test&key=XXX&token=XXX" | jq .
    {
      "options": {
        "terms": [],
        "modifiers": [
          {
            "text": "board:test"
          }
        ],
        "modelTypes": [],
        "partial": false
      }
    }
    

    it appears that the modifiers data type is indeed no longer an array of strings, but an array of map[string][string]s. I've updated the SearchOptions.modifiers type to reflect that change.

  • Attachments[] is always empty even if there is attachments

    Attachments[] is always empty even if there is attachments

    Using the latest release v1.9.0, hopefully I'm just doing something wrong but I have a giant list of cards all with attachments and after doing GetCards() from a list it seems the attachments array in all of them are empty. Is there possibly something I'm missing here I know all the cards have attachments and the rest of the array data is there not sure what else to try here.

  • Add Starred on Board struct + force all fields retrieval from API on GetBoard

    Add Starred on Board struct + force all fields retrieval from API on GetBoard

    This patch :

    • adds support for the "starred" field which indicated if the Board is one of user favorites.
    • enables retrieval of all fields for Board, because some fields (like Starred) may not transmitted by the API by default.
  • Getting custom fields doesn't work as expected

    Getting custom fields doesn't work as expected

    Problem: Using the CustomFields function on a Card reciever returns 0 data

    Code:

    func main () {
    
       appKey := `<CONFIDENTIAL>`
       token := `<CONFIDENTIAL>`
       boardId := `<CONFIDENTIAL>`
    
       client := trello.NewClient(appKey, token)
       board, err := client.GetBoard(boardId, trello.Defaults())
       if err != nil {
          fmt.Println(err)
          return
       }
    
       customFields, err := board.GetCustomFields(trello.Defaults())
       if err != nil {
          fmt.Println(err)
       }
    
       fmt.Println("Printing custom field objects on the board")
       for _, v := range customFields {
          fmt.Printf("%+v", v)
          fmt.Println()
       }
    
       lists, err := board.GetLists(trello.Defaults())
       if err != nil {
          fmt.Println(err)
          return
       }
    
       for _, list := range lists {
         cards, err := list.GetCards(trello.Defaults())
         if err != nil {
            fmt.Println(err)
            continue
         }
    
         fmt.Println("Number of cards in list:", len(cards))
         var count int = 0
    
         for _, card := range cards {
    
            count++
           
            /// It is unclear if the Card slice this function requires should come from Board.GetCustomFields, or if it should be an empty slice.
            customFieldMap := card.CustomFields(customFields)
            fmt.Println("Number of custom fields on card", count, ":", len(customFieldMap))
            fmt.Println("Number of custom field items on card", count, ":", len(card.CustomFieldItems))
    
         }
       }
    }
    

    Output:

    Printing custom field objects on the board
    &{ID:5fa073a5eedccb1a273b7db2 IDModel:5fa0710b81d40785e7e8d06a IDModelType:board FieldGroup:9fdff5d309838d346add25a8e5260d5c27b4dbcc98e5c3d0da85b5ec991e37f7 Name:Created Pos:16384 Display:{CardFront:false} Type:date Options:[]}
    &{ID:5fa073afa41de270281aa94c IDModel:5fa0710b81d40785e7e8d06a IDModelType:board FieldGroup:9c0fdca40714ca5c1f07cf19dce17821e5929624a57ae4a1f8fcd938cceca945 Name:Start Pos:32768 Display:{CardFront:false} Type:date Options:[]}
    &{ID:5fa073b63f96c845ec9dd0c7 IDModel:5fa0710b81d40785e7e8d06a IDModelType:board FieldGroup:fc5e9fa90b20867f3c27c61e67e33b2e583653abd693703800c04456ec854114 Name:End Pos:49152 Display:{CardFront:false} Type:date Options:[]}
    &{ID:5fa0741e1d9d2c2bc833788f IDModel:5fa0710b81d40785e7e8d06a IDModelType:board FieldGroup:c77db228ea2700530db145e0d91ab5129ce52883999ccc42693e6dae7d2c2ad3 Name:Charge Pos:65536 Display:{CardFront:true} Type:list Options:[0xc0000d64b0 0xc0000d6500 0xc0000d6550]}
    &{ID:5fa074286ef27c133d0186bb IDModel:5fa0710b81d40785e7e8d06a IDModelType:board FieldGroup:7602b2a97184edb3beeb5b0076b88f065146bd5797726754fc6c96e099d15abc Name:Workload Pos:81920 Display:{CardFront:true} Type:list Options:[0xc0000d65a0 0xc0000d65f0 0xc0000d6640 0xc0000d6690 0xc0000d66e0 0xc0000d6730]}
    &{ID:5fa0746a39b64c850400b920 IDModel:5fa0710b81d40785e7e8d06a IDModelType:board FieldGroup:b0cddfb41bc9462347387c37077a2de5338a50c797e04f3cf0adb6ae2344e83c Name:Priority Pos:98304 Display:{CardFront:true} Type:list Options:[0xc0000d6780 0xc0000d67d0 0xc0000d6820 0xc0000d6870 0xc0000d68c0 0xc0000d6910 0xc0000d69b0]}
    &{ID:5fa079eb3c04d6016ef994e2 IDModel:5fa0710b81d40785e7e8d06a IDModelType:board FieldGroup:e8620327b22fc5e743a35720260ad7f03a0edaef6e64e3c47f37f04f09ce4747 Name:Status Pos:114688 Display:{CardFront:true} Type:list Options:[0xc0000d6a50 0xc0000d6aa0 0xc0000d6af0 0xc0000d6b40 0xc0000d6b90]}
    Number of cards in list: 5
    Number of custom fields on card 1 : 0
    Number of custom field items on card 1 : 0
    Number of custom fields on card 2 : 0
    Number of custom field items on card 2 : 0
    Number of custom fields on card 3 : 0
    Number of custom field items on card 3 : 0
    Number of custom fields on card 4 : 0
    Number of custom field items on card 4 : 0
    Number of custom fields on card 5 : 0
    Number of custom field items on card 5 : 0
    Number of cards in list: 2
    Number of custom fields on card 1 : 0
    Number of custom field items on card 1 : 0
    Number of custom fields on card 2 : 0
    Number of custom field items on card 2 : 0
    Number of cards in list: 6
    Number of custom fields on card 1 : 0
    Number of custom field items on card 1 : 0
    Number of custom fields on card 2 : 0
    Number of custom field items on card 2 : 0
    Number of custom fields on card 3 : 0
    Number of custom field items on card 3 : 0
    Number of custom fields on card 4 : 0
    Number of custom field items on card 4 : 0
    Number of custom fields on card 5 : 0
    Number of custom field items on card 5 : 0
    Number of custom fields on card 6 : 0
    Number of custom field items on card 6 : 0
    Number of cards in list: 1
    Number of custom fields on card 1 : 0
    Number of custom field items on card 1 : 0
    Number of cards in list: 4
    Number of custom fields on card 1 : 0
    Number of custom field items on card 1 : 0
    Number of custom fields on card 2 : 0
    Number of custom field items on card 2 : 0
    Number of custom fields on card 3 : 0
    Number of custom field items on card 3 : 0
    Number of custom fields on card 4 : 0
    Number of custom field items on card 4 : 0
    

    Expectation: Using the CustomFields function on a Card reciever should provide data on what the value is for each custom field

    How to reproduce: Copy the above example code in your own main program, fill in the appKey, token, and boardId fields to a Trello board you control, then observe the output.

    Notes: It seems that the CustomFieldItems JSON serialized property on Card is empty to begin with, so the loop in Card.CustomFields skips over it.

  • invite with link?

    invite with link?

    I can't seem to find it anywhere in the API docs.. does anyone know how to automate the "invite with link" process? I am creating and populating a board, but someone still has to manually generate the link on their browser.

  • Use type.setClient(c) for consistency and ...

    Use type.setClient(c) for consistency and ...

    There are several Type(s) that have sub-types, and it was inconsistent. The goal here is to use type.setClient(c) every time, and if there are sub-types, loop through them and use their subType.setClient(c). Additionally, when possible, set the parent object. (i.e.) Board <-> List <-> Card <-> CheckList <-> CheckItem

    Used the _, item for range, as the code is much cleaner. (and maybe easier to understand).

    Also, minor "lint" change on board_test.go

  • Support dropdown list-type custom fields

    Support dropdown list-type custom fields

    When creating custom fields, I have the option to select "dropdown", which results in a .customField[].type="list" being created. The options are predefined in .customField[].options[] with .customField[].options[].value being what github.com/adlio/trello calls cfval. It always contains a text field.

    It would be great if dropdowns were supported by this library.

  • Cards lack GetList() method

    Cards lack GetList() method

    Card has a List field, but no Card.GetList() method to fill it.

    The information does not appear to be returned by the Trello API for calls to List.GetCards(), and cannot be optionally requested through it, since https://developer.atlassian.com/cloud/trello/rest/#api-lists-id-cards-get does not describe a fields argument (and it is not respected by the API).

  • feat: add custom field clean method

    feat: add custom field clean method

    This PR has three commits that need the review.

    feat: add RemoveIDCustomField method

    In this commit I've added the method to delete (only clear) custom field of the card by its ID (see "Clearing CustomFieldItems" here).

    But there was a problem. Because of the definition of the Value field in the CustomFieldItem result from the API was not parsed correctly. I'd tried to understand why we need here (in general purpose library) so complex unmarshaling with some kind of the business logic and stuck with that. There are no tests to explain this.

    impr: change custom fields value struct

    To develop this idea I've simplified CustomFieldItem struct and all corresponding methods. No tests was broken after that, only type actualization.

    impr: refactor CustomFields method

    As a result I've refactor CustomFields card method to use more idiomatic go code and new simplified CustomFieldItem struct.

    Conclusion

    I think, that it is more correct style for the general library and type casting from the CustomFieldItemValue should be done in the business logic on the application level. The casting logic that was here earlier is hard to understand and did not have general application.

A Wrapper Client for Google Spreadsheet API (Sheets API)

Senmai A Wrapper Client for Google Spreadsheet API (Sheets API) PREPARATION Service Account and Key File Create a service account on Google Cloud Plat

Nov 5, 2021
A GoLang wrapper for Politics & War's API. Forego the hassle of accessing the API directly!

A GoLang wrapper for Politics & War's API. Forego the hassle of accessing the API directly!

Mar 5, 2022
Simple golang airtable API wrapper

Golang Airtable API A simple #golang package to access the Airtable API. Table of contents Golang Airtable API Table of contents Installation Basic us

Jan 5, 2023
This is a Golang wrapper for working with TMDb API. It aims to support version 3.
This is a Golang wrapper for working with TMDb API. It aims to support version 3.

This is a Golang wrapper for working with TMDb API. It aims to support version 3. An API Key is required. To register for one, head over to themoviedb

Dec 27, 2022
⚡️ SharePoint authentication, HTTP client & fluent API wrapper for Go (Golang)
⚡️ SharePoint authentication, HTTP client & fluent API wrapper for Go (Golang)

Gosip - SharePoint authentication, HTTP client & fluent API wrapper for Go (Golang) Main features Unattended authentication using different strategies

Jan 2, 2023
Nov 28, 2022
The fantastic Reddit API wrapper for gophers
The fantastic Reddit API wrapper for gophers

mira is a Reddit Api Wrapper written in beautiful Go. It is super simple to use the bot as we also provide you with simple but fully extensive interfaces. Currently, mira is a project that is considered more or less complete.

Dec 18, 2022
A small, fast, reliable pastemyst API wrapper written in Golang

A small, fast, reliable pastemyst API wrapper written in Golang. Official pastemyst API docs found here.

Dec 12, 2022
SpamProtection-Go is an Official golang wrapper for Intellivoid SpamProtection API
SpamProtection-Go is an Official golang wrapper for Intellivoid SpamProtection API

SpamProtection-Go is an Official golang wrapper for Intellivoid SpamProtection API, which is fast, secure and requires no additional packages to be installed.

Feb 26, 2022
A Telegraph API wrapper in Go

Telegra.ph is a minimalist publishing tool that allows you to create richly formatted posts and push them to the Web in just a click. Telegraph posts also get beautiful Instant View pages on Telegram. So, this Go wrapper enables you to do all that easily.

Oct 29, 2022
Unofficial Anilist.co GraphQL API wrapper for GoLang.

anilistWrapGo Unofficial Anilist.co GraphQL API wrapper for GoLang. Examples All examples are present as tests in test directory. Below are a few snip

Dec 20, 2022
Pterodactyl API wrapper written in Golang

WARNING That repository isn't available for production environment. Many endpoints aren't yet implemented. Be careful if you are using that module. pt

Oct 4, 2022
💻 Quotable.io API Wrapper + CLI App
💻 Quotable.io API Wrapper + CLI App

?? Quotable.io API Wrapper + CLI App

Sep 27, 2022
A Wrapper of the Piston API in Golang

Go-Piston! This is a Go wrapper for working with the Piston API. It supports both the endpoints, namely runtimes and execute, mentioned here. ?? Insta

Aug 28, 2022
Golang wrapper for the FiveM natives API

Golang wrapper for the FiveM natives API

Dec 2, 2022
spamwatch-go is official Go wrapper for SpamWatch API
spamwatch-go is official Go wrapper for SpamWatch API

SpamWatch API Go Wrapper spamwatch-go is official Go wrapper for SpamWatch API, which is fast, secure and requires no additional packages to be instal

Feb 17, 2022
Unofficial but convenient Go wrapper around the NVD API

NVD API The NVD API is an unofficial Go wrapper around the NVD API. Supports: CVE CPE How to use The following shows how to basically use the wrapper

Nov 1, 2021
A Go wrapper around the Notion API

go-notion A Go wrapper around the Notion API. | ⚠ This package is new and under active development. How to Use Install the package go get github.com/b

Nov 19, 2021
A complete and simple wrapper for the Hypixel API

Gopixel A simple and complete1 wrapper for the hypixel API Key features Full API coverage1 Autocomplete for fields Near complete structs MIT license I

Apr 26, 2022