Back

Step by Step Guide to Building a ConnectWise Manage API Integration in Go

Aug 16, 2024 • 6 minute read

Introduction

Hey there, fellow developer! Ready to dive into the world of ConnectWise Manage API integration using Go? You're in for a treat. This guide will walk you through the process of building a robust integration that'll make your life easier and your code more powerful. Let's get started!

Prerequisites

Before we jump in, make sure you've got:

  • Go installed on your machine (you're a pro, so I'm sure you've got this covered)
  • ConnectWise Manage API credentials (if you don't have these, go bug your admin!)
  • Your favorite code editor ready to rock

Setting up the project

First things first, let's set up our project:

mkdir cwm-api-integration cd cwm-api-integration go mod init github.com/yourusername/cwm-api-integration

Now, let's grab the packages we'll need:

go get github.com/go-resty/resty/v2 go get github.com/sirupsen/logrus

Authentication

Alright, time to get our hands dirty with some authentication. ConnectWise uses API keys, so let's implement that:

package main import ( "github.com/go-resty/resty/v2" "github.com/sirupsen/logrus" ) const ( baseURL = "https://api-na.myconnectwise.net/v4_6_release/apis/3.0" companyID = "your_company_id" publicKey = "your_public_key" privateKey = "your_private_key" ) func main() { client := resty.New() client.SetBasicAuth(companyID+"+"+publicKey, privateKey) client.SetBaseURL(baseURL) // We'll use this client for our API calls }

Making API requests

Now that we're authenticated, let's make some API calls:

// GET request resp, err := client.R(). SetHeader("Accept", "application/json"). Get("/company/companies") if err != nil { logrus.Fatalf("API request failed: %v", err) } // POST request newCompany := map[string]interface{}{ "name": "Acme Corp", "identifier": "ACME", } resp, err := client.R(). SetHeader("Content-Type", "application/json"). SetBody(newCompany). Post("/company/companies") if err != nil { logrus.Fatalf("API request failed: %v", err) }

Error handling and logging

Let's add some proper error handling and logging:

if err != nil { logrus.WithFields(logrus.Fields{ "status": resp.StatusCode(), "body": resp.String(), }).Errorf("API request failed: %v", err) return } logrus.Infof("API request successful: %s", resp.String())

Data parsing and manipulation

Time to work with that JSON data:

type Company struct { ID int `json:"id"` Name string `json:"name"` Identifier string `json:"identifier"` } var companies []Company err = json.Unmarshal(resp.Body(), &companies) if err != nil { logrus.Fatalf("Failed to parse JSON: %v", err) } for _, company := range companies { logrus.Infof("Company: %s (ID: %d)", company.Name, company.ID) }

Implementing specific API endpoints

Let's create some helper functions for common endpoints:

func getCompanies(client *resty.Client) ([]Company, error) { // Implementation here } func createTicket(client *resty.Client, ticket Ticket) (Ticket, error) { // Implementation here } func logTimeEntry(client *resty.Client, timeEntry TimeEntry) error { // Implementation here }

Rate limiting and pagination

ConnectWise has rate limits, so let's be good citizens:

time.Sleep(time.Second) // Simple rate limiting // Pagination page := 1 for { resp, err := client.R(). SetQueryParam("page", strconv.Itoa(page)). SetQueryParam("pageSize", "1000"). Get("/company/companies") // Process response if len(companies) < 1000 { break // Last page } page++ }

Testing the integration

Don't forget to test your code! Here's a simple example:

func TestGetCompanies(t *testing.T) { client := setupTestClient() companies, err := getCompanies(client) assert.NoError(t, err) assert.NotEmpty(t, companies) }

Best practices and optimization

  • Keep your code modular and well-organized
  • Use goroutines for concurrent API calls (but be mindful of rate limits)
  • Cache frequently accessed data to reduce API calls

Conclusion

And there you have it! You've just built a ConnectWise Manage API integration in Go. Pretty cool, right? Remember, this is just the beginning. There's a whole world of possibilities with this API, so keep exploring and building awesome things!

Happy coding, and may your API calls always return 200 OK! 🚀