Create README with quickstart guide
Add comprehensive README.md documentation: - Project description - Installation instructions (go get) - Quick start example with client init, list checklists, create task - API overview for Checklists, Tasks, Notes - Due date helpers (DueToday, DueTomorrow, DueAt, DueInDays) - TaskBuilder fluent interface examples - Error handling with sentinel errors - Configuration options (timeout, retry, logger) - Authentication section (auto, 2FA, current user) - Link to pkg.go.dev documentation - MIT license reference Closes checkvist-api-nrk
This commit is contained in:
parent
2f44308d42
commit
45e6b6eb18
2 changed files with 236 additions and 1 deletions
|
|
@ -19,7 +19,7 @@
|
||||||
{"id":"checkvist-api-e9p","title":"Implement data models","description":"Create models.go with all data structures:\n- Checklist struct (ID, Name, Public, Archived, ReadOnly, TaskCount, TaskCompleted, Tags, TagsAsText, UpdatedAt)\n- Task struct (ID, ChecklistID, ParentID, Content, Status, Position, Priority, Tags, TagsAsText, DueDateRaw, DueDate, AssigneeIDs, CommentsCount, UpdateLine, UpdatedAt, CreatedAt, Children, Notes)\n- TaskStatus enum (StatusOpen=0, StatusClosed=1, StatusInvalidated=2)\n- Note struct (ID, TaskID, Comment, UpdatedAt, CreatedAt)\n- Tags type (map[string]bool)\n- User struct (ID, Username, Email)\n- DueDate struct with constructors (DueAt, DueString, DueInDays) and constants (DueToday, DueTomorrow, DueNextWeek, DueNextMonth)","status":"closed","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:06.900391036+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:22:22.273934664+01:00","closed_at":"2026-01-14T13:22:22.273934664+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-e9p","depends_on_id":"checkvist-api-5wr","type":"blocks","created_at":"2026-01-14T12:32:46.433908937+01:00","created_by":"Oliver Jakoubek"}]}
|
{"id":"checkvist-api-e9p","title":"Implement data models","description":"Create models.go with all data structures:\n- Checklist struct (ID, Name, Public, Archived, ReadOnly, TaskCount, TaskCompleted, Tags, TagsAsText, UpdatedAt)\n- Task struct (ID, ChecklistID, ParentID, Content, Status, Position, Priority, Tags, TagsAsText, DueDateRaw, DueDate, AssigneeIDs, CommentsCount, UpdateLine, UpdatedAt, CreatedAt, Children, Notes)\n- TaskStatus enum (StatusOpen=0, StatusClosed=1, StatusInvalidated=2)\n- Note struct (ID, TaskID, Comment, UpdatedAt, CreatedAt)\n- Tags type (map[string]bool)\n- User struct (ID, Username, Email)\n- DueDate struct with constructors (DueAt, DueString, DueInDays) and constants (DueToday, DueTomorrow, DueNextWeek, DueNextMonth)","status":"closed","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:06.900391036+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:22:22.273934664+01:00","closed_at":"2026-01-14T13:22:22.273934664+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-e9p","depends_on_id":"checkvist-api-5wr","type":"blocks","created_at":"2026-01-14T12:32:46.433908937+01:00","created_by":"Oliver Jakoubek"}]}
|
||||||
{"id":"checkvist-api-lpn","title":"Implement authentication with auto token renewal","description":"Add to client.go:\n- Authenticate(ctx context.Context) error - explicit login\n- refreshToken(ctx context.Context) error - token renewal\n- ensureAuthenticated(ctx context.Context) error - auto-auth before requests\n- CurrentUser(ctx context.Context) (*User, error) - get logged in user\n- Token management: store token and expiry, auto-refresh before expiry\n- Thread-safe token access using mutex\n- Support for optional 2FA token\nAPI endpoints:\n- POST /auth/login.json?version=2 (login)\n- POST /auth/refresh_token.json?version=2 (refresh)\n- GET /auth/curr_user.json (current user)\nToken sent via X-Client-Token header","status":"closed","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:08.358878117+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:26:32.668016856+01:00","closed_at":"2026-01-14T13:26:32.668016856+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-lpn","depends_on_id":"checkvist-api-ymg","type":"blocks","created_at":"2026-01-14T12:32:47.656124681+01:00","created_by":"Oliver Jakoubek"}]}
|
{"id":"checkvist-api-lpn","title":"Implement authentication with auto token renewal","description":"Add to client.go:\n- Authenticate(ctx context.Context) error - explicit login\n- refreshToken(ctx context.Context) error - token renewal\n- ensureAuthenticated(ctx context.Context) error - auto-auth before requests\n- CurrentUser(ctx context.Context) (*User, error) - get logged in user\n- Token management: store token and expiry, auto-refresh before expiry\n- Thread-safe token access using mutex\n- Support for optional 2FA token\nAPI endpoints:\n- POST /auth/login.json?version=2 (login)\n- POST /auth/refresh_token.json?version=2 (refresh)\n- GET /auth/curr_user.json (current user)\nToken sent via X-Client-Token header","status":"closed","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:08.358878117+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:26:32.668016856+01:00","closed_at":"2026-01-14T13:26:32.668016856+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-lpn","depends_on_id":"checkvist-api-ymg","type":"blocks","created_at":"2026-01-14T12:32:47.656124681+01:00","created_by":"Oliver Jakoubek"}]}
|
||||||
{"id":"checkvist-api-mnh","title":"Implement error types and sentinel errors","description":"Create errors.go with:\n- APIError struct (StatusCode, Message, RequestID, Err) with Error() and Unwrap() methods\n- Sentinel errors: ErrUnauthorized, ErrNotFound, ErrRateLimited, ErrBadRequest, ErrServerError\n- Helper function to create APIError from HTTP response","status":"closed","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:07.619359293+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:23:43.296883265+01:00","closed_at":"2026-01-14T13:23:43.296883265+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-mnh","depends_on_id":"checkvist-api-5wr","type":"blocks","created_at":"2026-01-14T12:32:46.754134799+01:00","created_by":"Oliver Jakoubek"}]}
|
{"id":"checkvist-api-mnh","title":"Implement error types and sentinel errors","description":"Create errors.go with:\n- APIError struct (StatusCode, Message, RequestID, Err) with Error() and Unwrap() methods\n- Sentinel errors: ErrUnauthorized, ErrNotFound, ErrRateLimited, ErrBadRequest, ErrServerError\n- Helper function to create APIError from HTTP response","status":"closed","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:07.619359293+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:23:43.296883265+01:00","closed_at":"2026-01-14T13:23:43.296883265+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-mnh","depends_on_id":"checkvist-api-5wr","type":"blocks","created_at":"2026-01-14T12:32:46.754134799+01:00","created_by":"Oliver Jakoubek"}]}
|
||||||
{"id":"checkvist-api-nrk","title":"Create README with quickstart","description":"Create README.md (in English) with:\n- Project description\n- Installation: go get code.beautifulmachines.dev/jakoubek/checkvist-api\n- Quick start example (init client, list checklists, create task)\n- API overview (Checklists, Tasks, Notes, Filters)\n- Builder pattern examples\n- Error handling examples\n- Configuration options\n- Link to GoDoc\n- License (MIT)","status":"open","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:38.724338606+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T12:31:38.724338606+01:00","dependencies":[{"issue_id":"checkvist-api-nrk","depends_on_id":"checkvist-api-c2k","type":"blocks","created_at":"2026-01-14T12:33:15.785698203+01:00","created_by":"Oliver Jakoubek"},{"issue_id":"checkvist-api-nrk","depends_on_id":"checkvist-api-rl9","type":"blocks","created_at":"2026-01-14T12:33:16.125115134+01:00","created_by":"Oliver Jakoubek"}]}
|
{"id":"checkvist-api-nrk","title":"Create README with quickstart","description":"Create README.md (in English) with:\n- Project description\n- Installation: go get code.beautifulmachines.dev/jakoubek/checkvist-api\n- Quick start example (init client, list checklists, create task)\n- API overview (Checklists, Tasks, Notes, Filters)\n- Builder pattern examples\n- Error handling examples\n- Configuration options\n- Link to GoDoc\n- License (MIT)","status":"closed","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:38.724338606+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:48:30.163762004+01:00","closed_at":"2026-01-14T13:48:30.163762004+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-nrk","depends_on_id":"checkvist-api-c2k","type":"blocks","created_at":"2026-01-14T12:33:15.785698203+01:00","created_by":"Oliver Jakoubek"},{"issue_id":"checkvist-api-nrk","depends_on_id":"checkvist-api-rl9","type":"blocks","created_at":"2026-01-14T12:33:16.125115134+01:00","created_by":"Oliver Jakoubek"}]}
|
||||||
{"id":"checkvist-api-rl9","title":"Implement Task operations","description":"Create tasks.go with TaskService:\n- client.Tasks(checklistID) returns TaskService\n- List(ctx) ([]Task, error) - GET /checklists/{id}/tasks.json\n- Get(ctx, taskID) (*Task, error) - GET /checklists/{id}/tasks/{task_id}.json (includes parent hierarchy)\n- Create(ctx, builder *TaskBuilder) (*Task, error) - POST /checklists/{id}/tasks.json\n- Update(ctx, taskID, opts) (*Task, error) - PUT /checklists/{id}/tasks/{task_id}.json\n- Delete(ctx, taskID) error - DELETE /checklists/{id}/tasks/{task_id}.json\n- Close(ctx, taskID) (*Task, error) - POST /checklists/{id}/tasks/{task_id}/close.json\n- Reopen(ctx, taskID) (*Task, error) - POST /checklists/{id}/tasks/{task_id}/reopen.json\n- Invalidate(ctx, taskID) (*Task, error) - POST /checklists/{id}/tasks/{task_id}/invalidate.json\nParse DueDate from DueDateRaw when retrieving tasks.","status":"closed","priority":0,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:30:53.90629838+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:39:29.443727155+01:00","closed_at":"2026-01-14T13:39:29.443727155+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-rl9","depends_on_id":"checkvist-api-8u6","type":"blocks","created_at":"2026-01-14T12:32:55.247292478+01:00","created_by":"Oliver Jakoubek"},{"issue_id":"checkvist-api-rl9","depends_on_id":"checkvist-api-lpn","type":"blocks","created_at":"2026-01-14T12:32:55.536931433+01:00","created_by":"Oliver Jakoubek"}]}
|
{"id":"checkvist-api-rl9","title":"Implement Task operations","description":"Create tasks.go with TaskService:\n- client.Tasks(checklistID) returns TaskService\n- List(ctx) ([]Task, error) - GET /checklists/{id}/tasks.json\n- Get(ctx, taskID) (*Task, error) - GET /checklists/{id}/tasks/{task_id}.json (includes parent hierarchy)\n- Create(ctx, builder *TaskBuilder) (*Task, error) - POST /checklists/{id}/tasks.json\n- Update(ctx, taskID, opts) (*Task, error) - PUT /checklists/{id}/tasks/{task_id}.json\n- Delete(ctx, taskID) error - DELETE /checklists/{id}/tasks/{task_id}.json\n- Close(ctx, taskID) (*Task, error) - POST /checklists/{id}/tasks/{task_id}/close.json\n- Reopen(ctx, taskID) (*Task, error) - POST /checklists/{id}/tasks/{task_id}/reopen.json\n- Invalidate(ctx, taskID) (*Task, error) - POST /checklists/{id}/tasks/{task_id}/invalidate.json\nParse DueDate from DueDateRaw when retrieving tasks.","status":"closed","priority":0,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:30:53.90629838+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:39:29.443727155+01:00","closed_at":"2026-01-14T13:39:29.443727155+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-rl9","depends_on_id":"checkvist-api-8u6","type":"blocks","created_at":"2026-01-14T12:32:55.247292478+01:00","created_by":"Oliver Jakoubek"},{"issue_id":"checkvist-api-rl9","depends_on_id":"checkvist-api-lpn","type":"blocks","created_at":"2026-01-14T12:32:55.536931433+01:00","created_by":"Oliver Jakoubek"}]}
|
||||||
{"id":"checkvist-api-tjk","title":"Implement TaskBuilder fluent interface","description":"Enhance task creation with builder pattern:\n- NewTask(content string) *TaskBuilder\n- WithTags(tags ...string) *TaskBuilder\n- WithDueDate(due DueDate) *TaskBuilder\n- WithPriority(p int) *TaskBuilder\n- WithParent(parentID int64) *TaskBuilder\n- WithPosition(pos int) *TaskBuilder\n- Build() returns parameters for API call\nTaskBuilder should be chainable and return itself for fluent usage:\n checkvist.NewTask(\"Content\").WithTags(\"tag1\").WithDueDate(checkvist.DueTomorrow).WithPriority(1)","status":"open","priority":1,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:30:55.929907579+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T12:30:55.929907579+01:00","dependencies":[{"issue_id":"checkvist-api-tjk","depends_on_id":"checkvist-api-rl9","type":"blocks","created_at":"2026-01-14T12:33:02.20339206+01:00","created_by":"Oliver Jakoubek"}]}
|
{"id":"checkvist-api-tjk","title":"Implement TaskBuilder fluent interface","description":"Enhance task creation with builder pattern:\n- NewTask(content string) *TaskBuilder\n- WithTags(tags ...string) *TaskBuilder\n- WithDueDate(due DueDate) *TaskBuilder\n- WithPriority(p int) *TaskBuilder\n- WithParent(parentID int64) *TaskBuilder\n- WithPosition(pos int) *TaskBuilder\n- Build() returns parameters for API call\nTaskBuilder should be chainable and return itself for fluent usage:\n checkvist.NewTask(\"Content\").WithTags(\"tag1\").WithDueDate(checkvist.DueTomorrow).WithPriority(1)","status":"open","priority":1,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:30:55.929907579+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T12:30:55.929907579+01:00","dependencies":[{"issue_id":"checkvist-api-tjk","depends_on_id":"checkvist-api-rl9","type":"blocks","created_at":"2026-01-14T12:33:02.20339206+01:00","created_by":"Oliver Jakoubek"}]}
|
||||||
{"id":"checkvist-api-v2f","title":"Write unit tests for Tasks","description":"Create tasks_test.go with tests:\n- TestTasks_List\n- TestTasks_Get\n- TestTasks_Get_WithParentHierarchy\n- TestTasks_Create\n- TestTasks_Create_WithBuilder\n- TestTasks_Update\n- TestTasks_Delete\n- TestTasks_Close\n- TestTasks_Reopen\n- TestTasks_Invalidate\n- TestDueDate_Parsing\nUse table-driven tests. Create testdata/tasks/ fixtures.","status":"closed","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:37.538754679+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:46:01.50434559+01:00","closed_at":"2026-01-14T13:46:01.50434559+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-v2f","depends_on_id":"checkvist-api-rl9","type":"blocks","created_at":"2026-01-14T12:33:13.81085058+01:00","created_by":"Oliver Jakoubek"}]}
|
{"id":"checkvist-api-v2f","title":"Write unit tests for Tasks","description":"Create tasks_test.go with tests:\n- TestTasks_List\n- TestTasks_Get\n- TestTasks_Get_WithParentHierarchy\n- TestTasks_Create\n- TestTasks_Create_WithBuilder\n- TestTasks_Update\n- TestTasks_Delete\n- TestTasks_Close\n- TestTasks_Reopen\n- TestTasks_Invalidate\n- TestDueDate_Parsing\nUse table-driven tests. Create testdata/tasks/ fixtures.","status":"closed","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-14T12:31:37.538754679+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-14T13:46:01.50434559+01:00","closed_at":"2026-01-14T13:46:01.50434559+01:00","close_reason":"Closed","dependencies":[{"issue_id":"checkvist-api-v2f","depends_on_id":"checkvist-api-rl9","type":"blocks","created_at":"2026-01-14T12:33:13.81085058+01:00","created_by":"Oliver Jakoubek"}]}
|
||||||
|
|
|
||||||
235
README.md
Normal file
235
README.md
Normal file
|
|
@ -0,0 +1,235 @@
|
||||||
|
# checkvist-api
|
||||||
|
|
||||||
|
A type-safe, idiomatic Go client library for the [Checkvist](https://checkvist.com/) API.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get code.beautifulmachines.dev/jakoubek/checkvist-api
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"code.beautifulmachines.dev/jakoubek/checkvist-api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Create a new client
|
||||||
|
client := checkvist.NewClient("your-email@example.com", "your-api-key")
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// List all checklists
|
||||||
|
checklists, err := client.Checklists().List(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cl := range checklists {
|
||||||
|
fmt.Printf("Checklist: %s (%d tasks)\n", cl.Name, cl.TaskCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new task
|
||||||
|
task, err := client.Tasks(checklists[0].ID).Create(ctx,
|
||||||
|
checkvist.NewTask("Buy groceries").
|
||||||
|
WithDueDate(checkvist.DueTomorrow).
|
||||||
|
WithPriority(1).
|
||||||
|
WithTags("shopping", "personal"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Created task: %s (ID: %d)\n", task.Content, task.ID)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Overview
|
||||||
|
|
||||||
|
### Checklists
|
||||||
|
|
||||||
|
```go
|
||||||
|
// List all checklists
|
||||||
|
checklists, err := client.Checklists().List(ctx)
|
||||||
|
|
||||||
|
// List archived checklists
|
||||||
|
archived, err := client.Checklists().ListWithOptions(ctx, checkvist.ListOptions{Archived: true})
|
||||||
|
|
||||||
|
// Get a single checklist
|
||||||
|
checklist, err := client.Checklists().Get(ctx, checklistID)
|
||||||
|
|
||||||
|
// Create a new checklist
|
||||||
|
checklist, err := client.Checklists().Create(ctx, "My New List")
|
||||||
|
|
||||||
|
// Update a checklist
|
||||||
|
checklist, err := client.Checklists().Update(ctx, checklistID, "New Name")
|
||||||
|
|
||||||
|
// Delete a checklist
|
||||||
|
err := client.Checklists().Delete(ctx, checklistID)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tasks
|
||||||
|
|
||||||
|
```go
|
||||||
|
// List all tasks in a checklist
|
||||||
|
tasks, err := client.Tasks(checklistID).List(ctx)
|
||||||
|
|
||||||
|
// Get a single task
|
||||||
|
task, err := client.Tasks(checklistID).Get(ctx, taskID)
|
||||||
|
|
||||||
|
// Create a task with the builder pattern
|
||||||
|
task, err := client.Tasks(checklistID).Create(ctx,
|
||||||
|
checkvist.NewTask("Task content").
|
||||||
|
WithParent(parentID). // Create as subtask
|
||||||
|
WithDueDate(checkvist.DueAt(time.Now().AddDate(0, 0, 7))).
|
||||||
|
WithPriority(1). // 1 = highest, 2 = high, 0 = normal
|
||||||
|
WithTags("work", "urgent"),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Update a task
|
||||||
|
content := "Updated content"
|
||||||
|
task, err := client.Tasks(checklistID).Update(ctx, taskID, checkvist.UpdateTaskRequest{
|
||||||
|
Content: &content,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Close/Reopen/Invalidate tasks
|
||||||
|
task, err := client.Tasks(checklistID).Close(ctx, taskID)
|
||||||
|
task, err := client.Tasks(checklistID).Reopen(ctx, taskID)
|
||||||
|
task, err := client.Tasks(checklistID).Invalidate(ctx, taskID)
|
||||||
|
|
||||||
|
// Delete a task
|
||||||
|
err := client.Tasks(checklistID).Delete(ctx, taskID)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notes (Comments)
|
||||||
|
|
||||||
|
```go
|
||||||
|
// List notes on a task
|
||||||
|
notes, err := client.Notes(checklistID, taskID).List(ctx)
|
||||||
|
|
||||||
|
// Create a note
|
||||||
|
note, err := client.Notes(checklistID, taskID).Create(ctx, "My comment")
|
||||||
|
|
||||||
|
// Update a note
|
||||||
|
note, err := client.Notes(checklistID, taskID).Update(ctx, noteID, "Updated comment")
|
||||||
|
|
||||||
|
// Delete a note
|
||||||
|
err := client.Notes(checklistID, taskID).Delete(ctx, noteID)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Due Dates
|
||||||
|
|
||||||
|
The library provides convenient due date helpers:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Predefined constants
|
||||||
|
checkvist.DueToday
|
||||||
|
checkvist.DueTomorrow
|
||||||
|
checkvist.DueNextWeek
|
||||||
|
checkvist.DueNextMonth
|
||||||
|
|
||||||
|
// From time.Time
|
||||||
|
checkvist.DueAt(time.Now().AddDate(0, 0, 7))
|
||||||
|
|
||||||
|
// Relative days
|
||||||
|
checkvist.DueInDays(5)
|
||||||
|
|
||||||
|
// Raw smart syntax
|
||||||
|
checkvist.DueString("^friday")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
The library provides structured error types for API errors:
|
||||||
|
|
||||||
|
```go
|
||||||
|
task, err := client.Tasks(checklistID).Get(ctx, taskID)
|
||||||
|
if err != nil {
|
||||||
|
// Check for specific error types
|
||||||
|
if errors.Is(err, checkvist.ErrNotFound) {
|
||||||
|
fmt.Println("Task not found")
|
||||||
|
} else if errors.Is(err, checkvist.ErrUnauthorized) {
|
||||||
|
fmt.Println("Invalid credentials")
|
||||||
|
} else if errors.Is(err, checkvist.ErrRateLimited) {
|
||||||
|
fmt.Println("Too many requests, please slow down")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get detailed error information
|
||||||
|
var apiErr *checkvist.APIError
|
||||||
|
if errors.As(err, &apiErr) {
|
||||||
|
fmt.Printf("Status: %d, Message: %s\n", apiErr.StatusCode, apiErr.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Available sentinel errors:
|
||||||
|
- `ErrUnauthorized` - Invalid credentials (HTTP 401)
|
||||||
|
- `ErrNotFound` - Resource not found (HTTP 404)
|
||||||
|
- `ErrRateLimited` - Rate limit exceeded (HTTP 429)
|
||||||
|
- `ErrBadRequest` - Invalid request (HTTP 400)
|
||||||
|
- `ErrServerError` - Server error (HTTP 5xx)
|
||||||
|
|
||||||
|
## Configuration Options
|
||||||
|
|
||||||
|
Customize the client with functional options:
|
||||||
|
|
||||||
|
```go
|
||||||
|
client := checkvist.NewClient("email", "api-key",
|
||||||
|
// Custom HTTP client
|
||||||
|
checkvist.WithHTTPClient(customHTTPClient),
|
||||||
|
|
||||||
|
// Custom timeout
|
||||||
|
checkvist.WithTimeout(60 * time.Second),
|
||||||
|
|
||||||
|
// Custom retry configuration
|
||||||
|
checkvist.WithRetryConfig(checkvist.RetryConfig{
|
||||||
|
MaxRetries: 5,
|
||||||
|
BaseDelay: 2 * time.Second,
|
||||||
|
MaxDelay: 60 * time.Second,
|
||||||
|
Jitter: true,
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Custom logger
|
||||||
|
checkvist.WithLogger(slog.New(slog.NewJSONHandler(os.Stdout, nil))),
|
||||||
|
|
||||||
|
// Custom base URL (for testing)
|
||||||
|
checkvist.WithBaseURL("https://custom-api.example.com"),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
The library handles authentication automatically:
|
||||||
|
- Authenticates on first API call
|
||||||
|
- Stores token securely
|
||||||
|
- Automatically refreshes token before expiry
|
||||||
|
- Thread-safe for concurrent use
|
||||||
|
|
||||||
|
You can also authenticate explicitly:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Standard authentication
|
||||||
|
err := client.Authenticate(ctx)
|
||||||
|
|
||||||
|
// With 2FA
|
||||||
|
err := client.AuthenticateWith2FA(ctx, "123456")
|
||||||
|
|
||||||
|
// Get current user info
|
||||||
|
user, err := client.CurrentUser(ctx)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
Full API documentation is available on [pkg.go.dev](https://pkg.go.dev/code.beautifulmachines.dev/jakoubek/checkvist-api).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License - see [LICENSE](LICENSE) file for details.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue