Skip to content

Commit

Permalink
✨ feat: add GET /tasks/:id route
Browse files Browse the repository at this point in the history
See https://stackoverflow.com/a/11760249 why we return 404 when ID not matching any task (instead of 200 or 202 or 204)
  • Loading branch information
jbuget committed Feb 8, 2022
1 parent de0ed63 commit eeb6484
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/domain/entities/TaskRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ export interface TaskRepository {
findAll(): Promise<TaskList>;

save(task: Task): Promise<Task>;

findById(id: number): Promise<Task|null>;
}
10 changes: 10 additions & 0 deletions src/domain/usecases/queries/get_task_by_id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { TaskRepository } from '../../entities/TaskRepository';
import { Task } from '../../entities/Task';

async function getTaskById(id: number, taskRepository: TaskRepository): Promise<Task | null> {
return await taskRepository.findById(id);
}

export {
getTaskById
};
18 changes: 15 additions & 3 deletions src/infrastructure/app.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import fastify, { FastifyInstance } from 'fastify';
import fastify, { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
import { listTasks } from '../domain/usecases/queries/list_tasks';
import { createTask } from '../domain/usecases/commands/create_task';
import { TaskRepository } from '../domain/entities/TaskRepository';
import { container } from './container';
import { getTaskById } from '../domain/usecases/queries/get_task_by_id';

function build(): FastifyInstance {
const logger = container.resolve('logger');
Expand All @@ -29,8 +30,19 @@ function build(): FastifyInstance {
});

// Get a task
server.get('/tasks/:id', async function (request, reply) {
reply.code(501).send();
server.get('/tasks/:id', async function (request: FastifyRequest<any>, reply: FastifyReply<any>) {
const taskId = parseInt(request.params.id);
if (isNaN(taskId)) {
reply.code(429).send();
} else {
const taskRepository: TaskRepository = container.resolve('taskRepository');
const task = await getTaskById(taskId, taskRepository);
if (!task) {
reply.code(404).send();
} else {
return task;
}
}
});

// Update a task
Expand Down
19 changes: 19 additions & 0 deletions src/infrastructure/repositories/TaskRepositorySql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,23 @@ export class TaskRepositorySql implements TaskRepository {
}
return domainTask;
}

async findById(id: number): Promise<Task | null> {
const prisma = this.prisma;
try {
const prismaTask = await prisma.task.findUnique({ where: { id } });
if (prismaTask) {
return new Task({
id: prismaTask.id,
content: prismaTask.content,
createdAt: prismaTask.createdAt,
updatedAt: prismaTask.updatedAt,
status: prismaTask.status as Status
});
}
} finally {
await prisma.$disconnect();
}
return null;
}
}
3 changes: 3 additions & 0 deletions test/domain/usecases/commands/create_task.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ describe('domain.usecases.commands.create_task', function () {
const stubbedSavedTask: Task = new Task({ id: 1, createdAt: now, content: params.content });

const taskRepository: TaskRepository = {
async findById(id: number): Promise<Task | null> {
return null;
},
async findAll(): Promise<TaskList> {
return new TaskList();
},
Expand Down
3 changes: 3 additions & 0 deletions test/domain/usecases/queries/list_tasks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ describe('domain.usecases.queries.list_tasks', function () {
const taskList: TaskList = new TaskList([task1, task2]);

const taskRepository: TaskRepository = {
async findById(id: number): Promise<Task | null> {
return null;
},
async save(task: Task): Promise<Task> {
return task;
},
Expand Down
49 changes: 48 additions & 1 deletion test/infrastructure/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('API', () => {
});

describe('GET /', () => {
it('should returns the list of all stored Tasks', async () => {
it('should return the list of all stored Tasks', async () => {
// given
const prisma = getPrismaClient();
await prisma.task.createMany({
Expand Down Expand Up @@ -92,5 +92,52 @@ describe('API', () => {
expect(json.updatedAt).toBeDefined();
});
});

describe('GET /:id', () => {
it('should return 200 with the task matching the given ID', async () => {
// given
const prisma = getPrismaClient();
await prisma.task.create({
data: {
id: 1,
content: 'Task 1 content',
status: 'DONE',
createdAt: new Date('2021-11-09T17:08:02.865Z'),
updatedAt: new Date('2021-11-09T17:08:02.866Z')
}
});

// when
const response = await server.inject({ method: 'GET', url: '/tasks/1' });

// then
expect(response.statusCode).toBe(200);
expect(response.json()).toStrictEqual({
content: 'Task 1 content',
createdAt: '2021-11-09T17:08:02.865Z',
id: 1,
status: 'DONE',
updatedAt: '2021-11-09T17:08:02.866Z'
});
});

it('should return 404 when no task ID matches the given ID', async () => {
// when
const response = await server.inject({ method: 'GET', url: '/tasks/999999' });

// then
expect(response.statusCode).toBe(404);
});

it('should return 429 when the given ID is not a number', async () => {
// given

// when
const response = await server.inject({ method: 'GET', url: '/tasks/bad_id' });

// then
expect(response.statusCode).toBe(429);
});
});
});
});

0 comments on commit eeb6484

Please sign in to comment.