From 32c16ff6638dcd2813b778218ea9eadcdb106562 Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sat, 5 Feb 2022 09:53:46 +0100 Subject: [PATCH 01/14] #1 Create Endpoint added Signed-off-by: Benny Samir Hierl --- examples.http | 33 +++++++++++++++++++ src/api/config/errors/index.ts | 15 +++++++++ src/api/models/wishlist/index.ts | 6 ++++ src/api/routes/wishlist/create.ts | 55 +++++++++++++++++++++++++++++++ src/api/routes/wishlist/index.ts | 2 ++ src/api/services/prisma/index.ts | 4 ++- src/types.ts | 2 +- 7 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 examples.http create mode 100644 src/api/config/errors/index.ts create mode 100644 src/api/routes/wishlist/create.ts diff --git a/examples.http b/examples.http new file mode 100644 index 0000000..966382e --- /dev/null +++ b/examples.http @@ -0,0 +1,33 @@ +@BASE_URL=http://localhost:5000/api + + +### +# @name createWishlistFirst +POST {{BASE_URL}}/wishlist +Content-Type: application/json + +{ + "title": "Junior", + "imageSrc": "https://unsplash.com/photos/JZ51o_-UOY8/download?force=true&w=200", + "slugUrlText": "junior" +} + +### +# @name createWishlistSecond +POST {{BASE_URL}}/wishlist +Content-Type: application/json + +{ + "title": "Wedding", + "imageSrc": "https://unsplash.com/photos/8vaQKYnawHw/download?ixid=MnwxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNjQ0MDQ4MTIy&force=true&w=200", + "description": "We are getting married", + "slugUrlText": "wedding" +} + +### +# @name getWishlists +GET {{BASE_URL}}/wishlist + +### +# @name getFirstWishlist +GET {{BASE_URL}}/wishlist/{{getWishlists.response.body.0.slugUrlText}} diff --git a/src/api/config/errors/index.ts b/src/api/config/errors/index.ts new file mode 100644 index 0000000..a3d14a2 --- /dev/null +++ b/src/api/config/errors/index.ts @@ -0,0 +1,15 @@ +class httpError extends Error { + code: string + statusCode: number + constructor(message: string, statusCode: number, code: string) { + super(message) + this.name = this.constructor.name + Error.captureStackTrace(this, this.constructor) + this.statusCode = statusCode + this.code = code + } +} + +export const uniqueKeyError = (msg: string, code = '4001') => { + return new httpError(msg, 400, code) +} diff --git a/src/api/models/wishlist/index.ts b/src/api/models/wishlist/index.ts index 35b5ddc..fe7cbcc 100644 --- a/src/api/models/wishlist/index.ts +++ b/src/api/models/wishlist/index.ts @@ -1,4 +1,5 @@ import { prisma } from '../../services' +import { Wishlist } from '@/types' export default { getAll: async (): Promise => { @@ -17,6 +18,11 @@ export default { include: { items: includeItems }, }) }, + create: async (payload: Wishlist) => { + return await prisma.client.wishlist.create({ + data: payload, + }) + }, // eslint-disable-next-line @typescript-eslint/no-explicit-any updateItem: async (itemId: number, payload: any) => { return await prisma.client.item.update({ diff --git a/src/api/routes/wishlist/create.ts b/src/api/routes/wishlist/create.ts new file mode 100644 index 0000000..f6bbc50 --- /dev/null +++ b/src/api/routes/wishlist/create.ts @@ -0,0 +1,55 @@ +import { Wishlist } from '@/types' +import { FastifyRequest, FastifyReply, RouteOptions } from 'fastify' +import { wishlist } from '../../models' +import { prisma } from '../../services' +import { uniqueKeyError } from '../../config/errors' + +interface GetBySlugUrlTextRequest extends FastifyRequest { + params: { + wishlistId: string + itemId: number + } +} + +export const createList = { + method: 'POST', + url: '/', + schema: { + body: { + type: 'object', + additionalProperties: false, + required: ['title', 'imageSrc', 'slugUrlText'], + properties: { + title: { type: 'string' }, + imageSrc: { type: 'string' }, + description: { type: 'string' }, + slugUrlText: { type: 'string' }, + }, + }, + response: { + 201: { + type: 'object', + properties: { + id: { type: 'string' }, + title: { type: 'string' }, + imageSrc: { type: 'string' }, + description: { type: 'string' }, + slugUrlText: { type: 'string' }, + }, + }, + }, + }, + handler: async (request: GetBySlugUrlTextRequest, reply: FastifyReply) => { + request.log.debug(request.body) + try { + const item = await wishlist.create(request.body as Wishlist) + return item + } catch (error) { + if (error instanceof prisma.errorType && error.code === 'P2002') { + return reply.send(uniqueKeyError('Slugtext has to be unique')) + } + request.log.error(error) + throw new Error('Unexptected Error') + } + }, +} diff --git a/src/api/routes/wishlist/index.ts b/src/api/routes/wishlist/index.ts index 32fd362..1c9e7ee 100644 --- a/src/api/routes/wishlist/index.ts +++ b/src/api/routes/wishlist/index.ts @@ -1,9 +1,11 @@ import { FastifyInstance } from 'fastify' import { getAll, getBySlugUrl } from './read' import { updateItem } from './update' +import { createList } from './create' export default async (app: FastifyInstance) => { await app.route(getAll) await app.route(getBySlugUrl) + await app.route(createList) await app.route(updateItem) } diff --git a/src/api/services/prisma/index.ts b/src/api/services/prisma/index.ts index 3134896..9716a39 100644 --- a/src/api/services/prisma/index.ts +++ b/src/api/services/prisma/index.ts @@ -1,7 +1,9 @@ -import { PrismaClient } from '@prisma/client' +import { PrismaClient, Prisma } from '@prisma/client' const client = new PrismaClient() +const errorType = Prisma.PrismaClientKnownRequestError export default { client, + errorType, } diff --git a/src/types.ts b/src/types.ts index de90a26..5898f69 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,7 +9,7 @@ export interface WishlistItem { wishlistId: boolean } export interface Wishlist { - id: string + id?: string title: string description: string imageSrc: string From abf6addb704421e9f9aec09691e69bc9f9dd413f Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sat, 5 Feb 2022 09:56:15 +0100 Subject: [PATCH 02/14] #1 http status changed for case not unique slug text Signed-off-by: Benny Samir Hierl --- src/api/config/errors/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/config/errors/index.ts b/src/api/config/errors/index.ts index a3d14a2..99bacf3 100644 --- a/src/api/config/errors/index.ts +++ b/src/api/config/errors/index.ts @@ -11,5 +11,5 @@ class httpError extends Error { } export const uniqueKeyError = (msg: string, code = '4001') => { - return new httpError(msg, 400, code) + return new httpError(msg, 422, code) } From ff4a891b3500c9670a356c35a500f595a7da09c8 Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sat, 5 Feb 2022 10:16:23 +0100 Subject: [PATCH 03/14] #1 not found handling improved Signed-off-by: Benny Samir Hierl --- src/api/config/errors/index.ts | 4 ++++ src/api/routes/index.ts | 4 ++++ src/api/routes/wishlist/read.ts | 5 +---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/api/config/errors/index.ts b/src/api/config/errors/index.ts index 99bacf3..992af1b 100644 --- a/src/api/config/errors/index.ts +++ b/src/api/config/errors/index.ts @@ -10,6 +10,10 @@ class httpError extends Error { } } +export const notFoundError = () => { + return new httpError('Not Found', 404, '404') +} + export const uniqueKeyError = (msg: string, code = '4001') => { return new httpError(msg, 422, code) } diff --git a/src/api/routes/index.ts b/src/api/routes/index.ts index 222f45c..a4dbf16 100644 --- a/src/api/routes/index.ts +++ b/src/api/routes/index.ts @@ -1,10 +1,14 @@ import { FastifyInstance } from 'fastify' import { default as wishlistRoute } from './wishlist/' +import { notFoundError } from '../config/errors' export default { register: (app: FastifyInstance) => { return app.register( async (app) => { + app.setNotFoundHandler((request, reply) => { + reply.send(notFoundError()) + }) await app.register(wishlistRoute, { prefix: '/wishlist' }) }, { prefix: '/api' } diff --git a/src/api/routes/wishlist/read.ts b/src/api/routes/wishlist/read.ts index 389ad37..04fd5c9 100644 --- a/src/api/routes/wishlist/read.ts +++ b/src/api/routes/wishlist/read.ts @@ -68,10 +68,7 @@ export const getBySlugUrl = { if (list) { return list } else { - return reply.code(404).send({ - error: 'notFound', - http: 404, - }) + return reply.callNotFound() } }, } From 4b553830b02d0d7dd63341304da0c95ab0d425e1 Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sat, 5 Feb 2022 13:14:12 +0100 Subject: [PATCH 04/14] #1 error handling improved Signed-off-by: Benny Samir Hierl --- src/api/routes/wishlist/create.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/api/routes/wishlist/create.ts b/src/api/routes/wishlist/create.ts index f6bbc50..f945bc0 100644 --- a/src/api/routes/wishlist/create.ts +++ b/src/api/routes/wishlist/create.ts @@ -39,17 +39,16 @@ export const createList = { }, }, }, + errorHandler: (error, request, reply) => { + if (error instanceof prisma.errorType && error.code === 'P2002') { + return reply.send(uniqueKeyError('Slugtext has to be unique')) + } + request.log.error(error) + reply.send(new Error('Unexptected Error')) + }, handler: async (request: GetBySlugUrlTextRequest, reply: FastifyReply) => { request.log.debug(request.body) - try { - const item = await wishlist.create(request.body as Wishlist) - return item - } catch (error) { - if (error instanceof prisma.errorType && error.code === 'P2002') { - return reply.send(uniqueKeyError('Slugtext has to be unique')) - } - request.log.error(error) - throw new Error('Unexptected Error') - } + const item = await wishlist.create(request.body as Wishlist) + return item }, } From 8b0d8d27e38a000b843ca2b5eb6cc0b7726fd391 Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sat, 5 Feb 2022 13:20:44 +0100 Subject: [PATCH 05/14] #1 response code changed Signed-off-by: Benny Samir Hierl --- src/api/routes/wishlist/create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/routes/wishlist/create.ts b/src/api/routes/wishlist/create.ts index f945bc0..cc33fe0 100644 --- a/src/api/routes/wishlist/create.ts +++ b/src/api/routes/wishlist/create.ts @@ -49,6 +49,6 @@ export const createList = { handler: async (request: GetBySlugUrlTextRequest, reply: FastifyReply) => { request.log.debug(request.body) const item = await wishlist.create(request.body as Wishlist) - return item + reply.code(201).send(item) }, } From 5626fabdcee96f27aced48c138714aaea9f8707c Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sat, 5 Feb 2022 13:21:06 +0100 Subject: [PATCH 06/14] seed data adjusted Signed-off-by: Benny Samir Hierl --- .gitignore | 1 - prisma/seed.ts | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 prisma/seed.ts diff --git a/.gitignore b/.gitignore index b48fca3..e28467e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,5 +30,4 @@ dist/ coverage .env data -prisma/seed.ts public/*.jpeg diff --git a/prisma/seed.ts b/prisma/seed.ts new file mode 100644 index 0000000..c369da5 --- /dev/null +++ b/prisma/seed.ts @@ -0,0 +1,78 @@ +import { PrismaClient, Prisma } from '@prisma/client' + +const prisma = new PrismaClient() + +const wishlistData: Prisma.WishlistCreateInput[] = [ + { + title: 'Junior', + imageSrc: + 'https://unsplash.com/photos/JZ51o_-UOY8/download?force=true&w=200', + description: '', + slugUrlText: 'junior', + items: { + create: [ + { + title: 'Mr Maria Lion "First Light" Lampe', + url: 'https://babykochs.de/mr-maria-lion-first-light-lampe/', + imageSrc: + 'https://babykochs.de/wp-content/uploads/2021/01/First-Light-Lion1.jpg', + description: + 'Lion ist Teil der Serie "First Light - Miffy und Freunde" Kollektion, eine Nachtlampe, die als "kleiner Freund für ein kleines Wunder" entworfen wurde.', + comment: '', + }, + { + title: 'Liewood Nachtlicht Winston Bär dove blue', + url: 'https://babykochs.de/liewood-nachtlicht-baer/', + imageSrc: + 'https://babykochs.de/wp-content/uploads/2021/01/Liewood-Nachtlicht-Winston-bear-dove-blue.jpg', + description: + 'Mit dem Licht dieses süßen Bären fühlen sich Eure Kleinen in der Nacht ganz sicher und haben’s schön gemütlich.', + comment: '', + }, + { + title: 'Baby- und Kleinkindbett', + url: 'https://www.tchibo.de/baby-und-kleinkindbett-p400114225.html#modal-productimagegallery-modalGalleryImage-400886394', + imageSrc: + 'https://www.tchibo.de/newmedia/art_img/MAIN-IMPORTED/f045f71ebabea9e4/baby-und-kleinkindbett.jpg', + description: + 'Ein Bett, das mitwächst Zu einem erholsamen Schlaf und einer schönen Nacht gehört natürlich auch ein gutes Bett – das gilt auch für die Kleinsten.', + comment: '', + }, + ], + }, + }, + { + title: 'Wedding', + imageSrc: + 'https://unsplash.com/photos/8vaQKYnawHw/download?ixid=MnwxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNjQ0MDQ4MTIy&force=true&w=200', + description: 'We are getting married', + slugUrlText: 'wedding', + }, + { + title: '40th birthday', + imageSrc: + 'https://unsplash.com/photos/poH6OvcEeXE/download?ixid=MnwxMjA3fDB8MXxzZWFyY2h8NHx8YmlydGhkYXl8fDB8fHx8MTY0NDA1NDEzNA&force=true&w=200', + description: 'We are getting married', + slugUrlText: '40th-birthday', + }, +] + +async function main() { + console.log(`Start seeding ...`) + for (const u of wishlistData) { + const wishlist = await prisma.wishlist.create({ + data: u, + }) + console.log(`Created wishlist with id: ${wishlist.id}`) + } + console.log(`Seeding finished.`) +} + +main() + .catch((e) => { + console.error(e) + process.exit(1) + }) + .finally(async () => { + await prisma.$disconnect() + }) From 520ddfe653f3f87869c0dd02da5f920c4f387faa Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sat, 5 Feb 2022 13:22:19 +0100 Subject: [PATCH 07/14] small adjustment Signed-off-by: Benny Samir Hierl --- src/api/routes/wishlist/create.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/api/routes/wishlist/create.ts b/src/api/routes/wishlist/create.ts index cc33fe0..198d400 100644 --- a/src/api/routes/wishlist/create.ts +++ b/src/api/routes/wishlist/create.ts @@ -4,13 +4,6 @@ import { wishlist } from '../../models' import { prisma } from '../../services' import { uniqueKeyError } from '../../config/errors' -interface GetBySlugUrlTextRequest extends FastifyRequest { - params: { - wishlistId: string - itemId: number - } -} - export const createList = { method: 'POST', url: '/', @@ -46,7 +39,7 @@ export const createList = { request.log.error(error) reply.send(new Error('Unexptected Error')) }, - handler: async (request: GetBySlugUrlTextRequest, reply: FastifyReply) => { + handler: async (request: FastifyRequest, reply: FastifyReply) => { request.log.debug(request.body) const item = await wishlist.create(request.body as Wishlist) reply.code(201).send(item) From 2b5f4a9fd63398717046bd26e291a8cbcebc128c Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sat, 5 Feb 2022 13:43:55 +0100 Subject: [PATCH 08/14] #1 update api added Signed-off-by: Benny Samir Hierl --- examples.http | 12 +++++++ src/api/models/wishlist/index.ts | 10 ++++++ src/api/routes/wishlist/index.ts | 3 +- src/api/routes/wishlist/read.ts | 2 +- src/api/routes/wishlist/update.ts | 60 +++++++++++++++++++++++++++++-- 5 files changed, 83 insertions(+), 4 deletions(-) diff --git a/examples.http b/examples.http index 966382e..700d9a6 100644 --- a/examples.http +++ b/examples.http @@ -31,3 +31,15 @@ GET {{BASE_URL}}/wishlist ### # @name getFirstWishlist GET {{BASE_URL}}/wishlist/{{getWishlists.response.body.0.slugUrlText}} + +### +# @name updateFirstWishlist +PUT {{BASE_URL}}/wishlist/{{getWishlists.response.body.0.id}} +Content-Type: application/json + +{ + "title": "Junior", + "imageSrc": "https://unsplash.com/photos/JZ51o_-UOY8/download?force=true&w=200", + "description": "Juniors Wishlist", + "slugUrlText": "junior" +} diff --git a/src/api/models/wishlist/index.ts b/src/api/models/wishlist/index.ts index fe7cbcc..15245e1 100644 --- a/src/api/models/wishlist/index.ts +++ b/src/api/models/wishlist/index.ts @@ -23,6 +23,16 @@ export default { data: payload, }) }, + update: async (id: string, payload: Wishlist) => { + return await prisma.client.wishlist.update({ + where: { + id: id, + }, + data: { + ...payload, + }, + }) + }, // eslint-disable-next-line @typescript-eslint/no-explicit-any updateItem: async (itemId: number, payload: any) => { return await prisma.client.item.update({ diff --git a/src/api/routes/wishlist/index.ts b/src/api/routes/wishlist/index.ts index 1c9e7ee..33f34fb 100644 --- a/src/api/routes/wishlist/index.ts +++ b/src/api/routes/wishlist/index.ts @@ -1,11 +1,12 @@ import { FastifyInstance } from 'fastify' import { getAll, getBySlugUrl } from './read' -import { updateItem } from './update' +import { updateList, updateItem } from './update' import { createList } from './create' export default async (app: FastifyInstance) => { await app.route(getAll) await app.route(getBySlugUrl) await app.route(createList) + await app.route(updateList) await app.route(updateItem) } diff --git a/src/api/routes/wishlist/read.ts b/src/api/routes/wishlist/read.ts index 04fd5c9..03e5928 100644 --- a/src/api/routes/wishlist/read.ts +++ b/src/api/routes/wishlist/read.ts @@ -1,7 +1,7 @@ import { FastifyRequest, FastifyReply, RouteOptions } from 'fastify' import { wishlist } from '../../models' -export const getAll = { +export const getAll = { method: 'GET', url: '/', schema: { diff --git a/src/api/routes/wishlist/update.ts b/src/api/routes/wishlist/update.ts index a8775fe..bdc6952 100644 --- a/src/api/routes/wishlist/update.ts +++ b/src/api/routes/wishlist/update.ts @@ -1,13 +1,69 @@ +import { uniqueKeyError } from '../../config/errors' +import { prisma } from '../../services' +import { Wishlist } from '@/types' import { FastifyRequest, FastifyReply, RouteOptions } from 'fastify' import { wishlist } from '../../models' -interface GetBySlugUrlTextRequest extends FastifyRequest { +interface updateRequest extends FastifyRequest { + params: { + wishlistId: string + } +} +interface updateItemRequest extends FastifyRequest { params: { wishlistId: string itemId: number } } +export const updateList = { + method: 'PUT', + url: '/:wishlistId', + schema: { + body: { + type: 'object', + additionalProperties: false, + required: ['title', 'imageSrc', 'slugUrlText'], + properties: { + title: { type: 'string' }, + imageSrc: { type: 'string' }, + description: { type: 'string' }, + slugUrlText: { type: 'string' }, + }, + }, + response: { + 200: { + type: 'object', + properties: { + id: { type: 'string' }, + title: { type: 'string' }, + imageSrc: { type: 'string' }, + description: { type: 'string' }, + slugUrlText: { type: 'string' }, + }, + }, + }, + }, + errorHandler: (error, request, reply) => { + if (error instanceof prisma.errorType && error.code === 'P2002') { + return reply.send(uniqueKeyError('Slugtext has to be unique')) + } + if (error instanceof prisma.errorType && error.code === 'P2025') { + return reply.callNotFound() + } + request.log.error(error) + reply.send(new Error('Unexptected Error')) + }, + handler: async (request: updateRequest, reply: FastifyReply) => { + request.log.debug(request.body) + const item = await wishlist.update( + request.params.wishlistId, + request.body as Wishlist + ) + reply.code(201).send(item) + }, +} + export const updateItem = { method: 'PUT', url: '/:wishlistId/item/:itemId', @@ -40,7 +96,7 @@ export const updateItem = { }, }, }, - handler: async (request: GetBySlugUrlTextRequest, reply: FastifyReply) => { + handler: async (request: updateItemRequest, reply: FastifyReply) => { request.log.debug(request.body) const item = await wishlist.updateItem( Number(request.params.itemId), From 82ac242d9649168828a0c3e6740e47eba6ed5424 Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sat, 5 Feb 2022 14:03:29 +0100 Subject: [PATCH 09/14] #1 JSON Schemas centralized Signed-off-by: Benny Samir Hierl --- src/api/config/schemas/index.ts | 1 + src/api/config/schemas/wishlist.ts | 53 ++++++++++++++++++++++++++++ src/api/routes/wishlist/create.ts | 27 ++++---------- src/api/routes/wishlist/read.ts | 37 ++------------------ src/api/routes/wishlist/update.ts | 56 ++++++------------------------ 5 files changed, 73 insertions(+), 101 deletions(-) create mode 100644 src/api/config/schemas/index.ts create mode 100644 src/api/config/schemas/wishlist.ts diff --git a/src/api/config/schemas/index.ts b/src/api/config/schemas/index.ts new file mode 100644 index 0000000..5284f07 --- /dev/null +++ b/src/api/config/schemas/index.ts @@ -0,0 +1 @@ +export * from './wishlist' diff --git a/src/api/config/schemas/wishlist.ts b/src/api/config/schemas/wishlist.ts new file mode 100644 index 0000000..897bf25 --- /dev/null +++ b/src/api/config/schemas/wishlist.ts @@ -0,0 +1,53 @@ +export const wishlistItemRequestSchema = { + type: 'object', + additionalProperties: false, + required: ['title', 'imageSrc'], + properties: { + title: { type: 'string' }, + url: { type: 'string' }, + imageSrc: { type: 'string' }, + description: { type: 'string' }, + comment: { type: 'string' }, + bought: { type: 'boolean' }, + }, +} + +export const wishlistItemResponseSchema = { + type: 'object', + properties: { + id: { type: 'number' }, + title: { type: 'string' }, + url: { type: 'string' }, + imageSrc: { type: 'string' }, + description: { type: 'string' }, + comment: { type: 'string' }, + bought: { type: 'boolean' }, + wishlistId: { type: 'string' }, + }, +} + +export const wishlistRequestSchema = { + type: 'object', + additionalProperties: false, + required: ['title', 'imageSrc', 'slugUrlText'], + properties: { + title: { type: 'string' }, + imageSrc: { type: 'string' }, + description: { type: 'string' }, + slugUrlText: { type: 'string' }, + }, +} +export const wishlistResponseSchema = { + type: 'object', + properties: { + id: { type: 'string' }, + title: { type: 'string' }, + imageSrc: { type: 'string' }, + description: { type: 'string' }, + slugUrlText: { type: 'string' }, + items: { + type: 'array', + items: wishlistItemResponseSchema, + }, + }, +} diff --git a/src/api/routes/wishlist/create.ts b/src/api/routes/wishlist/create.ts index 198d400..9ee934a 100644 --- a/src/api/routes/wishlist/create.ts +++ b/src/api/routes/wishlist/create.ts @@ -3,33 +3,18 @@ import { FastifyRequest, FastifyReply, RouteOptions } from 'fastify' import { wishlist } from '../../models' import { prisma } from '../../services' import { uniqueKeyError } from '../../config/errors' +import { + wishlistRequestSchema, + wishlistResponseSchema, +} from '../../config/schemas' export const createList = { method: 'POST', url: '/', schema: { - body: { - type: 'object', - additionalProperties: false, - required: ['title', 'imageSrc', 'slugUrlText'], - properties: { - title: { type: 'string' }, - imageSrc: { type: 'string' }, - description: { type: 'string' }, - slugUrlText: { type: 'string' }, - }, - }, + body: wishlistRequestSchema, response: { - 201: { - type: 'object', - properties: { - id: { type: 'string' }, - title: { type: 'string' }, - imageSrc: { type: 'string' }, - description: { type: 'string' }, - slugUrlText: { type: 'string' }, - }, - }, + 201: wishlistResponseSchema, }, }, errorHandler: (error, request, reply) => { diff --git a/src/api/routes/wishlist/read.ts b/src/api/routes/wishlist/read.ts index 03e5928..3bc6e80 100644 --- a/src/api/routes/wishlist/read.ts +++ b/src/api/routes/wishlist/read.ts @@ -1,5 +1,6 @@ import { FastifyRequest, FastifyReply, RouteOptions } from 'fastify' import { wishlist } from '../../models' +import { wishlistResponseSchema } from '../../config/schemas' export const getAll = { method: 'GET', @@ -8,15 +9,7 @@ export const getAll = { response: { 200: { type: 'array', - items: { - properties: { - id: { type: 'string' }, - title: { type: 'string' }, - imageSrc: { type: 'string' }, - description: { type: 'string' }, - slugUrlText: { type: 'string' }, - }, - }, + items: wishlistResponseSchema, }, }, }, @@ -36,31 +29,7 @@ export const getBySlugUrl = { url: '/:slugText', schema: { response: { - 200: { - type: 'object', - properties: { - id: { type: 'string' }, - title: { type: 'string' }, - imageSrc: { type: 'string' }, - description: { type: 'string' }, - slugUrlText: { type: 'string' }, - items: { - type: 'array', - items: { - properties: { - id: { type: 'number' }, - title: { type: 'string' }, - url: { type: 'string' }, - imageSrc: { type: 'string' }, - description: { type: 'string' }, - comment: { type: 'string' }, - bought: { type: 'boolean' }, - wishlistId: { type: 'string' }, - }, - }, - }, - }, - }, + 200: wishlistResponseSchema, }, }, handler: async (request: GetBySlugUrlTextRequest, reply: FastifyReply) => { diff --git a/src/api/routes/wishlist/update.ts b/src/api/routes/wishlist/update.ts index bdc6952..b6f9a4d 100644 --- a/src/api/routes/wishlist/update.ts +++ b/src/api/routes/wishlist/update.ts @@ -3,6 +3,12 @@ import { prisma } from '../../services' import { Wishlist } from '@/types' import { FastifyRequest, FastifyReply, RouteOptions } from 'fastify' import { wishlist } from '../../models' +import { + wishlistRequestSchema, + wishlistResponseSchema, + wishlistItemRequestSchema, + wishlistItemResponseSchema, +} from '../../config/schemas' interface updateRequest extends FastifyRequest { params: { @@ -20,28 +26,9 @@ export const updateList = { method: 'PUT', url: '/:wishlistId', schema: { - body: { - type: 'object', - additionalProperties: false, - required: ['title', 'imageSrc', 'slugUrlText'], - properties: { - title: { type: 'string' }, - imageSrc: { type: 'string' }, - description: { type: 'string' }, - slugUrlText: { type: 'string' }, - }, - }, + body: wishlistRequestSchema, response: { - 200: { - type: 'object', - properties: { - id: { type: 'string' }, - title: { type: 'string' }, - imageSrc: { type: 'string' }, - description: { type: 'string' }, - slugUrlText: { type: 'string' }, - }, - }, + 200: wishlistResponseSchema, }, }, errorHandler: (error, request, reply) => { @@ -68,32 +55,9 @@ export const updateItem = { method: 'PUT', url: '/:wishlistId/item/:itemId', schema: { - body: { - type: 'object', - additionalProperties: false, - properties: { - title: { type: 'string' }, - url: { type: 'string' }, - image: { type: 'string' }, - description: { type: 'string' }, - comment: { type: 'string' }, - bought: { type: 'boolean' }, - }, - }, + body: wishlistItemRequestSchema, response: { - 204: { - type: 'object', - properties: { - id: { type: 'number' }, - title: { type: 'string' }, - url: { type: 'string' }, - image: { type: 'string' }, - description: { type: 'string' }, - comment: { type: 'string' }, - bought: { type: 'boolean' }, - wishlistId: { type: 'string' }, - }, - }, + 200: wishlistItemResponseSchema, }, }, handler: async (request: updateItemRequest, reply: FastifyReply) => { From 56db8ba65a2afeb5f5c994fc59207659fea4b45d Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sat, 5 Feb 2022 14:45:56 +0100 Subject: [PATCH 10/14] #1 Schema adjusted Signed-off-by: Benny Samir Hierl --- .../migration.sql | 8 ++++---- prisma/schema.prisma | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) rename prisma/migrations/{20220129174151_first_migration => 20220205134511_first_migration}/migration.sql (79%) diff --git a/prisma/migrations/20220129174151_first_migration/migration.sql b/prisma/migrations/20220205134511_first_migration/migration.sql similarity index 79% rename from prisma/migrations/20220129174151_first_migration/migration.sql rename to prisma/migrations/20220205134511_first_migration/migration.sql index f84bb69..d37838a 100644 --- a/prisma/migrations/20220129174151_first_migration/migration.sql +++ b/prisma/migrations/20220205134511_first_migration/migration.sql @@ -4,17 +4,17 @@ CREATE TABLE "Wishlist" ( "title" TEXT NOT NULL, "imageSrc" TEXT NOT NULL, "slugUrlText" TEXT NOT NULL, - "description" TEXT + "description" TEXT NOT NULL DEFAULT '' ); -- CreateTable CREATE TABLE "Item" ( "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "title" TEXT NOT NULL, - "url" TEXT, - "imageSrc" TEXT, + "url" TEXT NOT NULL DEFAULT '', + "imageSrc" TEXT NOT NULL DEFAULT '', "description" TEXT NOT NULL, - "comment" TEXT, + "comment" TEXT NOT NULL DEFAULT '', "bought" BOOLEAN NOT NULL DEFAULT false, "wishlistId" TEXT NOT NULL, CONSTRAINT "Item_wishlistId_fkey" FOREIGN KEY ("wishlistId") REFERENCES "Wishlist" ("id") ON DELETE RESTRICT ON UPDATE CASCADE diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 7616486..492ab53 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -15,18 +15,18 @@ model Wishlist { title String imageSrc String slugUrlText String @unique - description String? + description String @default("") items Item[] } model Item { - id Int @id @default(autoincrement()) + id Int @id @default(autoincrement()) title String - url String? - imageSrc String? + url String @default("") + imageSrc String @default("") description String - comment String? + comment String @default("") bought Boolean @default(false) - wishlist Wishlist @relation(fields: [wishlistId], references: [id]) + wishlist Wishlist @relation(fields: [wishlistId], references: [id]) wishlistId String } From dea3aaf477983a75772cd13dede5ad2a4c752ac5 Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sat, 5 Feb 2022 14:47:37 +0100 Subject: [PATCH 11/14] #1 Add item API Endpoint added Signed-off-by: Benny Samir Hierl --- examples.http | 12 ++++++++++ prisma/seed.ts | 26 ++++----------------- src/api/config/schemas/wishlist.ts | 2 +- src/api/models/wishlist/index.ts | 18 ++++++++++++++- src/api/routes/wishlist/create.ts | 36 +++++++++++++++++++++++++++++- src/api/routes/wishlist/index.ts | 3 ++- src/api/routes/wishlist/update.ts | 8 +++---- 7 files changed, 74 insertions(+), 31 deletions(-) diff --git a/examples.http b/examples.http index 700d9a6..eefce8d 100644 --- a/examples.http +++ b/examples.http @@ -43,3 +43,15 @@ Content-Type: application/json "description": "Juniors Wishlist", "slugUrlText": "junior" } + +### +# @name addItemToFirstWishlist +POST {{BASE_URL}}/wishlist/{{getWishlists.response.body.0.id}}/item +Content-Type: application/json + +{ + "title": "Goldfish 40442 | BrickHeadz", + "url": "https://www.lego.com/en-de/product/goldfish-40442", + "imageSrc": "https://www.lego.com/cdn/cs/set/assets/blt1fc37afef51cfa9f/40442.jpg?fit=bounds&format=jpg&quality=80&width=1500&height=1500&dpr=1", + "description": "Cute goldfish and fry, build-and-display BrickHeadz™ model" +} diff --git a/prisma/seed.ts b/prisma/seed.ts index c369da5..b404659 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -12,30 +12,12 @@ const wishlistData: Prisma.WishlistCreateInput[] = [ items: { create: [ { - title: 'Mr Maria Lion "First Light" Lampe', - url: 'https://babykochs.de/mr-maria-lion-first-light-lampe/', + title: 'Goldfish 40442 | BrickHeadz', + url: 'https://www.lego.com/en-de/product/goldfish-40442', imageSrc: - 'https://babykochs.de/wp-content/uploads/2021/01/First-Light-Lion1.jpg', + 'https://www.lego.com/cdn/cs/set/assets/blt1fc37afef51cfa9f/40442.jpg?fit=bounds&format=jpg&quality=80&width=1500&height=1500&dpr=1', description: - 'Lion ist Teil der Serie "First Light - Miffy und Freunde" Kollektion, eine Nachtlampe, die als "kleiner Freund für ein kleines Wunder" entworfen wurde.', - comment: '', - }, - { - title: 'Liewood Nachtlicht Winston Bär dove blue', - url: 'https://babykochs.de/liewood-nachtlicht-baer/', - imageSrc: - 'https://babykochs.de/wp-content/uploads/2021/01/Liewood-Nachtlicht-Winston-bear-dove-blue.jpg', - description: - 'Mit dem Licht dieses süßen Bären fühlen sich Eure Kleinen in der Nacht ganz sicher und haben’s schön gemütlich.', - comment: '', - }, - { - title: 'Baby- und Kleinkindbett', - url: 'https://www.tchibo.de/baby-und-kleinkindbett-p400114225.html#modal-productimagegallery-modalGalleryImage-400886394', - imageSrc: - 'https://www.tchibo.de/newmedia/art_img/MAIN-IMPORTED/f045f71ebabea9e4/baby-und-kleinkindbett.jpg', - description: - 'Ein Bett, das mitwächst Zu einem erholsamen Schlaf und einer schönen Nacht gehört natürlich auch ein gutes Bett – das gilt auch für die Kleinsten.', + 'Cute goldfish and fry, build-and-display BrickHeadz™ model', comment: '', }, ], diff --git a/src/api/config/schemas/wishlist.ts b/src/api/config/schemas/wishlist.ts index 897bf25..3e575fc 100644 --- a/src/api/config/schemas/wishlist.ts +++ b/src/api/config/schemas/wishlist.ts @@ -1,7 +1,7 @@ export const wishlistItemRequestSchema = { type: 'object', additionalProperties: false, - required: ['title', 'imageSrc'], + required: ['title', 'description'], properties: { title: { type: 'string' }, url: { type: 'string' }, diff --git a/src/api/models/wishlist/index.ts b/src/api/models/wishlist/index.ts index 15245e1..e140f3d 100644 --- a/src/api/models/wishlist/index.ts +++ b/src/api/models/wishlist/index.ts @@ -1,5 +1,5 @@ import { prisma } from '../../services' -import { Wishlist } from '@/types' +import { Wishlist, WishlistItem } from '@/types' export default { getAll: async (): Promise => { @@ -33,6 +33,22 @@ export default { }, }) }, + createItem: async (wishlistId: string, payload: WishlistItem) => { + const wishlist = await prisma.client.wishlist.update({ + where: { + id: wishlistId, + }, + data: { + items: { + create: { + ...payload, + }, + }, + }, + include: { items: true }, + }) + return wishlist.items.pop() + }, // eslint-disable-next-line @typescript-eslint/no-explicit-any updateItem: async (itemId: number, payload: any) => { return await prisma.client.item.update({ diff --git a/src/api/routes/wishlist/create.ts b/src/api/routes/wishlist/create.ts index 9ee934a..55a5087 100644 --- a/src/api/routes/wishlist/create.ts +++ b/src/api/routes/wishlist/create.ts @@ -1,13 +1,21 @@ -import { Wishlist } from '@/types' +import { Wishlist, WishlistItem } from '@/types' import { FastifyRequest, FastifyReply, RouteOptions } from 'fastify' import { wishlist } from '../../models' import { prisma } from '../../services' import { uniqueKeyError } from '../../config/errors' import { + wishlistItemRequestSchema, + wishlistItemResponseSchema, wishlistRequestSchema, wishlistResponseSchema, } from '../../config/schemas' +interface createItemRequest extends FastifyRequest { + params: { + wishlistId: string + } +} + export const createList = { method: 'POST', url: '/', @@ -30,3 +38,29 @@ export const createList = { reply.code(201).send(item) }, } + +export const createItem = { + method: 'POST', + url: '/:wishlistId/item', + schema: { + body: wishlistItemRequestSchema, + response: { + 201: wishlistItemResponseSchema, + }, + }, + errorHandler: (error, request, reply) => { + if (error instanceof prisma.errorType && error.code === 'P2025') { + return reply.callNotFound() + } + request.log.error(error) + reply.send(new Error('Unexptected Error')) + }, + handler: async (request: createItemRequest, reply: FastifyReply) => { + request.log.debug(request.body) + const item = await wishlist.createItem( + request.params.wishlistId, + request.body as WishlistItem + ) + reply.code(201).send(item) + }, +} diff --git a/src/api/routes/wishlist/index.ts b/src/api/routes/wishlist/index.ts index 33f34fb..ec37853 100644 --- a/src/api/routes/wishlist/index.ts +++ b/src/api/routes/wishlist/index.ts @@ -1,12 +1,13 @@ import { FastifyInstance } from 'fastify' import { getAll, getBySlugUrl } from './read' import { updateList, updateItem } from './update' -import { createList } from './create' +import { createList, createItem } from './create' export default async (app: FastifyInstance) => { await app.route(getAll) await app.route(getBySlugUrl) await app.route(createList) + await app.route(createItem) await app.route(updateList) await app.route(updateItem) } diff --git a/src/api/routes/wishlist/update.ts b/src/api/routes/wishlist/update.ts index b6f9a4d..be8224c 100644 --- a/src/api/routes/wishlist/update.ts +++ b/src/api/routes/wishlist/update.ts @@ -15,6 +15,7 @@ interface updateRequest extends FastifyRequest { wishlistId: string } } + interface updateItemRequest extends FastifyRequest { params: { wishlistId: string @@ -67,12 +68,9 @@ export const updateItem = { request.body ) if (item) { - return item + reply.send(item) } else { - return reply.code(404).send({ - error: 'notFound', - http: 404, - }) + reply.callNotFound() } }, } From 9534bc270ffab0a3d3c41d56188734ddba548054 Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sat, 5 Feb 2022 14:58:20 +0100 Subject: [PATCH 12/14] small typescript adjustments Signed-off-by: Benny Samir Hierl --- src/api/models/wishlist/index.ts | 11 ++++------- src/types.ts | 2 +- src/views/DetailView.vue | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/api/models/wishlist/index.ts b/src/api/models/wishlist/index.ts index e140f3d..570f159 100644 --- a/src/api/models/wishlist/index.ts +++ b/src/api/models/wishlist/index.ts @@ -2,15 +2,12 @@ import { prisma } from '../../services' import { Wishlist, WishlistItem } from '@/types' export default { - getAll: async (): Promise => { - return await prisma.client.wishlist.findMany({ + getAll: async (): Promise => { + return (await prisma.client.wishlist.findMany({ include: { items: false }, - }) + })) as Wishlist[] }, - getBySlugUrlText: async ( - value: string, - includeItems = false - ): Promise => { + getBySlugUrlText: async (value: string, includeItems = false) => { return await prisma.client.wishlist.findUnique({ where: { slugUrlText: value, diff --git a/src/types.ts b/src/types.ts index 5898f69..9962ef6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,7 +14,7 @@ export interface Wishlist { description: string imageSrc: string slugUrlText: string - items: WishlistItem[] + items?: WishlistItem[] } export interface TileProp { title: string diff --git a/src/views/DetailView.vue b/src/views/DetailView.vue index fe89828..73cf606 100644 --- a/src/views/DetailView.vue +++ b/src/views/DetailView.vue @@ -16,7 +16,7 @@ const { list, fetch, updateItem } = useWishlistStore() await fetch(route.params.slug as string) const notBoughtItems = computed(() => { - return list.value?.items.filter( + return list.value?.items?.filter( (item: WishlistItemType) => item.bought === false ) }) From 14cded061f3de4d28d92c39fe032a5cf730dbc2e Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sun, 6 Feb 2022 11:23:47 +0100 Subject: [PATCH 13/14] #1 error handling improved Signed-off-by: Benny Samir Hierl --- src/api/config/errors/index.ts | 41 +++++++++++++++++++++++++++++-- src/api/routes/index.ts | 7 +++--- src/api/routes/wishlist/create.ts | 22 +++++------------ src/api/routes/wishlist/update.ts | 35 +++++++++++--------------- src/api/services/prisma/index.ts | 4 +-- 5 files changed, 64 insertions(+), 45 deletions(-) diff --git a/src/api/config/errors/index.ts b/src/api/config/errors/index.ts index 992af1b..9d91200 100644 --- a/src/api/config/errors/index.ts +++ b/src/api/config/errors/index.ts @@ -1,3 +1,40 @@ +import { FastifyRequest, FastifyReply, FastifyError } from 'fastify' +import { Prisma } from '@prisma/client' + +const errorIs = (e: unknown, c: string) => + e instanceof Prisma.PrismaClientKnownRequestError && e.code === c + +export const defaultErrorHandler = ( + error: FastifyError, + request: FastifyRequest, + reply: FastifyReply +) => { + if (error.validation) { + error.code = '400' + reply.send(error) + } else if (errorIs(error, 'P2002')) { + reply.send( + uniqueKeyError( + // @ts-expect-error: Object is possibly 'undefined' + `${error.meta.target[0] || 'One of the fields'} has to be unique` + ) + ) + } else if (errorIs(error, 'P2025')) { + reply.callNotFound() + } else { + request.log.error(error) + const e = new httpError('unexpected error', 500, '500') + reply.send(e) + } +} + +export const notFoundHandler = ( + request: FastifyRequest, + reply: FastifyReply +) => { + reply.send(notFoundError()) +} + class httpError extends Error { code: string statusCode: number @@ -10,10 +47,10 @@ class httpError extends Error { } } -export const notFoundError = () => { +const notFoundError = () => { return new httpError('Not Found', 404, '404') } -export const uniqueKeyError = (msg: string, code = '4001') => { +const uniqueKeyError = (msg: string, code = '4001') => { return new httpError(msg, 422, code) } diff --git a/src/api/routes/index.ts b/src/api/routes/index.ts index a4dbf16..d88f405 100644 --- a/src/api/routes/index.ts +++ b/src/api/routes/index.ts @@ -1,14 +1,13 @@ import { FastifyInstance } from 'fastify' import { default as wishlistRoute } from './wishlist/' -import { notFoundError } from '../config/errors' +import { defaultErrorHandler, notFoundHandler } from '../config/errors' export default { register: (app: FastifyInstance) => { return app.register( async (app) => { - app.setNotFoundHandler((request, reply) => { - reply.send(notFoundError()) - }) + await app.setNotFoundHandler(notFoundHandler) + await app.setErrorHandler(defaultErrorHandler) await app.register(wishlistRoute, { prefix: '/wishlist' }) }, { prefix: '/api' } diff --git a/src/api/routes/wishlist/create.ts b/src/api/routes/wishlist/create.ts index 55a5087..cf8117b 100644 --- a/src/api/routes/wishlist/create.ts +++ b/src/api/routes/wishlist/create.ts @@ -1,8 +1,6 @@ import { Wishlist, WishlistItem } from '@/types' import { FastifyRequest, FastifyReply, RouteOptions } from 'fastify' import { wishlist } from '../../models' -import { prisma } from '../../services' -import { uniqueKeyError } from '../../config/errors' import { wishlistItemRequestSchema, wishlistItemResponseSchema, @@ -25,13 +23,6 @@ export const createList = { 201: wishlistResponseSchema, }, }, - errorHandler: (error, request, reply) => { - if (error instanceof prisma.errorType && error.code === 'P2002') { - return reply.send(uniqueKeyError('Slugtext has to be unique')) - } - request.log.error(error) - reply.send(new Error('Unexptected Error')) - }, handler: async (request: FastifyRequest, reply: FastifyReply) => { request.log.debug(request.body) const item = await wishlist.create(request.body as Wishlist) @@ -44,17 +35,16 @@ export const createItem = { url: '/:wishlistId/item', schema: { body: wishlistItemRequestSchema, + params: { + type: 'object', + properties: { + wishlistId: { type: 'string' }, + }, + }, response: { 201: wishlistItemResponseSchema, }, }, - errorHandler: (error, request, reply) => { - if (error instanceof prisma.errorType && error.code === 'P2025') { - return reply.callNotFound() - } - request.log.error(error) - reply.send(new Error('Unexptected Error')) - }, handler: async (request: createItemRequest, reply: FastifyReply) => { request.log.debug(request.body) const item = await wishlist.createItem( diff --git a/src/api/routes/wishlist/update.ts b/src/api/routes/wishlist/update.ts index be8224c..78d78fb 100644 --- a/src/api/routes/wishlist/update.ts +++ b/src/api/routes/wishlist/update.ts @@ -1,5 +1,3 @@ -import { uniqueKeyError } from '../../config/errors' -import { prisma } from '../../services' import { Wishlist } from '@/types' import { FastifyRequest, FastifyReply, RouteOptions } from 'fastify' import { wishlist } from '../../models' @@ -28,20 +26,16 @@ export const updateList = { url: '/:wishlistId', schema: { body: wishlistRequestSchema, + params: { + type: 'object', + properties: { + wishlistId: { type: 'string' }, + }, + }, response: { 200: wishlistResponseSchema, }, }, - errorHandler: (error, request, reply) => { - if (error instanceof prisma.errorType && error.code === 'P2002') { - return reply.send(uniqueKeyError('Slugtext has to be unique')) - } - if (error instanceof prisma.errorType && error.code === 'P2025') { - return reply.callNotFound() - } - request.log.error(error) - reply.send(new Error('Unexptected Error')) - }, handler: async (request: updateRequest, reply: FastifyReply) => { request.log.debug(request.body) const item = await wishlist.update( @@ -57,20 +51,21 @@ export const updateItem = { url: '/:wishlistId/item/:itemId', schema: { body: wishlistItemRequestSchema, + params: { + type: 'object', + properties: { + wishlistId: { type: 'string' }, + itemId: { type: 'number' }, + }, + }, response: { 200: wishlistItemResponseSchema, }, }, handler: async (request: updateItemRequest, reply: FastifyReply) => { request.log.debug(request.body) - const item = await wishlist.updateItem( - Number(request.params.itemId), - request.body + reply.send( + await wishlist.updateItem(Number(request.params.itemId), request.body) ) - if (item) { - reply.send(item) - } else { - reply.callNotFound() - } }, } diff --git a/src/api/services/prisma/index.ts b/src/api/services/prisma/index.ts index 9716a39..3134896 100644 --- a/src/api/services/prisma/index.ts +++ b/src/api/services/prisma/index.ts @@ -1,9 +1,7 @@ -import { PrismaClient, Prisma } from '@prisma/client' +import { PrismaClient } from '@prisma/client' const client = new PrismaClient() -const errorType = Prisma.PrismaClientKnownRequestError export default { client, - errorType, } From 16df584334b3945038096a646ef5578be349a6f6 Mon Sep 17 00:00:00 2001 From: Benny Samir Hierl Date: Sun, 6 Feb 2022 11:44:50 +0100 Subject: [PATCH 14/14] #1 delete endpoint added --- examples.http | 16 ++++++++++ src/api/models/wishlist/index.ts | 14 +++++++++ src/api/routes/wishlist/delete.ts | 50 +++++++++++++++++++++++++++++++ src/api/routes/wishlist/index.ts | 3 ++ src/api/routes/wishlist/update.ts | 4 +-- 5 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 src/api/routes/wishlist/delete.ts diff --git a/examples.http b/examples.http index eefce8d..9ff63c8 100644 --- a/examples.http +++ b/examples.http @@ -55,3 +55,19 @@ Content-Type: application/json "imageSrc": "https://www.lego.com/cdn/cs/set/assets/blt1fc37afef51cfa9f/40442.jpg?fit=bounds&format=jpg&quality=80&width=1500&height=1500&dpr=1", "description": "Cute goldfish and fry, build-and-display BrickHeadz™ model" } + +### +# @name updateItemOnFirstWishlist +PUT {{BASE_URL}}/wishlist/{{getWishlists.response.body.0.id}}/item/1 +Content-Type: application/json + +{ + "title": "Goldfish | BrickHeadz", + "url": "https://www.lego.com/en-de/product/goldfish-40442", + "imageSrc": "https://www.lego.com/cdn/cs/set/assets/blt1fc37afef51cfa9f/40442.jpg?fit=bounds&format=jpg&quality=80&width=1500&height=1500&dpr=1", + "description": "Cute goldfish and fry, build-and-display BrickHeadz™ model" +} + +### +# @name deleteItemToFirstWishlist +DELETE {{BASE_URL}}/wishlist/{{getWishlists.response.body.0.id}}/item/2 diff --git a/src/api/models/wishlist/index.ts b/src/api/models/wishlist/index.ts index 570f159..183f227 100644 --- a/src/api/models/wishlist/index.ts +++ b/src/api/models/wishlist/index.ts @@ -30,6 +30,13 @@ export default { }, }) }, + delete: async (id: string) => { + return await prisma.client.wishlist.delete({ + where: { + id: id, + }, + }) + }, createItem: async (wishlistId: string, payload: WishlistItem) => { const wishlist = await prisma.client.wishlist.update({ where: { @@ -57,4 +64,11 @@ export default { }, }) }, + deleteItem: async (itemId: number) => { + return await prisma.client.item.delete({ + where: { + id: itemId, + }, + }) + }, } diff --git a/src/api/routes/wishlist/delete.ts b/src/api/routes/wishlist/delete.ts new file mode 100644 index 0000000..ebeb9e9 --- /dev/null +++ b/src/api/routes/wishlist/delete.ts @@ -0,0 +1,50 @@ +import { FastifyRequest, FastifyReply, RouteOptions } from 'fastify' +import { wishlist } from '../../models' + +interface deleteRequest extends FastifyRequest { + params: { + wishlistId: string + } +} + +interface deleteItemRequest extends FastifyRequest { + params: { + wishlistId: string + itemId: number + } +} + +export const deleteList = { + method: 'DELETE', + url: '/:wishlistId', + schema: { + params: { + type: 'object', + properties: { + wishlistId: { type: 'string' }, + }, + }, + }, + handler: async (request: deleteRequest, reply: FastifyReply) => { + await wishlist.delete(request.params.wishlistId) + reply.code(204).send() + }, +} + +export const deleteItem = { + method: 'DELETE', + url: '/:wishlistId/item/:itemId', + schema: { + params: { + type: 'object', + properties: { + wishlistId: { type: 'string' }, + itemId: { type: 'number' }, + }, + }, + }, + handler: async (request: deleteItemRequest, reply: FastifyReply) => { + await wishlist.deleteItem(request.params.itemId) + reply.code(204).send() + }, +} diff --git a/src/api/routes/wishlist/index.ts b/src/api/routes/wishlist/index.ts index ec37853..13ad069 100644 --- a/src/api/routes/wishlist/index.ts +++ b/src/api/routes/wishlist/index.ts @@ -2,6 +2,7 @@ import { FastifyInstance } from 'fastify' import { getAll, getBySlugUrl } from './read' import { updateList, updateItem } from './update' import { createList, createItem } from './create' +import { deleteList, deleteItem } from './delete' export default async (app: FastifyInstance) => { await app.route(getAll) @@ -10,4 +11,6 @@ export default async (app: FastifyInstance) => { await app.route(createItem) await app.route(updateList) await app.route(updateItem) + await app.route(deleteList) + await app.route(deleteItem) } diff --git a/src/api/routes/wishlist/update.ts b/src/api/routes/wishlist/update.ts index 78d78fb..2f64817 100644 --- a/src/api/routes/wishlist/update.ts +++ b/src/api/routes/wishlist/update.ts @@ -64,8 +64,6 @@ export const updateItem = { }, handler: async (request: updateItemRequest, reply: FastifyReply) => { request.log.debug(request.body) - reply.send( - await wishlist.updateItem(Number(request.params.itemId), request.body) - ) + reply.send(await wishlist.updateItem(request.params.itemId, request.body)) }, }