Skip to content

feat: [BREAKING] migrate from REST API to Sync API #263

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

This is the official TypeScript API client for the Todoist REST API.

> [!IMPORTANT]
> This library is currently being migrated from the Todoist REST API to the Todoist Sync API. As a result, parts of the documentation may be outdated. However, the client API remains consistent with the latest stable release, [v3.0.3](https://github.com/Doist/todoist-api-typescript/releases/tag/v3.0.3). Please note that some client methods may return unexpected data or encounter failures during this transition.

## Installation

```
Expand Down
24 changes: 14 additions & 10 deletions src/TodoistApi.comments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
DEFAULT_COMMENT,
DEFAULT_REQUEST_ID,
} from './testUtils/testDefaults'
import { getRestBaseUri, ENDPOINT_REST_COMMENTS } from './consts/endpoints'
import { getSyncBaseUri, ENDPOINT_REST_COMMENTS } from './consts/endpoints'
import { setupRestClientMock } from './testUtils/mocks'

function getTarget() {
Expand All @@ -17,16 +17,19 @@ function getTarget() {
describe('TodoistApi comment endpoints', () => {
describe('getComments', () => {
test('calls get request with expected params', async () => {
const getCommentsArgs = { projectId: '12' }
const requestMock = setupRestClientMock([DEFAULT_COMMENT])
const getCommentsArgs = { projectId: '12', limit: 10, cursor: '0' }
const requestMock = setupRestClientMock({
results: [DEFAULT_COMMENT],
nextCursor: '123',
})
const api = getTarget()

await api.getComments(getCommentsArgs)

expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'GET',
getRestBaseUri(),
getSyncBaseUri(),
ENDPOINT_REST_COMMENTS,
DEFAULT_AUTH_TOKEN,
getCommentsArgs,
Expand All @@ -40,12 +43,13 @@ describe('TodoistApi comment endpoints', () => {
COMMENT_WITH_OPTIONALS_AS_NULL_PROJECT,
COMMENT_WITH_ATTACHMENT_WITH_OPTIONALS_AS_NULL,
]
setupRestClientMock(expectedComments)
setupRestClientMock({ results: expectedComments, nextCursor: '123' })
const api = getTarget()

const comments = await api.getComments({ taskId: '12' })
const { results: comments, nextCursor } = await api.getComments({ taskId: '12' })

expect(comments).toEqual(expectedComments)
expect(nextCursor).toBe('123')
})
})

Expand All @@ -60,7 +64,7 @@ describe('TodoistApi comment endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'GET',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_COMMENTS}/${commentId}`,
DEFAULT_AUTH_TOKEN,
)
Expand Down Expand Up @@ -92,7 +96,7 @@ describe('TodoistApi comment endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'POST',
getRestBaseUri(),
getSyncBaseUri(),
ENDPOINT_REST_COMMENTS,
DEFAULT_AUTH_TOKEN,
addCommentArgs,
Expand Down Expand Up @@ -126,7 +130,7 @@ describe('TodoistApi comment endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'POST',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_COMMENTS}/${taskId}`,
DEFAULT_AUTH_TOKEN,
updateCommentArgs,
Expand Down Expand Up @@ -156,7 +160,7 @@ describe('TodoistApi comment endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'DELETE',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_COMMENTS}/${taskId}`,
DEFAULT_AUTH_TOKEN,
undefined,
Expand Down
33 changes: 22 additions & 11 deletions src/TodoistApi.labels.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TodoistApi } from '.'
import { DEFAULT_AUTH_TOKEN, DEFAULT_LABEL, DEFAULT_REQUEST_ID } from './testUtils/testDefaults'
import { getRestBaseUri, ENDPOINT_REST_LABELS } from './consts/endpoints'
import { getSyncBaseUri, ENDPOINT_REST_LABELS } from './consts/endpoints'
import { setupRestClientMock } from './testUtils/mocks'

function getTarget() {
Expand All @@ -19,7 +19,7 @@ describe('TodoistApi label endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'GET',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_LABELS}/${labelId}`,
DEFAULT_AUTH_TOKEN,
)
Expand All @@ -37,28 +37,39 @@ describe('TodoistApi label endpoints', () => {

describe('getLabels', () => {
test('calls get on labels endpoint', async () => {
const requestMock = setupRestClientMock([DEFAULT_LABEL])
const requestMock = setupRestClientMock({
results: [DEFAULT_LABEL],
nextCursor: '123',
})
const api = getTarget()

await api.getLabels()
await api.getLabels({ limit: 10, cursor: '0' })

expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'GET',
getRestBaseUri(),
getSyncBaseUri(),
ENDPOINT_REST_LABELS,
DEFAULT_AUTH_TOKEN,
{
limit: 10,
cursor: '0',
},
)
})

test('returns result from rest client', async () => {
const labels = [DEFAULT_LABEL]
setupRestClientMock(labels)
setupRestClientMock({
results: [DEFAULT_LABEL],
nextCursor: '123',
})
const api = getTarget()

const response = await api.getLabels()
const { results, nextCursor } = await api.getLabels()

expect(response).toEqual(labels)
expect(results).toEqual(labels)
expect(nextCursor).toBe('123')
})
})

Expand All @@ -76,7 +87,7 @@ describe('TodoistApi label endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'POST',
getRestBaseUri(),
getSyncBaseUri(),
ENDPOINT_REST_LABELS,
DEFAULT_AUTH_TOKEN,
DEFAULT_ADD_LABEL_ARGS,
Expand Down Expand Up @@ -109,7 +120,7 @@ describe('TodoistApi label endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'POST',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_LABELS}/${labelId}`,
DEFAULT_AUTH_TOKEN,
DEFAULT_UPDATE_LABEL_ARGS,
Expand Down Expand Up @@ -139,7 +150,7 @@ describe('TodoistApi label endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'DELETE',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_LABELS}/${labelId}`,
DEFAULT_AUTH_TOKEN,
undefined,
Expand Down
43 changes: 26 additions & 17 deletions src/TodoistApi.projects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
PROJECT_WITH_OPTIONALS_AS_NULL,
} from './testUtils/testDefaults'
import {
getRestBaseUri,
getSyncBaseUri,
ENDPOINT_REST_PROJECTS,
ENDPOINT_REST_PROJECT_COLLABORATORS,
} from './consts/endpoints'
Expand All @@ -29,7 +29,7 @@ describe('TodoistApi project endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'GET',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_PROJECTS}/${projectId}`,
DEFAULT_AUTH_TOKEN,
)
Expand All @@ -47,28 +47,34 @@ describe('TodoistApi project endpoints', () => {

describe('getProjects', () => {
test('calls get on projects endpoint', async () => {
const requestMock = setupRestClientMock([DEFAULT_PROJECT])
const requestMock = setupRestClientMock({
results: [DEFAULT_PROJECT],
nextCursor: '123',
})
const api = getTarget()

await api.getProjects()
const args = { limit: 10, cursor: '0' }
await api.getProjects(args)

expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'GET',
getRestBaseUri(),
getSyncBaseUri(),
ENDPOINT_REST_PROJECTS,
DEFAULT_AUTH_TOKEN,
args,
)
})

test('returns result from rest client', async () => {
const projects = [DEFAULT_PROJECT, PROJECT_WITH_OPTIONALS_AS_NULL]
setupRestClientMock(projects)
setupRestClientMock({ results: projects, nextCursor: '123' })
const api = getTarget()

const response = await api.getProjects()
const { results, nextCursor } = await api.getProjects()

expect(response).toEqual(projects)
expect(results).toEqual(projects)
expect(nextCursor).toBe('123')
})
})

Expand All @@ -86,7 +92,7 @@ describe('TodoistApi project endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'POST',
getRestBaseUri(),
getSyncBaseUri(),
ENDPOINT_REST_PROJECTS,
DEFAULT_AUTH_TOKEN,
DEFAULT_ADD_PROJECT_ARGS,
Expand Down Expand Up @@ -117,7 +123,7 @@ describe('TodoistApi project endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'POST',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_PROJECTS}/${projectId}`,
DEFAULT_AUTH_TOKEN,
updateArgs,
Expand Down Expand Up @@ -147,7 +153,7 @@ describe('TodoistApi project endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'DELETE',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_PROJECTS}/${projectId}`,
DEFAULT_AUTH_TOKEN,
undefined,
Expand All @@ -170,27 +176,30 @@ describe('TodoistApi project endpoints', () => {
const users = [DEFAULT_USER]

test('calls get on expected endpoint', async () => {
const requestMock = setupRestClientMock(users)
const requestMock = setupRestClientMock({ results: users, nextCursor: '123' })
const api = getTarget()

await api.getProjectCollaborators(projectId)
const args = { limit: 10, cursor: '0' }
await api.getProjectCollaborators(projectId, args)

expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'GET',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_PROJECTS}/${projectId}/${ENDPOINT_REST_PROJECT_COLLABORATORS}`,
DEFAULT_AUTH_TOKEN,
args,
)
})

test('returns result from rest client', async () => {
setupRestClientMock(users)
setupRestClientMock({ results: users, nextCursor: '123' })
const api = getTarget()

const returnedUsers = await api.getProjectCollaborators(projectId)
const { results, nextCursor } = await api.getProjectCollaborators(projectId)

expect(returnedUsers).toEqual(users)
expect(results).toEqual(users)
expect(nextCursor).toBe('123')
})
})
})
29 changes: 17 additions & 12 deletions src/TodoistApi.sections.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TodoistApi } from '.'
import { DEFAULT_AUTH_TOKEN, DEFAULT_REQUEST_ID, DEFAULT_SECTION } from './testUtils/testDefaults'
import { getRestBaseUri, ENDPOINT_REST_SECTIONS } from './consts/endpoints'
import { getSyncBaseUri, ENDPOINT_REST_SECTIONS } from './consts/endpoints'
import { setupRestClientMock } from './testUtils/mocks'

function getTarget() {
Expand All @@ -19,7 +19,7 @@ describe('TodoistApi section endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'GET',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_SECTIONS}/${sectionId}`,
DEFAULT_AUTH_TOKEN,
)
Expand All @@ -38,29 +38,34 @@ describe('TodoistApi section endpoints', () => {
describe('getSections', () => {
test('calls get on sections endpoint', async () => {
const projectId = '123'
const requestMock = setupRestClientMock([DEFAULT_SECTION])
const requestMock = setupRestClientMock({
results: [DEFAULT_SECTION],
nextCursor: '123',
})
const api = getTarget()

await api.getSections(projectId)
const args = { projectId, limit: 10, cursor: '0' }
await api.getSections(args)

expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'GET',
getRestBaseUri(),
getSyncBaseUri(),
ENDPOINT_REST_SECTIONS,
DEFAULT_AUTH_TOKEN,
{ projectId },
args,
)
})

test('returns result from rest client', async () => {
const sections = [DEFAULT_SECTION]
setupRestClientMock(sections)
setupRestClientMock({ results: sections, nextCursor: '123' })
const api = getTarget()

const response = await api.getSections()
const { results, nextCursor } = await api.getSections({ projectId: '123' })

expect(response).toEqual(sections)
expect(results).toEqual(sections)
expect(nextCursor).toBe('123')
})
})

Expand All @@ -79,7 +84,7 @@ describe('TodoistApi section endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'POST',
getRestBaseUri(),
getSyncBaseUri(),
ENDPOINT_REST_SECTIONS,
DEFAULT_AUTH_TOKEN,
DEFAULT_ADD_SECTION_ARGS,
Expand Down Expand Up @@ -110,7 +115,7 @@ describe('TodoistApi section endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'POST',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_SECTIONS}/${sectionId}`,
DEFAULT_AUTH_TOKEN,
DEFAULT_UPDATE_SECTION_ARGS,
Expand Down Expand Up @@ -140,7 +145,7 @@ describe('TodoistApi section endpoints', () => {
expect(requestMock).toBeCalledTimes(1)
expect(requestMock).toBeCalledWith(
'DELETE',
getRestBaseUri(),
getSyncBaseUri(),
`${ENDPOINT_REST_SECTIONS}/${sectionId}`,
DEFAULT_AUTH_TOKEN,
undefined,
Expand Down
Loading
Loading