Skip to content

Commit

Permalink
feat: get contact by id
Browse files Browse the repository at this point in the history
  • Loading branch information
n9mi committed Sep 15, 2024
1 parent 95235dc commit 77bf481
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 37 deletions.
118 changes: 100 additions & 18 deletions __tests__/contact.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,65 @@ import bcrypt from "bcrypt";
import supertest from "supertest";
import { basePath, web } from "../src/application/web";
import logger from "../src/application/logger";
import { Contact } from "@prisma/client";

describe("GET /contact:id", () => {
let token: string = "";
let createdContact: Contact = {} as Contact;

beforeAll(async () => {
token = await ContactTestUtil.getToken();
createdContact = await ContactTestUtil.createContact();
});

afterAll(async () => {
await ContactTestUtil.deleteContact();
await ContactTestUtil.deleteUser();
});

it ("should return 200 - success getting a contact", async () => {
const res = await supertest(web)
.get(`${basePath}/contact/${createdContact.id}`)
.set('Authorization', `Bearer ${token}`);

logger.info(res.body);
expect(res.status).toBe(200);
expect(res.body.data.id).toBe(createdContact.id);
expect(res.body.data.first_name).toBe(createdContact.first_name);
expect(res.body.data.last_name).toBe(createdContact.last_name);
expect(res.body.data.email).toBe(createdContact.email);
expect(res.body.data.phone).toBe(createdContact.phone);
});

it("should return 404 - invalid contact id", async () => {
const res = await supertest(web)
.get(`${basePath}/contact/test123`)
.set('Authorization', `Bearer ${token}`);

logger.info(res.body);
expect(res.status).toBe(404);
expect(res.body.errors).toBeDefined();
});

it("should return 404 - contact id doesn't exists", async () => {
const res = await supertest(web)
.get(`${basePath}/contact/10000`)
.set('Authorization', `Bearer ${token}`);

logger.info(res.body);
expect(res.status).toBe(404);
expect(res.body.errors).toBeDefined();
});

it("should return 401 - empty authorization", async () => {
const res = await supertest(web)
.get(`${basePath}/contact/${createdContact.id}`);

logger.info(res.body);
expect(res.status).toBe(401);
expect(res.body.errors).toBeDefined();
});
});

describe("POST /contact", () => {
let token: string = "";
Expand All @@ -16,40 +75,33 @@ describe("POST /contact", () => {
await ContactTestUtil.deleteUser();
})

const newContact = {
first_name: "First",
last_name: "Last",
email: "[email protected]",
phone: "08123456789"
}

it("should return 200 - success creating contact", async () => {
const res = await supertest(web)
.post(`${basePath}/contact`)
.send(newContact)
.send(ContactTestUtil.contact)
.set('Authorization', `Bearer ${token}`);

logger.info(res.body);
expect(res.status).toBe(200);
expect(res.body.data.id).toBeGreaterThanOrEqual(1);
expect(res.body.data.first_name).toBe(newContact.first_name);
expect(res.body.data.last_name).toBe(newContact.last_name);
expect(res.body.data.email).toBe(newContact.email);
expect(res.body.data.phone).toBe(newContact.phone);
expect(res.body.data.first_name).toBe(ContactTestUtil.contact.first_name);
expect(res.body.data.last_name).toBe(ContactTestUtil.contact.last_name);
expect(res.body.data.email).toBe(ContactTestUtil.contact.email);
expect(res.body.data.phone).toBe(ContactTestUtil.contact.phone);
});

it("should return 200 - success creating contact with emty last_name, email, and phone", async () => {
const res = await supertest(web)
.post(`${basePath}/contact`)
.send({
first_name: newContact.first_name
first_name: ContactTestUtil.contact.first_name
})
.set('Authorization', `Bearer ${token}`);

logger.info(res.body);
expect(res.status).toBe(200);
expect(res.body.data.id).toBeGreaterThanOrEqual(1);
expect(res.body.data.first_name).toBe(newContact.first_name);
expect(res.body.data.first_name).toBe(ContactTestUtil.contact.first_name);
expect(res.body.data.last_name).toBe("");
expect(res.body.data.email).toBe("");
expect(res.body.data.phone).toBe("");
Expand All @@ -59,8 +111,8 @@ describe("POST /contact", () => {
const res = await supertest(web)
.post(`${basePath}/contact`)
.send({
first_name: newContact.first_name,
last_name: newContact.last_name,
first_name: ContactTestUtil.contact.first_name,
last_name: ContactTestUtil.contact.last_name,
email: "test",
})
.set('Authorization', `Bearer ${token}`);
Expand All @@ -74,8 +126,8 @@ describe("POST /contact", () => {
const res = await supertest(web)
.post(`${basePath}/contact`)
.send({
first_name: newContact.first_name,
last_name: newContact.last_name,
first_name: ContactTestUtil.contact.first_name,
last_name: ContactTestUtil.contact.last_name,
phone: "0123456789012345678901",
})
.set('Authorization', `Bearer ${token}`);
Expand All @@ -84,6 +136,18 @@ describe("POST /contact", () => {
expect(res.status).toBe(400);
expect(res.body.errors.phone).toBeDefined();
});

it("should return 401 - empty authorization", async () => {
const res = await supertest(web)
.post(`${basePath}/contact`)
.send({
first_name: ContactTestUtil.contact.first_name
});

logger.info(res.body);
expect(res.status).toBe(401);
expect(res.body.errors).toBeDefined();
});
})

class ContactTestUtil {
Expand All @@ -93,6 +157,13 @@ class ContactTestUtil {
password: "password"
};

static contact = {
first_name: "First",
last_name: "Last",
email: "[email protected]",
phone: "08123456789"
}

static async create() {
await prisma.user.create({
data: {
Expand Down Expand Up @@ -120,6 +191,17 @@ class ContactTestUtil {
await prisma.user.deleteMany({});
}

static async createContact(): Promise<Contact> {
const contact = await prisma.contact.create({
data: {
...ContactTestUtil.contact,
username: ContactTestUtil.user.username
}
});

return contact as Contact;
}

static async deleteContact() {
await prisma.contact.deleteMany({});
}
Expand Down
34 changes: 17 additions & 17 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ services:
- POSTGRES_PASSWORD=${DB_PASSWORD}
networks:
- contact_api_network
# contact-api:
# environment:
# - DATABASE_URL=${DATABASE_URL}
# - PORT=${PORT}
# - BASE_URL_PATH=${BASE_URL_PATH}
# - JWT_SECRET=${JWT_SECRET}
# - JWT_EXPIRED_IN_MINUTES=${JWT_EXPIRED_IN_MINUTES}
# build: .
# image: contact-api
# ports:
# - '3000:3000'
# depends_on:
# - db
# volumes:
# - .:/usr/src/node-app
# networks:
# - contact_api_network
contact-api:
environment:
- DATABASE_URL=${DATABASE_URL}
- PORT=${PORT}
- BASE_URL_PATH=${BASE_URL_PATH}
- JWT_SECRET=${JWT_SECRET}
- JWT_EXPIRED_IN_MINUTES=${JWT_EXPIRED_IN_MINUTES}
build: .
image: contact-api
ports:
- '3000:3000'
depends_on:
- db
volumes:
- .:/usr/src/node-app
networks:
- contact_api_network

volumes:
postgres-db:
Expand Down
17 changes: 17 additions & 0 deletions src/controller/contact.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
import { Request, Response, NextFunction } from "express";
import ContactService from "../service/contact";
import { ContactRequest } from "../model/contact";
import { ResponseError } from "../error/response";

export class ContactController {

static async getById(req: Request, res: Response, next: NextFunction) {
try {
if (isNaN(Number(req.params.id))) {
throw new ResponseError(404, "contact doesn't exists")
}
const getRes = await ContactService.findById(res.locals.user.username, Number(req.params.id));

res.status(200)
.json({
data: getRes
})
} catch (e) {
next(e);
}
}

static async create(req: Request, res: Response, next: NextFunction) {
try {
const createRes = await ContactService.create(res.locals.user.username, req.body as ContactRequest);
Expand Down
1 change: 1 addition & 0 deletions src/router/contact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { accessValidation } from "../middleware/accessValidation";
export const getContactRouter = (basePath: string) => {
const contactRouter = express.Router();
contactRouter.use(accessValidation);
contactRouter.get(`${basePath}/contact/:id`, ContactController.getById);
contactRouter.post(`${basePath}/contact`, ContactController.create);

return contactRouter;
Expand Down
16 changes: 14 additions & 2 deletions src/service/contact.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
import prisma from "../application/database";
import { ResponseError } from "../error/response";
import { ContactRequest, ContactResponse, toContactResponse } from "../model/contact";
import { ContactValidation } from "../validation/contact";
import { Validation } from "../validation/validation";

export default class ContactService {

static async findById(username: string, id: number): Promise<ContactResponse> {
const contact = await prisma.contact.findFirstOrThrow({
where: {
AND: {
username: username,
id: id
}
}
}).catch((e) => { throw new ResponseError(404, "contact doesn't exists") });

return toContactResponse(contact);
}

static async create(username: string, req: ContactRequest): Promise<ContactResponse> {
const validatedReq = Validation.validate(ContactValidation.CREATE, req);

console.info(validatedReq);

const contact = await prisma.contact.create({
data: {
...validatedReq,
Expand Down

0 comments on commit 77bf481

Please sign in to comment.