Hey there, fellow Go enthusiast! Ready to supercharge your fundraising efforts with Donorbox? Let's dive into building a robust API integration that'll have you managing donations like a pro in no time.
Before we jump in, make sure you've got:
Let's kick things off by creating a new Go module:
mkdir donorbox-integration && cd donorbox-integration go mod init github.com/yourusername/donorbox-integration
Now, let's grab the HTTP client we'll need:
go get -u github.com/go-resty/resty/v2
Donorbox uses API key authentication. Let's set that up:
package main import ( "github.com/go-resty/resty/v2" ) const ( baseURL = "https://donorbox.org/api/v1" apiKey = "your-api-key-here" ) func main() { client := resty.New(). SetBaseURL(baseURL). SetHeader("Authorization", "Bearer "+apiKey) }
Now that we've got our client set up, let's make some requests!
func fetchDonations(client *resty.Client) ([]Donation, error) { var response struct { Donations []Donation `json:"donations"` } _, err := client.R(). SetResult(&response). Get("/donations") return response.Donations, err }
func createDonation(client *resty.Client, donation Donation) error { _, err := client.R(). SetBody(donation). Post("/donations") return err }
func getDonor(client *resty.Client, donorID string) (Donor, error) { var donor Donor _, err := client.R(). SetResult(&donor). Get("/donors/" + donorID) return donor, err }
Donorbox returns errors in a consistent format. Let's handle them:
type APIError struct { Message string `json:"message"` } func handleAPIError(resp *resty.Response) error { if resp.IsError() { var apiError APIError if err := json.Unmarshal(resp.Body(), &apiError); err != nil { return fmt.Errorf("unknown error: %s", resp.Status()) } return fmt.Errorf("API error: %s", apiError.Message) } return nil }
Donorbox uses cursor-based pagination. Here's how to handle it:
func fetchAllDonations(client *resty.Client) ([]Donation, error) { var allDonations []Donation cursor := "" for { var response struct { Donations []Donation `json:"donations"` Meta struct { NextCursor string `json:"next_cursor"` } `json:"meta"` } _, err := client.R(). SetQueryParam("cursor", cursor). SetResult(&response). Get("/donations") if err != nil { return nil, err } allDonations = append(allDonations, response.Donations...) if response.Meta.NextCursor == "" { break } cursor = response.Meta.NextCursor } return allDonations, nil }
Donorbox has rate limits, so let's be good citizens:
func main() { client := resty.New(). SetBaseURL(baseURL). SetHeader("Authorization", "Bearer "+apiKey). SetRetryCount(3). SetRetryWaitTime(5 * time.Second) }
Don't forget to test! Here's a quick example:
func TestFetchDonations(t *testing.T) { mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte(`{"donations": [{"id": "123", "amount": 50}]}`)) })) defer mockServer.Close() client := resty.New().SetBaseURL(mockServer.URL) donations, err := fetchDonations(client) assert.NoError(t, err) assert.Len(t, donations, 1) assert.Equal(t, "123", donations[0].ID) }
And there you have it! You've just built a solid Donorbox API integration in Go. Remember, this is just the beginning - there's always room to expand and optimize. Keep exploring the API docs, and happy coding!