Implemented the GET /images endpoint with corresponding params #20
|
@ -1,6 +1,7 @@
|
|||
import { Request, Response } from "express";
|
||||
import imageService from "../services/ImageService";
|
||||
import mongoose, { mongo } from "mongoose";
|
||||
import { Image } from "../models/ImageModel";
|
||||
|
||||
class ImageController {
|
||||
async getImageById(req: Request, res: Response) {
|
||||
|
@ -20,12 +21,22 @@ class ImageController {
|
|||
}
|
||||
}
|
||||
|
||||
async getAllImages(_: Request, res: Response): Promise<void> {
|
||||
async getAllImages(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const images = await imageService.findAll();
|
||||
if (req.query.status !== undefined && !["consumed", "unavailable", "available"].includes(req.query.status as string)) {
|
||||
throw TypeError("if present, `status` should have the values `consumed`, `unavailable`, or `available`")
|
||||
}
|
||||
const limit = req.query.limit ? Number(req.query.limit) : undefined;
|
||||
const status = req.query.status ? req.query.status as Image["status"] : undefined;
|
||||
|
||||
const images = await imageService.findAll(limit, status);
|
||||
res.json({ images });
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: "Internal Server Error" });
|
||||
if (error instanceof TypeError) {
|
||||
res.status(400).json({ error });
|
||||
} else {
|
||||
res.status(500).json({ error: "Internal Server Error" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +58,7 @@ class ImageController {
|
|||
res.status(400).json({ error: error.message });
|
||||
} else {
|
||||
// Return 500 in other case
|
||||
res.status(500).json({ error: error });
|
||||
res.status(500).json({ error });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import mongoose, { Document } from "mongoose";
|
||||
|
||||
export interface Image extends Document {
|
||||
url: String;
|
||||
enum: "consumed" | "unavailable" | "available";
|
||||
tags?: String[];
|
||||
url: string;
|
||||
status: "consumed" | "unavailable" | "available";
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
const ImageSchema = new mongoose.Schema(
|
||||
|
|
|
@ -5,10 +5,23 @@ class ImageService {
|
|||
const image = await imageModel.findOne({ _id: id });
|
||||
return image;
|
||||
}
|
||||
async findAll(): Promise<Image[]> {
|
||||
const allImages = await imageModel.find();
|
||||
|
||||
async findAll(limit?: number, status?: Image["status"]): Promise<Image[]> {
|
||||
const typeError = TypeError("if present, `limit` must be a non-negative integer");
|
||||
const filter = status !== undefined ? { status } : {};
|
||||
let query = imageModel.find(filter);
|
||||
if (limit !== undefined) {
|
||||
if (Number.isInteger(limit)) {
|
||||
if (limit > 0) query = query.limit(limit);
|
||||
else if (limit < 0) throw typeError;
|
||||
} else {
|
||||
throw typeError;
|
||||
}
|
||||
}
|
||||
const allImages = await query;
|
||||
return allImages;
|
||||
}
|
||||
|
||||
async add(image: Image): Promise<Image> {
|
||||
const newImage = await imageModel.create(image);
|
||||
return newImage;
|
||||
|
|
|
@ -3,6 +3,8 @@ import request, { Response } from "supertest";
|
|||
import app, { startApp } from "../src/app";
|
||||
import imageService from "../src/services/ImageService";
|
||||
import populateDatabase from "./populateDatabase";
|
||||
import { Image } from "../src/models/ImageModel";
|
||||
import { faker } from "@faker-js/faker";
|
||||
|
||||
const imageServiceOriginal = imageService;
|
||||
|
||||
|
@ -73,7 +75,7 @@ describe("GET /images works properly", async () => {
|
|||
it("should return 500 for an error on the service", async () => {
|
||||
mock.module("../src/services/ImageService", () => ({
|
||||
default: {
|
||||
add: () => {
|
||||
findAll: () => {
|
||||
throw new Error("This is an expected testing error");
|
||||
},
|
||||
},
|
||||
|
@ -83,6 +85,68 @@ describe("GET /images works properly", async () => {
|
|||
|
||||
expect(res.status).toBe(500);
|
||||
});
|
||||
|
||||
it("should return 400 for an invalid status param value", async () => {
|
||||
const res = await request(app).get("/images?status=foo");
|
||||
expect(res.statusCode).toBe(400);
|
||||
});
|
||||
|
||||
it("should return 200 for a request with valid status param", async () => {
|
||||
const status = faker.helpers.arrayElement(["consumed", "available", "unavailable"])
|
||||
const res = await request(app).get(`/images?status=${status}`);
|
||||
expect(res.statusCode).toBe(200);
|
||||
});
|
||||
|
||||
it("should only have the requested status in the images", async () => {
|
||||
const status = faker.helpers.arrayElement(["consumed", "available", "unavailable"])
|
||||
const res = await request(app).get(`/images?status=${status}`);
|
||||
expect(res.body.images
|
||||
.map((image: Image) => image.status)
|
||||
.every((imageStatus: string) => imageStatus === status)).toBeTrue();
|
||||
});
|
||||
|
||||
it("should return 400 for a floating point value in limit value", async () => {
|
||||
const res = await request(app).get("/images?limit=2.4");
|
||||
expect(res.statusCode).toBe(400);
|
||||
});
|
||||
|
||||
it("should return 400 for a negative value in limit value", async () => {
|
||||
const res = await request(app).get("/images?limit=-1");
|
||||
expect(res.statusCode).toBe(400);
|
||||
});
|
||||
|
||||
it("should return 400 for a NaN limit value", async () => {
|
||||
const res = await request(app).get("/images?limit=foo");
|
||||
expect(res.statusCode).toBe(400);
|
||||
});
|
||||
|
||||
it("should return 200 for a request with valid limit param", async () => {
|
||||
const limit = faker.number.int({ min: 5, max: 50 });
|
||||
const res = await request(app).get(`/images?limit=${limit}`);
|
||||
expect(res.statusCode).toBe(200);
|
||||
});
|
||||
|
||||
it("should return 200 for a request with valid limit param", async () => {
|
||||
const limit = faker.number.int({ min: 5, max: 50 });
|
||||
const res = await request(app).get(`/images?limit=${limit}`);
|
||||
expect(res.body.images.length).toBeLessThanOrEqual(limit);
|
||||
});
|
||||
|
||||
it("should return 200 for a request with both valid params", async () => {
|
||||
const res = await request(app).get("/images?limit=3&status=available");
|
||||
expect(res.statusCode).toBe(200);
|
||||
});
|
||||
|
||||
it("should return the same ids using limit=0 and using no limit parameter", async () => {
|
||||
const resLimit0 = await request(app).get("/images?limit=0");
|
||||
const resNoLimit = await request(app).get("/images");
|
||||
|
||||
const ids1 = resNoLimit.body.images.map((image: Image) => image._id);
|
||||
const ids2 = resLimit0.body.images.map((image: Image) => image._id);
|
||||
|
||||
expect(ids1.length).toBe(ids2.length);
|
||||
ids1.forEach((id: string) => expect(ids2).toContain(id));
|
||||
})
|
||||
});
|
||||
|
||||
describe("POST /images works properly", () => {
|
||||
|
@ -178,7 +242,7 @@ describe("POST /images works properly", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("/images/:id works properly", () => {
|
||||
describe("GET /images/:id works properly", () => {
|
||||
it("should return 200 for existing ids", async () => {
|
||||
const list = await request(app).get("/images");
|
||||
const id = list.body.images[0]._id;
|
||||
|
|
Loading…
Reference in New Issue