Skip to content

Commit

Permalink
add default expose strategy option
Browse files Browse the repository at this point in the history
  • Loading branch information
baptadn committed May 23, 2022
1 parent f560a88 commit 5eee6d0
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 25 deletions.
53 changes: 53 additions & 0 deletions __tests__/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ensureCamelCase,
executeMiddlewares,
formatResourceId,
getAccessibleRoutes,
getPaginationOptions,
getResourceNameFromUrl,
getRouteType,
Expand Down Expand Up @@ -355,3 +356,55 @@ it('should get the correct matching resource name', () => {
it('should ensure the string is in camel case', () => {
expect(ensureCamelCase('FooBar')).toBe('fooBar')
})

describe('Expose strategy', () => {
it('should expose all routes', () => {
expect(getAccessibleRoutes(undefined, undefined, 'all')).toEqual([
RouteType.READ_ALL,
RouteType.READ_ONE,
RouteType.UPDATE,
RouteType.DELETE,
RouteType.CREATE,
])
})

it('should expose no routes', () => {
expect(getAccessibleRoutes([], undefined, 'all')).toEqual([])
expect(getAccessibleRoutes(undefined, undefined, 'none')).toEqual([])
})

it('should expose only CREATE and READ_ALL routes', () => {
expect(
getAccessibleRoutes(
[RouteType.CREATE, RouteType.READ_ALL],
undefined,
'all'
)
).toEqual([RouteType.CREATE, RouteType.READ_ALL])
})

it('should expose not expose DELETE route', () => {
expect(getAccessibleRoutes(undefined, [RouteType.DELETE], 'all')).toEqual([
RouteType.READ_ALL,
RouteType.READ_ONE,
RouteType.UPDATE,
RouteType.CREATE,
])
})

it('should only expose CREATE route', () => {
expect(
getAccessibleRoutes(
[RouteType.DELETE, RouteType.CREATE],
[RouteType.DELETE],
'all'
)
).toEqual([RouteType.CREATE])
})

it('should only expose DELETE route', () => {
expect(getAccessibleRoutes([RouteType.DELETE], undefined, 'none')).toEqual([
RouteType.DELETE,
])
})
})
5 changes: 5 additions & 0 deletions docs/pages/api-docs/options.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ NextCrud({
only: [RouteType.READ_ALL],
},
},
defaultExposeStrategy: 'all',
})
```
Expand All @@ -57,6 +58,10 @@ import { RouteType } from '@premieroctet/next-crud'

A required instance of an adaptater class, see <Link href="/api-docs/adapters">this section</Link>.

#### defaultExposeStrategy

If `all`, all routes are exposed, if `none`, only the routes specified in the `only` option are exposed. Default to `all`.

#### formatResourceId

An optional function that allows you to format the retrieve resource id for the routes implying a single resource. By default it transforms number strings as numbers, else keep them as strings.
Expand Down
29 changes: 25 additions & 4 deletions docs/pages/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,30 @@ import Link from 'next/link'

## Installation

`yarn add @premieroctet/next-crud`
```
yarn add @premieroctet/next-crud
npm install -S @premieroctet/next-crud
```

## Quick Start

or
```typescript
// pages/api/[...nextcrud.ts]

`npm i -S @premieroctet/next-crud`
import NextCrud, { PrismaAdapter } from '@premieroctet/next-crud'
import { Prisma, PrismaClient } from '@prisma/client'

const prismaClient = new PrismaClient()

const handler = NextCrud({
adapter: new PrismaAdapter({
prismaClient,
}),
})

export default handler
```

## Usage

Expand All @@ -48,6 +67,8 @@ import NextCrud, { PrismaAdapter } from '@premieroctet/next-crud'
- Then create the handler and export it

```javascript
// pages/api/[...nextcrud.ts]

const handler = NextCrud({
adapter: new PrismaAdapter({
prismaClient: myPrismaClientInstance,
Expand All @@ -59,7 +80,7 @@ export default handler

_More info about all the available options <Link href="/api-docs/options">here</Link>_

You can also find a working example <Link href="https://github.com/premieroctet/next-crud/tree/master/example">on Github</Link> or you can run it <Link href="https://codesandbox.io/s/next-crud-demo-qj3gn">on Codesandbox</Link>.
You can also find a working example <Link href="https://github.com/premieroctet/next-crud/tree/master/example">on GitHub</Link> or you can run it <Link href="https://codesandbox.io/s/next-crud-demo-qj3gn">on Codesandbox</Link>.

That will create the following routes:

Expand Down
14 changes: 11 additions & 3 deletions src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
IPaginationConfig,
TModelsOptions,
TSwaggerConfig,
TDefaultExposeStrategy,
} from './types'
import {
getRouteType,
Expand Down Expand Up @@ -53,6 +54,7 @@ interface INextCrudOptions<T, Q, M extends string = string> {
pagination?: IPaginationConfig
models?: TModelsOptions<M>
swagger?: TSwaggerConfig<M>
defaultExposeStrategy?: TDefaultExposeStrategy
}

const defaultPaginationConfig: IPaginationConfig = {
Expand All @@ -76,6 +78,7 @@ function NextCrud<T, Q = any, M extends string = string>({
middlewares = [],
pagination = defaultPaginationConfig,
swagger = defaultSwaggerConfig,
defaultExposeStrategy = 'all',
}: INextCrudOptions<T, Q, M>): NextApiHandler<T> {
if (
!adapter.create ||
Expand Down Expand Up @@ -104,7 +107,11 @@ function NextCrud<T, Q = any, M extends string = string>({
}

if (swaggerConfig?.enabled) {
const swaggerRoutes = getModelsAccessibleRoutes(adapter.getModels(), models)
const swaggerRoutes = getModelsAccessibleRoutes(
adapter.getModels(),
models,
defaultExposeStrategy
)
const swaggerTags = getSwaggerTags(
adapter.getModels(),
swaggerConfig.config
Expand Down Expand Up @@ -163,11 +170,12 @@ function NextCrud<T, Q = any, M extends string = string>({
resourceName,
})

const modelConfig = models?.[resourceName]
const modelConfig = models?.[modelName]

const accessibleRoutes = getAccessibleRoutes(
modelConfig?.only,
modelConfig?.exclude
modelConfig?.exclude,
defaultExposeStrategy
)

if (!accessibleRoutes.includes(routeType)) {
Expand Down
14 changes: 10 additions & 4 deletions src/swagger/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
TModelsOptions,
TSwaggerTag,
TSwaggerModelsConfig,
TSwaggerParameter,
TDefaultExposeStrategy,
} from '../types'
import { getAccessibleRoutes } from '../utils'
import { getQueryParams } from './parameters'
Expand Down Expand Up @@ -147,22 +147,28 @@ type TRoutes<M extends string> = {

export const getModelsAccessibleRoutes = <M extends string>(
modelNames: M[],
models?: TModelsOptions<M>
models?: TModelsOptions<M>,
defaultExposeStrategy: TDefaultExposeStrategy = 'all'
): TRoutes<M> => {
return modelNames.reduce((acc, modelName) => {
if (models?.[modelName]) {
return {
...acc,
[modelName]: getAccessibleRoutes(
models[modelName].only,
models[modelName].exclude
models[modelName].exclude,
defaultExposeStrategy
),
}
}

return {
...acc,
[modelName]: getAccessibleRoutes(),
[modelName]: getAccessibleRoutes(
undefined,
undefined,
defaultExposeStrategy
),
}
}, {})
}
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,5 @@ export type TSwaggerConfig<M extends string> = {
apiUrl: string
config?: TSwaggerModelsConfig<M>
}

export type TDefaultExposeStrategy = 'all' | 'none'
31 changes: 17 additions & 14 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
IPaginationConfig,
IParsedQueryParams,
TPaginationOptions,
TDefaultExposeStrategy,
} from './types'

interface GetRouteTypeParams {
Expand Down Expand Up @@ -197,25 +198,27 @@ export const getResourceNameFromUrl = <M extends string = string>(

export const getAccessibleRoutes = (
only?: RouteType[],
exclude?: RouteType[]
exclude?: RouteType[],
defaultExposeStrategy: TDefaultExposeStrategy = 'all'
): RouteType[] => {
let accessibleRoutes: RouteType[] = [
RouteType.READ_ALL,
RouteType.READ_ONE,
RouteType.UPDATE,
RouteType.DELETE,
RouteType.CREATE,
]

if (only?.length) {
accessibleRoutes = accessibleRoutes.filter((elem) => {
return only?.includes(elem)
})
let accessibleRoutes: RouteType[] =
defaultExposeStrategy === 'none'
? []
: [
RouteType.READ_ALL,
RouteType.READ_ONE,
RouteType.UPDATE,
RouteType.DELETE,
RouteType.CREATE,
]

if (Array.isArray(only)) {
accessibleRoutes = only
}

if (exclude?.length) {
accessibleRoutes = accessibleRoutes.filter((elem) => {
return !exclude?.includes(elem)
return !exclude.includes(elem)
})
}

Expand Down

0 comments on commit 5eee6d0

Please sign in to comment.