Skip to content

Commit

Permalink
Fixes + error handling (#14)
Browse files Browse the repository at this point in the history
* Remove useless packages, fix version in example

* Better error handling

* Improve error handling

* Add error handling in adapter
  • Loading branch information
foyarash authored Dec 15, 2020
1 parent 2c447b7 commit 69eea93
Show file tree
Hide file tree
Showing 13 changed files with 1,315 additions and 1,036 deletions.
1 change: 1 addition & 0 deletions docs/pages/api-docs/adapters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface IAdapter<T, Q = IParsedQueryParams> {
create(data: any, query?: Q): Promise<T> // POST /api/modelName
update(resourceId: string | number, data: any, query?: Q): Promise<T> // PUT/PATCH /api/modelName/:id
delete(resourceId: string | number, query?: Q): Promise<T> // DELETE /api/modelName/:id
handleError?: (err: Error) => void // Used to throw a custom error of your own
}
```

Expand Down
2 changes: 1 addition & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@prisma/client": "^2.11.0",
"framer-motion": "^2.9.4",
"next": "latest",
"@premieroctet/next-crud": "file:..",
"@premieroctet/next-crud": "latest",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-hook-form": "^6.11.5",
Expand Down
1,184 changes: 1,170 additions & 14 deletions example/yarn.lock

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@
"dependencies": {
"lodash.isobject": "^3.0.2",
"lodash.set": "^4.3.2",
"nextra": "^0.3.1",
"nextra-theme-docs": "^1.0.1",
"path-to-regexp": "^6.2.0",
"qs": "^6.9.4"
}
Expand Down
29 changes: 27 additions & 2 deletions src/adapters/prisma/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
// @ts-ignore
import { PrismaClient, PrismaAction, PrismaClientOptions } from '@prisma/client'
import {
PrismaClient,
PrismaAction,
PrismaClientOptions,
PrismaClientKnownRequestError,
PrismaClientValidationError,
// @ts-ignore
} from '@prisma/client'
import HttpError from '../../httpError'
import { IAdapter, IParsedQueryParams } from '../../types'
import { IPrismaParsedQueryParams } from './types'
import { parsePrismaCursor } from './utils/parseCursor'
Expand Down Expand Up @@ -33,6 +40,24 @@ export default class PrismaAdapter<T>
this.manyRelations = manyRelations
}

handleError(err: Error) {
console.error(err.message)
if (
err instanceof PrismaClientKnownRequestError ||
err instanceof PrismaClientValidationError
) {
throw new HttpError(
400,
'invalid request, check your server logs for more info'
)
} else {
throw new HttpError(
500,
'an unknown error occured, check your server logs for more info'
)
}
}

parseQuery(query?: IParsedQueryParams) {
const parsed: IPrismaParsedQueryParams = {}

Expand Down
73 changes: 43 additions & 30 deletions src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
getOneHandler,
updateHandler,
} from './handlers'
import HttpError from './httpError'
import { parseQuery } from './queryParser'
import { IAdapter, IHandlerParams, RouteType, TMiddleware } from './types'
import { getRouteType, formatResourceId as formatResourceIdUtil } from './utils'
Expand Down Expand Up @@ -120,35 +121,43 @@ function NextCrud<T, Q = any>({
const resourceIdFormatted = formatResourceId(resourceId)

const executeCrud = async () => {
switch (routeType) {
case RouteType.READ_ONE:
await getOneHandler({
...params,
resourceId: resourceIdFormatted,
})
break
case RouteType.READ_ALL:
await getAllHandler<T, Q>(params)
break
case RouteType.CREATE:
await createHandler<T, Q>({ ...params, body })
break
case RouteType.UPDATE:
await updateHandler<T, Q>({
...params,
resourceId: resourceIdFormatted,
body,
})
break
case RouteType.DELETE:
await deleteHandler<T, Q>({
...params,
resourceId: resourceIdFormatted,
})
break
case null:
res.status(404)
break
try {
switch (routeType) {
case RouteType.READ_ONE:
await getOneHandler({
...params,
resourceId: resourceIdFormatted,
})
break
case RouteType.READ_ALL:
await getAllHandler<T, Q>(params)
break
case RouteType.CREATE:
await createHandler<T, Q>({ ...params, body })
break
case RouteType.UPDATE:
await updateHandler<T, Q>({
...params,
resourceId: resourceIdFormatted,
body,
})
break
case RouteType.DELETE:
await deleteHandler<T, Q>({
...params,
resourceId: resourceIdFormatted,
})
break
case null:
res.status(404)
break
}
} catch (e) {
if (adapter.handleError && !(e instanceof HttpError)) {
adapter.handleError(e)
} else {
throw e
}
}
}

Expand Down Expand Up @@ -182,7 +191,11 @@ function NextCrud<T, Q = any>({
await onSuccess?.(req, res)
} catch (e) {
await onError?.(req, res, e)
res.status(500).send(e.message)
if (e instanceof HttpError) {
res.status(e.statusCode).send(e.message)
} else {
res.status(500).send(e.message)
}
} finally {
await adapter.disconnect?.()
res.end()
Expand Down
35 changes: 21 additions & 14 deletions src/handlers/deleteHandler.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import HttpError from '../httpError'
import { IUniqueResourceHandlerParams } from '../types'
import { executeMiddlewares } from '../utils'

Expand All @@ -11,20 +12,26 @@ async function deleteHandler<T, Q>({
request,
middlewares,
}: IDeleteHandler<T, Q>): Promise<void> {
const deletedResource = await adapter.delete(resourceId, query)
await executeMiddlewares(
[
...middlewares,
({ result }) => {
response.send(result)
},
],
{
req: request,
res: response,
result: deletedResource,
}
)
const resource = await adapter.getOne(resourceId, query)

if (resource) {
const deletedResource = await adapter.delete(resourceId, query)
await executeMiddlewares(
[
...middlewares,
({ result }) => {
response.send(result)
},
],
{
req: request,
res: response,
result: deletedResource,
}
)
} else {
throw new HttpError(404, `resource ${resourceId} not found`)
}
}

export default deleteHandler
6 changes: 6 additions & 0 deletions src/handlers/getOne.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import HttpError from '../httpError'
import { IUniqueResourceHandlerParams } from '../types'
import { executeMiddlewares } from '../utils'

Expand All @@ -12,6 +13,11 @@ async function getOneHandler<T, Q>({
request,
}: IGetOneHandler<T, Q>): Promise<void> {
const resource = await adapter.getOne(resourceId, query)

if (!resource) {
throw new HttpError(404, `resource ${resourceId} not found`)
}

await executeMiddlewares(
[
...middlewares,
Expand Down
35 changes: 21 additions & 14 deletions src/handlers/updateHandler.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import HttpError from '../httpError'
import { IUniqueResourceHandlerParams } from '../types'
import { executeMiddlewares } from '../utils'

Expand All @@ -14,20 +15,26 @@ async function updateHandler<T, Q>({
middlewares,
request,
}: IUpdateHandler<T, Q>): Promise<void> {
const updatedResource = await adapter.update(resourceId, body, query)
await executeMiddlewares(
[
...middlewares,
({ result }) => {
response.send(result)
},
],
{
req: request,
res: response,
result: updatedResource,
}
)
const resource = await adapter.getOne(resourceId, query)

if (resource) {
const updatedResource = await adapter.update(resourceId, body, query)
await executeMiddlewares(
[
...middlewares,
({ result }) => {
response.send(result)
},
],
{
req: request,
res: response,
result: updatedResource,
}
)
} else {
throw new HttpError(404, `resource ${resourceId} not found`)
}
}

export default updateHandler
11 changes: 11 additions & 0 deletions src/httpError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as http from 'http'

export default class HttpError extends Error {
statusCode: number

constructor(code: number, message?: string) {
super(`${http.STATUS_CODES[code]}: ${message}`)
this.name = 'HttpError'
this.statusCode = code
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default } from './handler'
export { default as PrismaAdapter } from './adapters/prisma'
export * from './types'
export { default as HttpError } from './httpError'
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface IAdapter<T, Q> {
delete(resourceId: string | number, query?: Q): Promise<T>
connect?: () => Promise<void>
disconnect?: () => Promise<void>
handleError?: (err: Error) => void
}

export type TMiddlewareContext<T> = {
Expand Down
Loading

0 comments on commit 69eea93

Please sign in to comment.