twapi

package module
v0.0.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2025 License: MIT Imports: 8 Imported by: 0

README ยถ

๐Ÿš€ Teamwork.com API - Go SDK

Go Version License Go Report Card

The official Go SDK for the Teamwork.com API

Build powerful integrations with Teamwork's project management platform

๐Ÿ“– API Documentation โ€ข ๐ŸŽฏ Examples โ€ข ๐Ÿ› Report Issues


โœจ Features

  • ๏ฟฝ Multiple Authentication Methods - Bearer token, Basic auth, and OAuth2
  • ๐Ÿ—๏ธ Type-Safe API - Fully typed requests and responses
  • ๐ŸŒ Context Support - Built-in context.Context support for cancellation and timeouts
  • ๐Ÿ“ฆ Zero Dependencies - Minimal external dependencies
  • ๐Ÿงช Thoroughly Tested - Comprehensive test coverage
  • ๐Ÿ“ฑ Cross-Platform - Works on Windows, macOS, and Linux

๐Ÿ“ฆ Installation

Add this library as a dependency to your Go module:

go get github.com/teamwork/twapi-go-sdk

Requirements:

  • Go 1.24 or later
  • A Teamwork.com account with API access

๐Ÿ” Authentication

The SDK supports multiple authentication methods to suit different use cases:

Perfect for server-to-server integrations and scripts:

import "github.com/teamwork/twapi-go-sdk/session"

session := session.NewBearerToken("your_api_token", "https://yourdomain.teamwork.com")
๐Ÿ”‘ Basic Authentication

Use with API tokens or user credentials:

// With API token
session := session.NewBasicAuth("your_api_token", "", "https://yourdomain.teamwork.com")

// With username/password
session := session.NewBasicAuth("username", "password", "https://yourdomain.teamwork.com")
๐ŸŒ OAuth2

Ideal for user-facing applications (opens browser for authorization):

session := session.NewOAuth2("client_id", "client_secret",
  session.WithOAuth2Server("https://teamwork.com"),
  session.WithOAuth2CallbackServerAddr("127.0.0.1:6275"),
)

[!CAUTION] โš ๏ธ Note: OAuth2 opens a browser window and is not suitable for headless environments.

๐Ÿ Quick Start

Here's a simple example to get you started:

package main

import (
  "context"
  "fmt"
  "log"

  twapi "github.com/teamwork/twapi-go-sdk"
  "github.com/teamwork/twapi-go-sdk/projects"
  "github.com/teamwork/twapi-go-sdk/session"
)

func main() {
  ctx := context.Background()
  
  // Initialize the SDK with bearer token authentication
  engine := twapi.NewEngine(session.NewBearerToken("your_token", "https://yourdomain.teamwork.com"))

  // Create a new project
  project, err := projects.ProjectCreate(ctx, engine, projects.NewProjectCreateRequest("My Awesome Project"))
  if err != nil {
    log.Fatalf("Failed to create project: %v", err)
  }
  
  fmt.Printf("โœ… Created project '%s' with ID: %d\n", project.Name, project.ID)
}

๐Ÿ“š Examples

Working with Projects
package main

import (
  "context"
  "fmt"
  "time"

  twapi "github.com/teamwork/twapi-go-sdk"
  "github.com/teamwork/twapi-go-sdk/projects"
  "github.com/teamwork/twapi-go-sdk/session"
)

func main() {
  ctx := context.Background()
  engine := twapi.NewEngine(session.NewBearerToken("your_token", "https://yourdomain.teamwork.com"))

  project, err := projects.ProjectCreate(ctx, engine, projects.ProjectCreateRequest{
    Name:        "Q1 Marketing Campaign",
    Description: twapi.Ptr("Marketing campaign for Q1 product launch"),
    StartAt:     twapi.Ptr(time.Now()),
    EndAt:       twapi.Ptr(time.Now().AddDate(0, 3, 0)), // 3 months from now
  })
  if err != nil {
    fmt.Fprintf(os.Stderr, "โŒ Failed to create project: %v\n", err)
    os.Exit(1)
  }

  // Retrieve the project
  retrievedProject, err := projects.ProjectGet(ctx, engine, projects.NewProjectRetrieveRequest(int64(project.ID)))
  if err != nil {
    fmt.Fprintf(os.Stderr, "โŒ Failed to retrieve project: %v\n", err)
    os.Exit(1)
  }

  fmt.Printf("โœ… Project: %s (ID: %d)\n", retrievedProject.Name, retrievedProject.ID)
  
  // List all projects
  projectsList, err := projects.ProjectList(ctx, engine, projects.NewProjectRetrieveManyRequest())
  if err != nil {
    fmt.Fprintf(os.Stderr, "โŒ Failed to list projects: %v\n", err)
    os.Exit(1)
  }
  
  fmt.Printf("โœ… Found %d projects\n", len(projectsList.Projects))
  
  // Update the project
  updatedProject, err := projects.ProjectUpdate(ctx, engine, projects.ProjectUpdateRequest{
    Path:  projects.ProjectUpdateRequestPath{
      ID: int64(project.ID),
    },
    Name: "Q1 Marketing Campaign - Updated",
  })
  if err != nil {
    fmt.Fprintf(os.Stderr, "โŒ Failed to update project: %v\n", err)
    os.Exit(1)
  }
  
  fmt.Printf("โœ… Updated project name to: %s\n", updatedProject.Name)

  // Delete the project
  err = projects.ProjectDelete(ctx, engine, projects.NewProjectDeleteRequest(int64(project.ID)))
  if err != nil {
    fmt.Fprintf(os.Stderr, "โŒ Failed to delete project: %v\n", err)
    os.Exit(1)
  }

  fmt.Println("โœ… Project deleted successfully")
}
OAuth2 Authentication Example
package main

import (
  "context"
  "flag"
  "fmt"
  "os"

  twapi "github.com/teamwork/twapi-go-sdk"
  "github.com/teamwork/twapi-go-sdk/projects"
  "github.com/teamwork/twapi-go-sdk/session"
)

func main() {
  clientID := flag.String("client-id", "", "OAuth2 Client ID")
  clientSecret := flag.String("client-secret", "", "OAuth2 Client Secret")
  flag.Parse()

  if *clientID == "" || *clientSecret == "" {
    fmt.Fprintln(os.Stderr, "โŒ client-id and client-secret are required")
    os.Exit(1)
  }

  // Create OAuth2 session (will open browser for authorization)
  session := session.NewOAuth2(*clientID, *clientSecret,
    session.WithOAuth2CallbackServerAddr("127.0.0.1:6275"),
  )
  
  engine := twapi.NewEngine(session)

  // Test the connection by creating a project
  project, err := projects.ProjectCreate(context.Background(), engine, projects.NewProjectCreateRequest("OAuth2 Test Project"))
  if err != nil {
    fmt.Fprintf(os.Stderr, "โŒ Failed to create project: %v\n", err)
    os.Exit(1)
  }

  fmt.Printf("โœ… OAuth2 authentication successful! Created project: %s (ID: %d)\n", project.Name, project.ID)
}
Error Handling Best Practices
package main

import (
  "context"
  "errors"
  "fmt"
  "net/http"

  twapi "github.com/teamwork/twapi-go-sdk"
  "github.com/teamwork/twapi-go-sdk/projects"
  "github.com/teamwork/twapi-go-sdk/session"
)

func main() {
  ctx := context.Background()
  engine := twapi.NewEngine(session.NewBearerToken("your_token", "https://yourdomain.teamwork.com"))

  project, err := projects.ProjectCreate(ctx, engine, projects.NewProjectCreateRequest("Test Project"))
  if err != nil {
    // Handle different types of errors
    var httpErr *twapi.HTTPError
    if errors.As(err, &httpErr) {
      switch httpErr.StatusCode {
      case http.StatusUnauthorized:
        fmt.Println("โŒ Authentication failed - check your API token")
      case http.StatusForbidden:
        fmt.Println("โŒ Access denied - insufficient permissions")
      case http.StatusTooManyRequests:
        fmt.Println("โŒ Rate limit exceeded - please retry later")
      default:
        fmt.Printf("โŒ HTTP error %d: %s\n", httpErr.StatusCode, httpErr.Message)
      }
    } else {
      fmt.Printf("โŒ Unexpected error: %v\n", err)
    }
    return
  }

  fmt.Printf("โœ… Success! Created project: %s\n", project.Name)
}

๐Ÿ› ๏ธ Available Modules

Currently supported Teamwork.com API endpoints:

Module Description Status
projects Create, read, update, and delete projects โœ… Stable
More modules coming soon... ๐Ÿšง In Development

๐Ÿ”ง Configuration

Context and Timeouts

The SDK supports Go's context.Context for request cancellation and timeouts:

import "time"

// Create a context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

// Use the context in API calls
project, err := projects.ProjectCreate(ctx, engine, request)
Custom HTTP Client

You can customize the underlying HTTP client:

import (
  "net/http"
  "time"
)

// Create engine with custom HTTP client
httpClient := &http.Client{
  Timeout: 60 * time.Second,
  Transport: &http.Transport{
    MaxIdleConns:        10,
    IdleConnTimeout:     30 * time.Second,
    DisableCompression:  true,
  },
}

engine := twapi.NewEngine(session,
  twapi.WithHTTPClient(httpClient),
)

๐Ÿ› Error Handling

The SDK provides structured error handling:

import "errors"

project, err := projects.ProjectCreate(ctx, engine, request)
if err != nil {
  var httpErr *twapi.HTTPError
  if errors.As(err, &httpErr) {
    fmt.Printf("HTTP %d: %s\n", httpErr.StatusCode, httpErr.Message)
    // Handle specific status codes
  }
}

๐Ÿงช Testing

Run the test suite:

go test ./...

Run integration tests:

TWAPI_SERVER=https://yourdomain.teamwork.com/ TWAPI_TOKEN=your_api_token go test ./...

Run tests with coverage:

go test -race -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

๐Ÿ“‹ Requirements

  • Go Version: 1.24 or later
  • Dependencies: Minimal external dependencies (see go.mod)
  • Teamwork Account: Valid Teamwork.com account with API access

๐Ÿค Contributing

We welcome contributions! Please see our Contributing Guidelines for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ†˜ Support


Made with โค๏ธ by the Teamwork.com team

โญ Star us on GitHub if this project helped you!

Documentation ยถ

Index ยถ

Constants ยถ

This section is empty.

Variables ยถ

This section is empty.

Functions ยถ

func Execute ยถ

func Execute[T HTTPResponser](ctx context.Context, engine *Engine, requester HTTPRequester) (T, error)

Execute sends an HTTP request using the provided requester and handles the response using the provided responser.

func Ptr ยถ

func Ptr[T any](v T) *T

Ptr returns a pointer to the value v.

Types ยถ

type Date ยถ

type Date time.Time

Date is a type alias for time.Time, used to represent date values in the API.

func (Date) MarshalJSON ยถ

func (d Date) MarshalJSON() ([]byte, error)

MarshalJSON encodes the Date as a string in the format "2006-01-02".

func (Date) MarshalText ยถ

func (d Date) MarshalText() ([]byte, error)

MarshalText encodes the Date as a string in the format "2006-01-02".

func (Date) String ยถ

func (d Date) String() string

String returns the string representation of the Date in the format "2006-01-02".

func (*Date) UnmarshalJSON ยถ

func (d *Date) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a JSON string into a Date type.

func (*Date) UnmarshalText ยถ

func (d *Date) UnmarshalText(text []byte) error

UnmarshalText decodes a text string into a Date type. This is required when using Date type as a map key.

type Engine ยถ

type Engine struct {
	// contains filtered or unexported fields
}

Engine is the main structure that handles communication with the Teamwork API.

func NewEngine ยถ

func NewEngine(session Session, opts ...EngineOption) *Engine

NewEngine creates a new Engine instance with the provided HTTP client and session.

type EngineOption ยถ

type EngineOption func(*Engine)

EngineOption is a function that modifies the Engine configuration.

func WithHTTPClient ยถ

func WithHTTPClient(client *http.Client) EngineOption

WithHTTPClient sets the HTTP client for the Engine. By default, it uses http.DefaultClient.

func WithLogger ยถ

func WithLogger(logger *slog.Logger) EngineOption

WithLogger sets the logger for the Engine. By default, it uses slog.Default().

func WithRequestMiddleware ยถ added in v0.0.3

func WithRequestMiddleware(middleware func(HTTPRequester) HTTPRequester) EngineOption

WithRequestMiddleware adds a request middleware to the Engine. Middlewares are applied in the order they are added.

func WithResponseMiddleware ยถ added in v0.0.3

func WithResponseMiddleware(middleware func(HTTPResponser) HTTPResponser) EngineOption

WithResponseMiddleware adds a response middleware to the Engine. Middlewares are applied in the order they are added.

type HTTPError ยถ added in v0.0.3

type HTTPError struct {
	StatusCode int
	Headers    http.Header
	Message    string
	Details    string
}

HTTPError represents an error response from the API.

func NewHTTPError ยถ added in v0.0.3

func NewHTTPError(resp *http.Response, message string) *HTTPError

NewHTTPError creates a new HTTPError from an http.Response.

func (*HTTPError) Error ยถ added in v0.0.3

func (e *HTTPError) Error() string

Error implements the error interface.

type HTTPRequester ยถ

type HTTPRequester interface {
	HTTPRequest(ctx context.Context, server string) (*http.Request, error)
}

HTTPRequester knows how to create an HTTP request for a specific entity.

type HTTPResponser ยถ

type HTTPResponser interface {
	HandleHTTPResponse(resp *http.Response) error
}

HTTPResponser knows how to handle an HTTP response for a specific entity.

type Money ยถ

type Money int64

Money represents a monetary value in the API.

func (*Money) Set ยถ

func (m *Money) Set(value float64)

Set sets the value of Money from a float64.

func (Money) Value ยถ

func (m Money) Value() float64

Value returns the value of Money as a float64.

type OptionalDateTime ยถ

type OptionalDateTime time.Time

OptionalDateTime is a type alias for time.Time, used to represent date and time values in the API. The difference is that it will accept empty strings as valid values.

func (OptionalDateTime) MarshalJSON ยถ

func (d OptionalDateTime) MarshalJSON() ([]byte, error)

MarshalJSON encodes the OptionalDateTime as a string in the format "2006-01-02T15:04:05Z07:00".

func (*OptionalDateTime) UnmarshalJSON ยถ

func (d *OptionalDateTime) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a JSON string into an OptionalDateTime type.

type Relationship ยถ added in v0.0.3

type Relationship struct {
	ID   int64          `json:"id"`
	Type string         `json:"type"`
	Meta map[string]any `json:"meta,omitempty"`
}

Relationship describes the relation between the main entity and a sideload type.

type Session ยถ

type Session interface {
	Authenticate(ctx context.Context, req *http.Request) error
	Server() string
}

Session is an interface that defines the methods required for a session to authenticate requests to the Teamwork Engine.

type Time ยถ

type Time time.Time

Time is a type alias for time.Time, used to represent time values in the API.

func (Time) MarshalJSON ยถ

func (t Time) MarshalJSON() ([]byte, error)

MarshalJSON encodes the Time as a string in the format "15:04:05".

func (Time) MarshalText ยถ

func (t Time) MarshalText() ([]byte, error)

MarshalText encodes the Time as a string in the format "15:04:05".

func (Time) String ยถ

func (t Time) String() string

String returns the string representation of the Time in the format "15:04:05".

func (*Time) UnmarshalJSON ยถ

func (t *Time) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a JSON string into a Date type.

func (*Time) UnmarshalText ยถ

func (t *Time) UnmarshalText(text []byte) error

UnmarshalText decodes a text string into a Time type. This is required when using Time type as a map key.

Directories ยถ

Path Synopsis
examples
oauth2 command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL