1
0
Fork
You've already forked todoist-api
0
backend library for the terminalist project, written in rust
  • Rust 98.5%
  • Makefile 1.5%
Romain Bertrand 898767bf5e
Merge pull request #7 from romaintb/fix/readme
Minor adjustments to README.md
2025年09月10日 15:17:32 +02:00
.github/workflows Initial release 2025年08月15日 20:00:13 +02:00
src Fix linting errors 2025年09月10日 14:14:59 +02:00
tests Fix linting errors 2025年09月10日 14:14:59 +02:00
.gitignore Initial release 2025年08月15日 20:00:13 +02:00
Cargo.toml Prepare for v0.3 2025年08月31日 11:50:50 +02:00
CHANGELOG.md Adjusted CHANGELOG.md to reflect changes in v0.3.0 2025年09月10日 14:57:16 +02:00
clippy.toml Linting and formating 2025年08月15日 20:03:24 +02:00
LICENSE Rename to todoist-api, todoist-rs was taken 2025年08月15日 20:16:08 +02:00
Makefile Initial release 2025年08月15日 20:00:13 +02:00
README.md Minor adjustments to README.md 2025年09月10日 15:12:14 +02:00
rustfmt.toml Linting and formating 2025年08月15日 20:03:24 +02:00

Todoist-api

Crates.io Version CI Documentation License: MIT Rust Version Todoist API

A comprehensive Rust wrapper for the Todoist REST API v2, providing a clean and ergonomic interface for managing tasks, projects, labels, sections, and comments.

Features

  • 🚀 Async/await support - Built with Tokio for high-performance async operations
  • 📝 Full CRUD operations - Create, read, update, and delete all Todoist entities
  • 🏗️ Project management - Complete project lifecycle management
  • 🏷️ Label support - Full label operations with filtering
  • 📋 Section management - Organize projects with sections
  • 💬 Comment system - Add and manage comments on tasks and projects
  • 🔍 Advanced filtering - Filter tasks, projects, and labels with pagination
  • 🔒 Type safety - Full Rust type safety with Serde serialization
  • 🛡️ Error handling - Comprehensive error handling with specific error types and rate limiting support
  • 📚 Well documented - Extensive documentation

Installation

Add this to your Cargo.toml:

[dependencies]
todoist-api = "0.3.0"

Quick Start

usetodoist_api::TodoistWrapper;usetodoist_api::models::CreateTaskArgs;#[tokio::main]asyncfn main()-> Result<(),Box<dynstd::error::Error>>{// Create a new Todoist client
lettodoist=TodoistWrapper::new("your-api-token".to_string());// Get all tasks
lettasks=todoist.get_tasks().await?;println!("Found {} tasks",tasks.len());// Create a new task
letargs=CreateTaskArgs{content: "Buy groceries".to_string(),project_id: None,..Default::default()};letnew_task=todoist.create_task(&args).await?;println!("Created task: {}",new_task.content);// Complete a task
todoist.complete_task(&new_task.id).await?;println!("Task completed!");Ok(())}

Error Handling

The library provides comprehensive error handling with specific error types that allow you to handle different scenarios appropriately:

usetodoist_api::{TodoistWrapper,TodoistError,TodoistResult};#[tokio::main]asyncfn main()-> Result<(),Box<dynstd::error::Error>>{lettodoist=TodoistWrapper::new("your-api-token".to_string());matchtodoist.get_projects().await{Ok(projects)=>println!("Found {} projects",projects.len()),Err(TodoistError::RateLimited{retry_after,message})=>{println!("Rate limited: {} (retry after {} seconds)",message,retry_after.unwrap_or(0));// Handle rate limiting - wait and retry
}Err(TodoistError::AuthenticationError{message})=>{println!("Authentication failed: {}",message);// Handle authentication issues
}Err(TodoistError::NotFound{resource_type,resource_id,message})=>{println!("Resource not found: {} (ID: {:?}) - {}",resource_type,resource_id,message);// Handle missing resources
}Err(TodoistError::EmptyResponse{endpoint,message})=>{println!("Empty response from {}: {}",endpoint,message);// Handle unexpected empty responses
}Err(e)=>println!("Other error: {}",e),}Ok(())}

Rate Limiting

The library automatically detects rate limiting (HTTP 429) and provides retry information:

usestd::time::Duration;// Handle rate limiting with automatic retry
asyncfn get_tasks_with_retry(todoist: &TodoistWrapper)-> TodoistResult<Vec<Task>>{letmutattempts=0;letmax_attempts=3;loop{attempts+=1;letresult=todoist.get_tasks().await;matchresult{Ok(tasks)=>returnOk(tasks),Err(TodoistError::RateLimited{retry_after,message})ifattempts<max_attempts=>{letdelay=retry_after.unwrap_or(60);println!("Rate limited (attempt {}/{}): {}. Waiting {} seconds...",attempts,max_attempts,message,delay);tokio::time::sleep(Duration::from_secs(delay)).await;continue;}Err(e)=>returnErr(e),}}}

Error Types

  • RateLimited - API rate limiting with retry information
  • AuthenticationError - Invalid or expired API token
  • AuthorizationError - Insufficient permissions
  • NotFound - Resource not found
  • ValidationError - Invalid request parameters
  • ServerError - Todoist server errors (5xx)
  • NetworkError - Network/connection issues
  • ParseError - Response parsing failures
  • EmptyResponse - Unexpected empty API responses
  • Generic - Other errors with optional status codes

API Reference

Creating a Client

lettodoist=TodoistWrapper::new("your-api-token".to_string());

Task Operations

// Get all tasks
lettasks=todoist.get_tasks().await?;// Get a specific task
lettask=todoist.get_task("task_id").await?;// Get tasks for a specific project
letproject_tasks=todoist.get_tasks_for_project("project_id").await?;// Get tasks by filter query
letfilter_args=TaskFilterArgs{query: "today".to_string(),lang: Some("en".to_string()),limit: Some(10),cursor: None,};letfiltered_tasks=todoist.get_tasks_by_filter(&filter_args).await?;// Create a simple task
letargs=CreateTaskArgs{content: "Task content".to_string(),project_id: Some("project_id".to_string()),..Default::default()};lettask=todoist.create_task(&args).await?;// Create a task with full options
letcreate_args=CreateTaskArgs{content: "Complex task".to_string(),description: Some("Task description".to_string()),project_id: Some("project_id".to_string()),priority: Some(3),due_string: Some("tomorrow at 12:00".to_string()),labels: Some(vec!["important".to_string()]),..Default::default()};lettask=todoist.create_task(&create_args).await?;// Update a task
letupdate_args=UpdateTaskArgs{content: Some("Updated content".to_string()),priority: Some(4),due_string: Some("next week".to_string()),..Default::default()};letupdated_task=todoist.update_task("task_id",&update_args).await?;// Complete a task
todoist.complete_task("task_id").await?;// Reopen a completed task
todoist.reopen_task("task_id").await?;// Delete a task
todoist.delete_task("task_id").await?;

Project Operations

// Get all projects
letprojects=todoist.get_projects().await?;// Get a specific project
letproject=todoist.get_project("project_id").await?;// Get projects with filtering
letfilter_args=ProjectFilterArgs{limit: Some(20),cursor: None,};letfiltered_projects=todoist.get_projects_filtered(&filter_args).await?;// Create a new project
letcreate_args=CreateProjectArgs{name: "New Project".to_string(),color: Some("blue".to_string()),is_favorite: Some(true),view_style: Some("list".to_string()),parent_id: None,};letproject=todoist.create_project(&create_args).await?;// Update a project
letupdate_args=UpdateProjectArgs{name: Some("Updated Project Name".to_string()),color: Some("red".to_string()),is_favorite: Some(false),view_style: Some("board".to_string()),};letupdated_project=todoist.update_project("project_id",&update_args).await?;// Delete a project
todoist.delete_project("project_id").await?;

Label Operations

// Get all labels
letlabels=todoist.get_labels().await?;// Get a specific label
letlabel=todoist.get_label("label_id").await?;// Get labels with filtering
letfilter_args=LabelFilterArgs{limit: Some(50),cursor: None,};letfiltered_labels=todoist.get_labels_filtered(&filter_args).await?;// Create a new label
letcreate_args=CreateLabelArgs{name: "Important".to_string(),color: Some("red".to_string()),order: Some(1),is_favorite: Some(true),};letlabel=todoist.create_label(&create_args).await?;// Update a label
letupdate_args=UpdateLabelArgs{name: Some("Very Important".to_string()),color: Some("dark_red".to_string()),order: Some(0),is_favorite: Some(true),};letupdated_label=todoist.update_label("label_id",&update_args).await?;// Delete a label
todoist.delete_label("label_id").await?;

Section Operations

// Get all sections
letsections=todoist.get_sections().await?;// Get a specific section
letsection=todoist.get_section("section_id").await?;// Get sections for a project
letfilter_args=SectionFilterArgs{project_id: Some("project_id".to_string()),limit: Some(20),cursor: None,};letproject_sections=todoist.get_sections_filtered(&filter_args).await?;// Create a new section
letcreate_args=CreateSectionArgs{name: "New Section".to_string(),project_id: "project_id".to_string(),order: Some(1),};letsection=todoist.create_section(&create_args).await?;// Update a section
letupdate_args=UpdateSectionArgs{name: "Updated Section Name".to_string(),};letupdated_section=todoist.update_section("section_id",&update_args).await?;// Delete a section
todoist.delete_section("section_id").await?;

Comment Operations

// Get all comments
letcomments=todoist.get_comments().await?;// Get a specific comment
letcomment=todoist.get_comment("comment_id").await?;// Get comments for a task
letfilter_args=CommentFilterArgs{task_id: Some("task_id".to_string()),project_id: None,limit: Some(20),cursor: None,};lettask_comments=todoist.get_comments_filtered(&filter_args).await?;// Create a new comment
letcreate_args=CreateCommentArgs{content: "This is a comment".to_string(),task_id: Some("task_id".to_string()),project_id: None,attachment: None,};letcomment=todoist.create_comment(&create_args).await?;// Update a comment
letupdate_args=UpdateCommentArgs{content: "Updated comment content".to_string(),};letupdated_comment=todoist.update_comment("comment_id",&update_args).await?;// Delete a comment
todoist.delete_comment("comment_id").await?;

Data Models

The library provides comprehensive data models for all Todoist entities:

  • Task - Complete task information with all fields
  • Project - Project details and metadata
  • Label - Label information and styling
  • Section - Section organization within projects
  • Comment - Comment system for tasks and projects
  • Attachment - File attachments for comments
  • User - User information and preferences
  • Due - Due date and time information
  • Deadline - Deadline information
  • Duration - Task duration tracking

Argument Types

For flexible API operations, the library provides argument types:

  • CreateTaskArgs - Full task creation options
  • UpdateTaskArgs - Task update parameters
  • CreateProjectArgs - Project creation options
  • UpdateProjectArgs - Project update parameters
  • CreateLabelArgs - Label creation options
  • UpdateLabelArgs - Label update parameters
  • CreateSectionArgs - Section creation options
  • UpdateSectionArgs - Section update parameters
  • CreateCommentArgs - Comment creation options
  • UpdateCommentArgs - Comment update parameters

Filter Types

For advanced querying and pagination:

  • TaskFilterArgs - Task filtering and pagination
  • ProjectFilterArgs - Project filtering and pagination
  • LabelFilterArgs - Label filtering and pagination
  • SectionFilterArgs - Section filtering and pagination
  • CommentFilterArgs - Comment filtering and pagination

Advanced Error Handling

All operations return TodoistResult<T> with specific error types for precise error handling:

usetodoist_api::{TodoistWrapper,TodoistError};matchtodoist.get_tasks().await{Ok(tasks)=>println!("Found {} tasks",tasks.len()),Err(TodoistError::RateLimited{retry_after,message})=>{println!("Rate limited: {} (retry after {} seconds)",message,retry_after.unwrap_or(0));// Handle rate limiting - wait and retry
}Err(TodoistError::AuthenticationError{message})=>{eprintln!("Authentication failed: {}",message);// Handle authentication issues
}Err(TodoistError::EmptyResponse{endpoint,message})=>{eprintln!("Empty response from {}: {}",endpoint,message);// Handle unexpected empty responses
}Err(e)=>eprintln!("Other error: {}",e),}

Error Types

The library provides specific error types for different scenarios:

  • RateLimited - API rate limiting with retry information
  • AuthenticationError - Invalid or expired API token
  • AuthorizationError - Insufficient permissions
  • NotFound - Resource not found
  • ValidationError - Invalid request parameters
  • ServerError - Todoist server errors (5xx)
  • NetworkError - Network/connection issues
  • ParseError - Response parsing failures
  • EmptyResponse - Unexpected empty API responses
  • Generic - Other errors with optional status codes

Configuration

The library uses sensible defaults:

  • 10-second timeout for HTTP requests
  • Fallback to default client if custom client creation fails
  • Bearer token authentication
  • Comprehensive error handling with rate limiting detection

Testing

The library includes a comprehensive test suite covering all functionality:

Test Coverage

  • Unit Tests: 47 tests covering all models, argument types, and core functionality
  • Integration Tests: 10 tests for complete workflows (can be run with real API access)

Running Tests

# Run all tests
cargo test
# Run only unit tests (no API access required)
cargo test --lib
# Run specific test suites
cargo test models_tests
cargo test wrapper_tests
cargo test integration_tests
# Run with verbose output
cargo test -- --nocapture
# Run ignored tests (requires API token)
cargo test -- --ignored

Test Configuration

Set the following environment variables to run integration tests:

export TODOIST_API_TOKEN="your-api-token"
export RUN_INTEGRATION_TESTS=true

Test Structure

tests/
├── models_tests.rs # Data model validation tests
├── wrapper_tests.rs # API wrapper functionality tests
├── integration_tests.rs # End-to-end workflow tests
├── common/
│ └── mod.rs # Test utilities and helpers
└── config.rs # Test configuration management

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

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

Changelog

For detailed release notes and version history, see CHANGELOG.md.

Roadmap

  • Task filtering and search
  • Complete API coverage
  • Advanced filtering and pagination
  • Section and comment management
  • OAuth2 authentication support
  • Webhook support
  • Rate limiting and retry logic
  • Batch operations