@furystack/rest-service 12.3.5 → 14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -0
- package/README.md +47 -28
- package/esm/actions/get-current-user.spec.js +10 -6
- package/esm/actions/get-current-user.spec.js.map +1 -1
- package/esm/actions/index.d.ts +0 -1
- package/esm/actions/index.d.ts.map +1 -1
- package/esm/actions/index.js +0 -1
- package/esm/actions/index.js.map +1 -1
- package/esm/actions/is-authenticated.spec.js +10 -6
- package/esm/actions/is-authenticated.spec.js.map +1 -1
- package/esm/actions/logout-action.spec.js +11 -9
- package/esm/actions/logout-action.spec.js.map +1 -1
- package/esm/actions/logout.js +1 -1
- package/esm/actions/logout.js.map +1 -1
- package/esm/actions/password-login-action.js +1 -1
- package/esm/actions/password-login-action.js.map +1 -1
- package/esm/actions/password-login-action.spec.js +23 -28
- package/esm/actions/password-login-action.spec.js.map +1 -1
- package/esm/authenticate.js +1 -1
- package/esm/authenticate.js.map +1 -1
- package/esm/authenticate.spec.js +41 -33
- package/esm/authenticate.spec.js.map +1 -1
- package/esm/authorize.spec.js +34 -29
- package/esm/authorize.spec.js.map +1 -1
- package/esm/endpoint-generators/create-delete-endpoint.d.ts +6 -11
- package/esm/endpoint-generators/create-delete-endpoint.d.ts.map +1 -1
- package/esm/endpoint-generators/create-delete-endpoint.js +7 -11
- package/esm/endpoint-generators/create-delete-endpoint.js.map +1 -1
- package/esm/endpoint-generators/create-delete-endpoint.spec.js +14 -21
- package/esm/endpoint-generators/create-delete-endpoint.spec.js.map +1 -1
- package/esm/endpoint-generators/create-get-collection-endpoint.d.ts +11 -11
- package/esm/endpoint-generators/create-get-collection-endpoint.d.ts.map +1 -1
- package/esm/endpoint-generators/create-get-collection-endpoint.js +13 -12
- package/esm/endpoint-generators/create-get-collection-endpoint.js.map +1 -1
- package/esm/endpoint-generators/create-get-collection-endpoint.spec.js +43 -70
- package/esm/endpoint-generators/create-get-collection-endpoint.spec.js.map +1 -1
- package/esm/endpoint-generators/create-get-entity-endpoint.d.ts +6 -11
- package/esm/endpoint-generators/create-get-entity-endpoint.d.ts.map +1 -1
- package/esm/endpoint-generators/create-get-entity-endpoint.js +7 -11
- package/esm/endpoint-generators/create-get-entity-endpoint.js.map +1 -1
- package/esm/endpoint-generators/create-get-entity-endpoint.spec.js +16 -33
- package/esm/endpoint-generators/create-get-entity-endpoint.spec.js.map +1 -1
- package/esm/endpoint-generators/create-get-openapi-document-action.d.ts +1 -15
- package/esm/endpoint-generators/create-get-openapi-document-action.d.ts.map +1 -1
- package/esm/endpoint-generators/create-get-openapi-document-action.js +1 -24
- package/esm/endpoint-generators/create-get-openapi-document-action.js.map +1 -1
- package/esm/endpoint-generators/create-get-schema-action.d.ts +1 -1
- package/esm/endpoint-generators/create-get-schema-action.d.ts.map +1 -1
- package/esm/endpoint-generators/create-get-schema-action.js.map +1 -1
- package/esm/endpoint-generators/create-patch-endpoint.d.ts +7 -13
- package/esm/endpoint-generators/create-patch-endpoint.d.ts.map +1 -1
- package/esm/endpoint-generators/create-patch-endpoint.js +8 -13
- package/esm/endpoint-generators/create-patch-endpoint.js.map +1 -1
- package/esm/endpoint-generators/create-patch-endpoint.spec.js +10 -17
- package/esm/endpoint-generators/create-patch-endpoint.spec.js.map +1 -1
- package/esm/endpoint-generators/create-post-endpoint.d.ts +7 -13
- package/esm/endpoint-generators/create-post-endpoint.d.ts.map +1 -1
- package/esm/endpoint-generators/create-post-endpoint.js +8 -13
- package/esm/endpoint-generators/create-post-endpoint.js.map +1 -1
- package/esm/endpoint-generators/create-post-endpoint.spec.js +41 -14
- package/esm/endpoint-generators/create-post-endpoint.spec.js.map +1 -1
- package/esm/endpoint-generators/utils.d.ts +17 -2
- package/esm/endpoint-generators/utils.d.ts.map +1 -1
- package/esm/endpoint-generators/utils.js +33 -20
- package/esm/endpoint-generators/utils.js.map +1 -1
- package/esm/endpoint-generators/with-schema-and-openapi-action.d.ts +0 -2
- package/esm/endpoint-generators/with-schema-and-openapi-action.d.ts.map +1 -1
- package/esm/get-schema-from-api.d.ts +1 -1
- package/esm/get-schema-from-api.d.ts.map +1 -1
- package/esm/get-schema-from-api.spec.js.map +1 -1
- package/esm/helpers.d.ts +53 -87
- package/esm/helpers.d.ts.map +1 -1
- package/esm/helpers.js +91 -92
- package/esm/helpers.js.map +1 -1
- package/esm/helpers.spec.d.ts +2 -1
- package/esm/helpers.spec.d.ts.map +1 -1
- package/esm/helpers.spec.js +41 -38
- package/esm/helpers.spec.js.map +1 -1
- package/esm/http-authentication-settings.d.ts +35 -12
- package/esm/http-authentication-settings.d.ts.map +1 -1
- package/esm/http-authentication-settings.js +21 -29
- package/esm/http-authentication-settings.js.map +1 -1
- package/esm/http-server-pool.d.ts +64 -0
- package/esm/http-server-pool.d.ts.map +1 -0
- package/esm/http-server-pool.js +95 -0
- package/esm/http-server-pool.js.map +1 -0
- package/esm/http-server-pool.spec.d.ts +2 -0
- package/esm/http-server-pool.spec.d.ts.map +1 -0
- package/esm/http-server-pool.spec.js +193 -0
- package/esm/http-server-pool.spec.js.map +1 -0
- package/esm/http-user-context.d.ts +31 -44
- package/esm/http-user-context.d.ts.map +1 -1
- package/esm/http-user-context.js +76 -95
- package/esm/http-user-context.js.map +1 -1
- package/esm/http-user-context.spec.d.ts +8 -2
- package/esm/http-user-context.spec.d.ts.map +1 -1
- package/esm/http-user-context.spec.js +189 -337
- package/esm/http-user-context.spec.js.map +1 -1
- package/esm/index.d.ts +6 -4
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +6 -4
- package/esm/index.js.map +1 -1
- package/esm/login-response-strategy.d.ts +11 -10
- package/esm/login-response-strategy.d.ts.map +1 -1
- package/esm/login-response-strategy.js +7 -6
- package/esm/login-response-strategy.js.map +1 -1
- package/esm/login-response-strategy.spec.js +25 -29
- package/esm/login-response-strategy.spec.js.map +1 -1
- package/esm/openapi/generate-openapi-document.d.ts +0 -8
- package/esm/openapi/generate-openapi-document.d.ts.map +1 -1
- package/esm/openapi/generate-openapi-document.js +0 -2
- package/esm/openapi/generate-openapi-document.js.map +1 -1
- package/esm/proxy-manager.spec.js +152 -176
- package/esm/proxy-manager.spec.js.map +1 -1
- package/esm/proxy-runtime.d.ts +27 -0
- package/esm/proxy-runtime.d.ts.map +1 -0
- package/esm/proxy-runtime.js +45 -0
- package/esm/proxy-runtime.js.map +1 -0
- package/esm/proxy-runtime.spec.d.ts +2 -0
- package/esm/proxy-runtime.spec.d.ts.map +1 -0
- package/esm/proxy-runtime.spec.js +39 -0
- package/esm/proxy-runtime.spec.js.map +1 -0
- package/esm/rest-api-runtime.d.ts +76 -0
- package/esm/rest-api-runtime.d.ts.map +1 -0
- package/esm/rest-api-runtime.js +131 -0
- package/esm/rest-api-runtime.js.map +1 -0
- package/esm/rest-api-runtime.spec.d.ts +2 -0
- package/esm/rest-api-runtime.spec.d.ts.map +1 -0
- package/esm/rest-api-runtime.spec.js +58 -0
- package/esm/rest-api-runtime.spec.js.map +1 -0
- package/esm/rest-service.integration.spec.d.ts +1 -1
- package/esm/rest-service.integration.spec.d.ts.map +1 -1
- package/esm/rest-service.integration.spec.js +60 -82
- package/esm/rest-service.integration.spec.js.map +1 -1
- package/esm/rest.integration.test.js +26 -84
- package/esm/rest.integration.test.js.map +1 -1
- package/esm/server-telemetry.d.ts +57 -0
- package/esm/server-telemetry.d.ts.map +1 -0
- package/esm/server-telemetry.js +26 -0
- package/esm/server-telemetry.js.map +1 -0
- package/esm/server-telemetry.spec.d.ts +2 -0
- package/esm/server-telemetry.spec.d.ts.map +1 -0
- package/esm/server-telemetry.spec.js +52 -0
- package/esm/server-telemetry.spec.js.map +1 -0
- package/esm/static-server-manager.spec.js +60 -125
- package/esm/static-server-manager.spec.js.map +1 -1
- package/esm/static-site-runtime.d.ts +21 -0
- package/esm/static-site-runtime.d.ts.map +1 -0
- package/esm/static-site-runtime.js +48 -0
- package/esm/static-site-runtime.js.map +1 -0
- package/esm/static-site-runtime.spec.d.ts +2 -0
- package/esm/static-site-runtime.spec.d.ts.map +1 -0
- package/esm/static-site-runtime.spec.js +30 -0
- package/esm/static-site-runtime.spec.js.map +1 -0
- package/esm/user-store.d.ts +39 -0
- package/esm/user-store.d.ts.map +1 -0
- package/esm/user-store.js +62 -0
- package/esm/user-store.js.map +1 -0
- package/esm/user-store.spec.d.ts +2 -0
- package/esm/user-store.spec.d.ts.map +1 -0
- package/esm/user-store.spec.js +72 -0
- package/esm/user-store.spec.js.map +1 -0
- package/esm/validate.integration.spec.js +26 -83
- package/esm/validate.integration.spec.js.map +1 -1
- package/package.json +8 -8
- package/src/actions/get-current-user.spec.ts +11 -10
- package/src/actions/index.ts +0 -1
- package/src/actions/is-authenticated.spec.ts +12 -7
- package/src/actions/logout-action.spec.ts +12 -12
- package/src/actions/logout.ts +1 -1
- package/src/actions/password-login-action.spec.ts +30 -30
- package/src/actions/password-login-action.ts +1 -1
- package/src/authenticate.spec.ts +45 -51
- package/src/authenticate.ts +1 -1
- package/src/authorize.spec.ts +37 -39
- package/src/endpoint-generators/create-delete-endpoint.spec.ts +16 -24
- package/src/endpoint-generators/create-delete-endpoint.ts +11 -17
- package/src/endpoint-generators/create-get-collection-endpoint.spec.ts +45 -78
- package/src/endpoint-generators/create-get-collection-endpoint.ts +17 -19
- package/src/endpoint-generators/create-get-entity-endpoint.spec.ts +17 -33
- package/src/endpoint-generators/create-get-entity-endpoint.ts +11 -17
- package/src/endpoint-generators/create-get-openapi-document-action.ts +2 -38
- package/src/endpoint-generators/create-get-schema-action.ts +1 -1
- package/src/endpoint-generators/create-patch-endpoint.spec.ts +11 -18
- package/src/endpoint-generators/create-patch-endpoint.ts +12 -23
- package/src/endpoint-generators/create-post-endpoint.spec.ts +45 -14
- package/src/endpoint-generators/create-post-endpoint.ts +13 -23
- package/src/endpoint-generators/utils.ts +36 -28
- package/src/endpoint-generators/with-schema-and-openapi-action.ts +0 -3
- package/src/get-schema-from-api.spec.ts +1 -1
- package/src/get-schema-from-api.ts +1 -1
- package/src/helpers.spec.ts +51 -41
- package/src/helpers.ts +140 -109
- package/src/http-authentication-settings.ts +51 -25
- package/src/http-server-pool.spec.ts +220 -0
- package/src/http-server-pool.ts +169 -0
- package/src/http-user-context.spec.ts +203 -383
- package/src/http-user-context.ts +114 -91
- package/src/index.ts +6 -4
- package/src/login-response-strategy.spec.ts +32 -31
- package/src/login-response-strategy.ts +13 -12
- package/src/openapi/generate-openapi-document.ts +0 -3
- package/src/proxy-manager.spec.ts +152 -182
- package/src/proxy-runtime.spec.ts +50 -0
- package/src/proxy-runtime.ts +75 -0
- package/src/rest-api-runtime.spec.ts +77 -0
- package/src/rest-api-runtime.ts +204 -0
- package/src/rest-service.integration.spec.ts +68 -87
- package/src/rest.integration.test.ts +27 -87
- package/src/server-telemetry.spec.ts +56 -0
- package/src/server-telemetry.ts +51 -0
- package/src/static-server-manager.spec.ts +63 -151
- package/src/static-site-runtime.spec.ts +39 -0
- package/src/static-site-runtime.ts +75 -0
- package/src/user-store.spec.ts +86 -0
- package/src/user-store.ts +68 -0
- package/src/validate.integration.spec.ts +39 -97
- package/esm/actions/login-action.spec.d.ts +0 -2
- package/esm/actions/login-action.spec.d.ts.map +0 -1
- package/esm/actions/login-action.spec.js +0 -34
- package/esm/actions/login-action.spec.js.map +0 -1
- package/esm/actions/login.d.ts +0 -19
- package/esm/actions/login.d.ts.map +0 -1
- package/esm/actions/login.js +0 -27
- package/esm/actions/login.js.map +0 -1
- package/esm/api-manager.d.ts +0 -104
- package/esm/api-manager.d.ts.map +0 -1
- package/esm/api-manager.js +0 -180
- package/esm/api-manager.js.map +0 -1
- package/esm/proxy-manager.d.ts +0 -53
- package/esm/proxy-manager.d.ts.map +0 -1
- package/esm/proxy-manager.js +0 -84
- package/esm/proxy-manager.js.map +0 -1
- package/esm/server-manager.d.ts +0 -48
- package/esm/server-manager.d.ts.map +0 -1
- package/esm/server-manager.js +0 -100
- package/esm/server-manager.js.map +0 -1
- package/esm/static-server-manager.d.ts +0 -19
- package/esm/static-server-manager.d.ts.map +0 -1
- package/esm/static-server-manager.js +0 -65
- package/esm/static-server-manager.js.map +0 -1
- package/esm/swagger/generate-swagger-json.spec.d.ts +0 -2
- package/esm/swagger/generate-swagger-json.spec.d.ts.map +0 -1
- package/esm/swagger/generate-swagger-json.spec.js +0 -215
- package/esm/swagger/generate-swagger-json.spec.js.map +0 -1
- package/src/actions/login-action.spec.ts +0 -42
- package/src/actions/login.ts +0 -32
- package/src/api-manager.ts +0 -308
- package/src/proxy-manager.ts +0 -102
- package/src/server-manager.ts +0 -135
- package/src/static-server-manager.ts +0 -90
- package/src/swagger/generate-swagger-json.spec.ts +0 -250
package/src/authorize.spec.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { User } from '@furystack/core'
|
|
2
2
|
import { AuthorizationError, IdentityContext } from '@furystack/core'
|
|
3
|
-
import {
|
|
3
|
+
import { createInjector } from '@furystack/inject'
|
|
4
4
|
import { usingAsync } from '@furystack/utils'
|
|
5
5
|
import type { IncomingMessage, ServerResponse } from 'http'
|
|
6
6
|
import { describe, expect, it, vi } from 'vitest'
|
|
@@ -8,59 +8,57 @@ import { Authorize } from './authorize.js'
|
|
|
8
8
|
import { EmptyResult } from './request-action-implementation.js'
|
|
9
9
|
|
|
10
10
|
describe('Authorize', () => {
|
|
11
|
-
const response = {} as
|
|
11
|
+
const response = {} as ServerResponse
|
|
12
12
|
const request = { url: 'http://google.com' } as IncomingMessage
|
|
13
13
|
|
|
14
|
-
it('
|
|
15
|
-
await usingAsync(
|
|
16
|
-
const
|
|
17
|
-
i.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
14
|
+
it('throws AuthorizationError when the current user cannot be resolved', async () => {
|
|
15
|
+
await usingAsync(createInjector(), async (i) => {
|
|
16
|
+
const isAuthorized = vi.fn(async () => false)
|
|
17
|
+
i.bind(IdentityContext, () => ({
|
|
18
|
+
isAuthorized,
|
|
19
|
+
getCurrentUser: () => Promise.reject(new Error(':(')),
|
|
20
|
+
isAuthenticated: () => Promise.resolve(false),
|
|
21
|
+
}))
|
|
22
|
+
const exampleAction = vi.fn(async () => EmptyResult())
|
|
23
|
+
const authorized = Authorize('Role1')(exampleAction)
|
|
23
24
|
|
|
24
25
|
await expect(() => authorized({ injector: i, request, response })).rejects.toThrow(AuthorizationError)
|
|
25
|
-
expect(
|
|
26
|
+
expect(exampleAction).not.toHaveBeenCalled()
|
|
26
27
|
})
|
|
27
28
|
})
|
|
28
29
|
|
|
29
|
-
it('
|
|
30
|
-
await usingAsync(
|
|
31
|
-
const
|
|
32
|
-
i.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
)
|
|
39
|
-
const
|
|
40
|
-
const authorized = Authorize('Role2')(exampleAuthorizedAction)
|
|
30
|
+
it('throws AuthorizationError when the current user does not have the required role', async () => {
|
|
31
|
+
await usingAsync(createInjector(), async (i) => {
|
|
32
|
+
const isAuthorized = vi.fn(async () => false)
|
|
33
|
+
i.bind(IdentityContext, () => ({
|
|
34
|
+
isAuthorized,
|
|
35
|
+
getCurrentUser: <TUser extends User>() =>
|
|
36
|
+
Promise.resolve({ username: 'a', roles: ['Role1'] } as unknown as TUser),
|
|
37
|
+
isAuthenticated: () => Promise.resolve(true),
|
|
38
|
+
}))
|
|
39
|
+
const exampleAction = vi.fn(async () => EmptyResult())
|
|
40
|
+
const authorized = Authorize('Role2')(exampleAction)
|
|
41
41
|
|
|
42
42
|
await expect(() => authorized({ injector: i, request, response })).rejects.toThrow(AuthorizationError)
|
|
43
|
-
expect(
|
|
43
|
+
expect(exampleAction).not.toHaveBeenCalled()
|
|
44
44
|
})
|
|
45
45
|
})
|
|
46
46
|
|
|
47
|
-
it('
|
|
48
|
-
await usingAsync(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
)
|
|
57
|
-
const
|
|
58
|
-
const authorized = Authorize('Role1')(exampleAuthorizedAction)
|
|
59
|
-
const params = { injector: i, body: undefined, query: undefined, request, response }
|
|
47
|
+
it('invokes the wrapped action when the current user holds the required role', async () => {
|
|
48
|
+
await usingAsync(createInjector(), async (i) => {
|
|
49
|
+
i.bind(IdentityContext, () => ({
|
|
50
|
+
isAuthorized: () => Promise.resolve(true),
|
|
51
|
+
getCurrentUser: <TUser extends User>() =>
|
|
52
|
+
Promise.resolve({ username: 'a', roles: ['Role1'] } as unknown as TUser),
|
|
53
|
+
isAuthenticated: () => Promise.resolve(true),
|
|
54
|
+
}))
|
|
55
|
+
const exampleAction = vi.fn(async () => EmptyResult())
|
|
56
|
+
const authorized = Authorize('Role1')(exampleAction)
|
|
57
|
+
const params = { injector: i, request, response }
|
|
60
58
|
const result = await authorized(params)
|
|
61
59
|
expect(result.statusCode).toBe(200)
|
|
62
60
|
expect(result.chunk).toBe(undefined)
|
|
63
|
-
expect(
|
|
61
|
+
expect(exampleAction).toHaveBeenCalledWith(params)
|
|
64
62
|
})
|
|
65
63
|
})
|
|
66
64
|
})
|
|
@@ -1,40 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { getPort } from '@furystack/core/port-generator'
|
|
2
|
+
import { createInjector } from '@furystack/inject'
|
|
3
3
|
import type { DeleteEndpoint } from '@furystack/rest'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { usingAsync } from '@furystack/utils'
|
|
5
|
+
import { describe, expect, it } from 'vitest'
|
|
6
6
|
import { useRestService } from '../helpers.js'
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { createDeleteEndpoint } from './create-delete-endpoint.js'
|
|
8
|
+
import type { MockClass } from './utils.js'
|
|
9
|
+
import { MockDataSet, setupContext } from './utils.js'
|
|
10
10
|
|
|
11
11
|
describe('createDeleteEndpoint', () => {
|
|
12
|
-
it('
|
|
13
|
-
await usingAsync(
|
|
14
|
-
const port = getPort()
|
|
12
|
+
it('deletes the entity and responds 204', async () => {
|
|
13
|
+
await usingAsync(createInjector(), async (i) => {
|
|
15
14
|
setupContext(i)
|
|
15
|
+
const port = getPort()
|
|
16
16
|
await useRestService<{ DELETE: { '/:id': DeleteEndpoint<MockClass, 'id'> } }>({
|
|
17
17
|
injector: i,
|
|
18
18
|
root: '/api',
|
|
19
19
|
port,
|
|
20
|
-
api: {
|
|
21
|
-
DELETE: {
|
|
22
|
-
'/:id': createDeleteEndpoint({ model: MockClass, primaryKey: 'id' }),
|
|
23
|
-
},
|
|
24
|
-
},
|
|
20
|
+
api: { DELETE: { '/:id': createDeleteEndpoint(MockDataSet) } },
|
|
25
21
|
})
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
expect(countBeforeDelete).toBe(1)
|
|
22
|
+
const dataSet = i.get(MockDataSet)
|
|
23
|
+
await dataSet.add(i, { id: 'mock', value: 'mock' })
|
|
24
|
+
expect(await dataSet.count(i)).toBe(1)
|
|
30
25
|
|
|
31
26
|
const response = await fetch(`http://127.0.0.1:${port}/api/mock`, { method: 'DELETE' })
|
|
32
27
|
expect(response.status).toBe(204)
|
|
33
|
-
|
|
34
|
-
expect(
|
|
35
|
-
|
|
36
|
-
const countAfterDelete = await getDataSetFor(i, MockClass, 'id').count(i)
|
|
37
|
-
expect(countAfterDelete).toBe(0)
|
|
28
|
+
expect(await response.text()).toBe('')
|
|
29
|
+
expect(await dataSet.count(i)).toBe(0)
|
|
38
30
|
})
|
|
39
31
|
})
|
|
40
32
|
})
|
|
@@ -1,25 +1,19 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DataSetToken } from '@furystack/repository'
|
|
2
2
|
import type { DeleteEndpoint } from '@furystack/rest'
|
|
3
|
-
import type
|
|
4
|
-
import { JsonResult } from '../request-action-implementation.js'
|
|
5
|
-
import { getRepository } from '@furystack/repository'
|
|
3
|
+
import { JsonResult, type RequestAction } from '../request-action-implementation.js'
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
|
-
* Creates a DELETE endpoint
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* @param options.primaryKey The field used as primary key on the model
|
|
12
|
-
* @returns a boolean that indicates the success
|
|
6
|
+
* Creates a DELETE endpoint that removes the entity identified by the URL's
|
|
7
|
+
* `:id` parameter. Returns `204 No Content` once the removal has been
|
|
8
|
+
* persisted to the underlying store.
|
|
13
9
|
*/
|
|
14
|
-
export const createDeleteEndpoint = <T extends object, TPrimaryKey extends keyof T>(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}) => {
|
|
18
|
-
const endpoint: RequestAction<DeleteEndpoint<T, TPrimaryKey>> = async ({ injector, getUrlParams }) => {
|
|
10
|
+
export const createDeleteEndpoint = <T extends object, TPrimaryKey extends keyof T>(
|
|
11
|
+
dataSet: DataSetToken<T, TPrimaryKey>,
|
|
12
|
+
): RequestAction<DeleteEndpoint<T, TPrimaryKey>> => {
|
|
13
|
+
return async ({ injector, getUrlParams }) => {
|
|
19
14
|
const { id } = getUrlParams()
|
|
20
|
-
const
|
|
21
|
-
await
|
|
15
|
+
const ds = injector.get(dataSet)
|
|
16
|
+
await ds.remove(injector, id)
|
|
22
17
|
return JsonResult({}, 204)
|
|
23
18
|
}
|
|
24
|
-
return endpoint
|
|
25
19
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { createGetCollectionEndpoint } from './create-get-collection-endpoint.js'
|
|
1
|
+
import type { FindOptions } from '@furystack/core'
|
|
2
|
+
import { getPort } from '@furystack/core/port-generator'
|
|
3
|
+
import { createInjector, type Injector } from '@furystack/inject'
|
|
5
4
|
import type { GetCollectionEndpoint, GetCollectionResult } from '@furystack/rest'
|
|
6
5
|
import { serializeToQueryString } from '@furystack/rest'
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
6
|
+
import { usingAsync } from '@furystack/utils'
|
|
7
|
+
import { describe, expect, it } from 'vitest'
|
|
9
8
|
import { useRestService } from '../helpers.js'
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
9
|
+
import { createGetCollectionEndpoint } from './create-get-collection-endpoint.js'
|
|
10
|
+
import type { MockClass } from './utils.js'
|
|
11
|
+
import { MockDataSet, setupContext } from './utils.js'
|
|
12
12
|
|
|
13
13
|
const addMockEntities = async (i: Injector) =>
|
|
14
|
-
|
|
15
|
-
.
|
|
14
|
+
i
|
|
15
|
+
.get(MockDataSet)
|
|
16
16
|
.add(
|
|
17
17
|
i,
|
|
18
18
|
{ id: 'mock1', value: '4' },
|
|
@@ -22,24 +22,21 @@ const addMockEntities = async (i: Injector) =>
|
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
describe('createGetCollectionEndpoint', () => {
|
|
25
|
-
it('
|
|
26
|
-
await usingAsync(
|
|
25
|
+
it('returns the collection without filter / order', async () => {
|
|
26
|
+
await usingAsync(createInjector(), async (i) => {
|
|
27
27
|
setupContext(i)
|
|
28
28
|
const port = getPort()
|
|
29
29
|
await useRestService<{ GET: { '/entities': GetCollectionEndpoint<MockClass> } }>({
|
|
30
30
|
injector: i,
|
|
31
31
|
root: '/api',
|
|
32
32
|
port,
|
|
33
|
-
api: {
|
|
34
|
-
GET: {
|
|
35
|
-
'/entities': createGetCollectionEndpoint({ model: MockClass, primaryKey: 'id' }),
|
|
36
|
-
},
|
|
37
|
-
},
|
|
33
|
+
api: { GET: { '/entities': createGetCollectionEndpoint(MockDataSet) } },
|
|
38
34
|
})
|
|
39
35
|
await addMockEntities(i)
|
|
40
36
|
|
|
41
|
-
const
|
|
42
|
-
const
|
|
37
|
+
const dataSet = i.get(MockDataSet)
|
|
38
|
+
const count = await dataSet.count(i)
|
|
39
|
+
const allEntities = await dataSet.find(i, {})
|
|
43
40
|
|
|
44
41
|
const response = await fetch(`http://127.0.0.1:${port}/api/entities`, { method: 'GET' })
|
|
45
42
|
expect(response.ok).toBe(true)
|
|
@@ -50,24 +47,21 @@ describe('createGetCollectionEndpoint', () => {
|
|
|
50
47
|
})
|
|
51
48
|
})
|
|
52
49
|
|
|
53
|
-
it('
|
|
54
|
-
await usingAsync(
|
|
50
|
+
it('returns entities in the requested order', async () => {
|
|
51
|
+
await usingAsync(createInjector(), async (i) => {
|
|
55
52
|
setupContext(i)
|
|
56
53
|
const port = getPort()
|
|
57
54
|
await useRestService<{ GET: { '/entities': GetCollectionEndpoint<MockClass> } }>({
|
|
58
55
|
injector: i,
|
|
59
56
|
root: '/api',
|
|
60
57
|
port,
|
|
61
|
-
api: {
|
|
62
|
-
GET: {
|
|
63
|
-
'/entities': createGetCollectionEndpoint({ model: MockClass, primaryKey: 'id' }),
|
|
64
|
-
},
|
|
65
|
-
},
|
|
58
|
+
api: { GET: { '/entities': createGetCollectionEndpoint(MockDataSet) } },
|
|
66
59
|
})
|
|
67
60
|
await addMockEntities(i)
|
|
68
61
|
const findOptions: FindOptions<MockClass, Array<keyof MockClass>> = { order: { value: 'ASC' } }
|
|
69
|
-
const
|
|
70
|
-
const
|
|
62
|
+
const dataSet = i.get(MockDataSet)
|
|
63
|
+
const count = await dataSet.count(i, findOptions.filter)
|
|
64
|
+
const orderedEntities = await dataSet.find(i, findOptions)
|
|
71
65
|
const response = await fetch(`http://127.0.0.1:${port}/api/entities?${serializeToQueryString({ findOptions })}`, {
|
|
72
66
|
method: 'GET',
|
|
73
67
|
})
|
|
@@ -79,29 +73,21 @@ describe('createGetCollectionEndpoint', () => {
|
|
|
79
73
|
})
|
|
80
74
|
})
|
|
81
75
|
|
|
82
|
-
it('
|
|
83
|
-
await usingAsync(
|
|
76
|
+
it('applies a supplied filter', async () => {
|
|
77
|
+
await usingAsync(createInjector(), async (i) => {
|
|
84
78
|
setupContext(i)
|
|
85
79
|
const port = getPort()
|
|
86
80
|
await useRestService<{ GET: { '/entities': GetCollectionEndpoint<MockClass> } }>({
|
|
87
81
|
injector: i,
|
|
88
82
|
root: '/api',
|
|
89
83
|
port,
|
|
90
|
-
api: {
|
|
91
|
-
GET: {
|
|
92
|
-
'/entities': createGetCollectionEndpoint({ model: MockClass, primaryKey: 'id' }),
|
|
93
|
-
},
|
|
94
|
-
},
|
|
84
|
+
api: { GET: { '/entities': createGetCollectionEndpoint(MockDataSet) } },
|
|
95
85
|
})
|
|
96
86
|
await addMockEntities(i)
|
|
97
|
-
const findOptions: FindOptions<MockClass, Array<keyof MockClass>> = {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const count = await getDataSetFor(i, MockClass, 'id').count(i, findOptions.filter)
|
|
102
|
-
const filteredEntities = await getDataSetFor(i, MockClass, 'id').find(i, findOptions)
|
|
103
|
-
|
|
104
|
-
expect(filteredEntities).not.toContainEqual({ id: 'mock2', value: '3' })
|
|
87
|
+
const findOptions: FindOptions<MockClass, Array<keyof MockClass>> = { filter: { id: { $ne: 'mock2' } } }
|
|
88
|
+
const dataSet = i.get(MockDataSet)
|
|
89
|
+
const count = await dataSet.count(i, findOptions.filter)
|
|
90
|
+
const filteredEntities = await dataSet.find(i, findOptions)
|
|
105
91
|
|
|
106
92
|
const response = await fetch(`http://127.0.0.1:${port}/api/entities?${serializeToQueryString({ findOptions })}`, {
|
|
107
93
|
method: 'GET',
|
|
@@ -114,67 +100,48 @@ describe('createGetCollectionEndpoint', () => {
|
|
|
114
100
|
})
|
|
115
101
|
})
|
|
116
102
|
|
|
117
|
-
it('
|
|
118
|
-
await usingAsync(
|
|
103
|
+
it('applies select projection', async () => {
|
|
104
|
+
await usingAsync(createInjector(), async (i) => {
|
|
119
105
|
setupContext(i)
|
|
120
106
|
const port = getPort()
|
|
121
107
|
await useRestService<{ GET: { '/entities': GetCollectionEndpoint<MockClass> } }>({
|
|
122
108
|
injector: i,
|
|
123
109
|
root: '/api',
|
|
124
110
|
port,
|
|
125
|
-
api: {
|
|
126
|
-
GET: {
|
|
127
|
-
'/entities': createGetCollectionEndpoint({ model: MockClass, primaryKey: 'id' }),
|
|
128
|
-
},
|
|
129
|
-
},
|
|
111
|
+
api: { GET: { '/entities': createGetCollectionEndpoint(MockDataSet) } },
|
|
130
112
|
})
|
|
131
113
|
await addMockEntities(i)
|
|
132
|
-
const findOptions: FindOptions<MockClass, Array<keyof MockClass>> = {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const count = await getDataSetFor(i, MockClass, 'id').count(i, findOptions.filter)
|
|
137
|
-
const selectedEntities = await getDataSetFor(i, MockClass, 'id').find(i, findOptions)
|
|
138
|
-
|
|
139
|
-
selectedEntities.forEach((e) => expect(e.value).toBeUndefined())
|
|
114
|
+
const findOptions: FindOptions<MockClass, Array<keyof MockClass>> = { select: ['id'] }
|
|
115
|
+
const dataSet = i.get(MockDataSet)
|
|
116
|
+
const count = await dataSet.count(i, findOptions.filter)
|
|
117
|
+
const selected = await dataSet.find(i, findOptions)
|
|
140
118
|
|
|
141
119
|
const response = await fetch(`http://127.0.0.1:${port}/api/entities?${serializeToQueryString({ findOptions })}`, {
|
|
142
120
|
method: 'GET',
|
|
143
121
|
})
|
|
144
|
-
|
|
145
122
|
expect(response.ok).toBe(true)
|
|
146
123
|
const json = (await response.json()) as GetCollectionResult<MockClass>
|
|
147
124
|
expect(response.status).toBe(200)
|
|
148
125
|
expect(json.count).toBe(count)
|
|
149
|
-
expect(json.entries).toEqual(
|
|
126
|
+
expect(json.entries).toEqual(selected)
|
|
150
127
|
})
|
|
151
128
|
})
|
|
152
129
|
|
|
153
|
-
it('
|
|
154
|
-
await usingAsync(
|
|
130
|
+
it('honours top/skip', async () => {
|
|
131
|
+
await usingAsync(createInjector(), async (i) => {
|
|
155
132
|
setupContext(i)
|
|
156
133
|
const port = getPort()
|
|
157
134
|
await useRestService<{ GET: { '/entities': GetCollectionEndpoint<MockClass> } }>({
|
|
158
135
|
injector: i,
|
|
159
136
|
root: '/api',
|
|
160
137
|
port,
|
|
161
|
-
api: {
|
|
162
|
-
GET: {
|
|
163
|
-
'/entities': createGetCollectionEndpoint({ model: MockClass, primaryKey: 'id' }),
|
|
164
|
-
},
|
|
165
|
-
},
|
|
138
|
+
api: { GET: { '/entities': createGetCollectionEndpoint(MockDataSet) } },
|
|
166
139
|
})
|
|
167
140
|
await addMockEntities(i)
|
|
168
|
-
const findOptions: FindOptions<MockClass, Array<keyof MockClass>> = {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const count = await getDataSetFor(i, MockClass, 'id').count(i, findOptions.filter)
|
|
174
|
-
const topSkipEntities = await getDataSetFor(i, MockClass, 'id').find(i, findOptions)
|
|
175
|
-
|
|
176
|
-
expect(topSkipEntities).not.toContainEqual({ id: 'mock1', value: '4' })
|
|
177
|
-
expect(topSkipEntities).not.toContainEqual({ id: 'mock4', value: '1' })
|
|
141
|
+
const findOptions: FindOptions<MockClass, Array<keyof MockClass>> = { skip: 1, top: 2 }
|
|
142
|
+
const dataSet = i.get(MockDataSet)
|
|
143
|
+
const count = await dataSet.count(i, findOptions.filter)
|
|
144
|
+
const page = await dataSet.find(i, findOptions)
|
|
178
145
|
|
|
179
146
|
const response = await fetch(`http://127.0.0.1:${port}/api/entities?${serializeToQueryString({ findOptions })}`, {
|
|
180
147
|
method: 'GET',
|
|
@@ -182,7 +149,7 @@ describe('createGetCollectionEndpoint', () => {
|
|
|
182
149
|
expect(response.status).toBe(200)
|
|
183
150
|
const json = (await response.json()) as GetCollectionResult<MockClass>
|
|
184
151
|
expect(json.count).toBe(count)
|
|
185
|
-
expect(json.entries).toEqual(
|
|
152
|
+
expect(json.entries).toEqual(page)
|
|
186
153
|
})
|
|
187
154
|
})
|
|
188
155
|
})
|
|
@@ -1,28 +1,26 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DataSetToken } from '@furystack/repository'
|
|
2
2
|
import type { GetCollectionEndpoint } from '@furystack/rest'
|
|
3
|
-
import type
|
|
4
|
-
import { JsonResult } from '../request-action-implementation.js'
|
|
5
|
-
import { getRepository } from '@furystack/repository'
|
|
3
|
+
import { JsonResult, type RequestAction } from '../request-action-implementation.js'
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
|
-
* Creates a GetCollection endpoint
|
|
9
|
-
* @
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @
|
|
6
|
+
* Creates a GetCollection endpoint backed by the DataSet resolved from the
|
|
7
|
+
* provided {@link DataSetToken}. The token carries the entity model and
|
|
8
|
+
* primary key, so callers no longer need to pass them separately.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const endpoint = createGetCollectionEndpoint(UserDataSet)
|
|
13
|
+
* ```
|
|
13
14
|
*/
|
|
14
|
-
export const createGetCollectionEndpoint = <T, TPrimaryKey extends keyof T>(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}) => {
|
|
18
|
-
const endpoint: RequestAction<GetCollectionEndpoint<T>> = async ({ injector, getQuery }) => {
|
|
15
|
+
export const createGetCollectionEndpoint = <T, TPrimaryKey extends keyof T>(
|
|
16
|
+
dataSet: DataSetToken<T, TPrimaryKey>,
|
|
17
|
+
): RequestAction<GetCollectionEndpoint<T>> => {
|
|
18
|
+
return async ({ injector, getQuery }) => {
|
|
19
19
|
const { findOptions } = getQuery()
|
|
20
|
-
const
|
|
21
|
-
const entriesPromise =
|
|
22
|
-
const countPromise =
|
|
20
|
+
const ds = injector.get(dataSet)
|
|
21
|
+
const entriesPromise = ds.find(injector, findOptions || {})
|
|
22
|
+
const countPromise = ds.count(injector, findOptions?.filter)
|
|
23
23
|
const [entries, count] = await Promise.all([entriesPromise, countPromise])
|
|
24
|
-
|
|
25
24
|
return JsonResult({ entries, count })
|
|
26
25
|
}
|
|
27
|
-
return endpoint
|
|
28
26
|
}
|
|
@@ -1,83 +1,67 @@
|
|
|
1
1
|
import { getPort } from '@furystack/core/port-generator'
|
|
2
|
-
import {
|
|
3
|
-
import { getDataSetFor } from '@furystack/repository'
|
|
2
|
+
import { createInjector } from '@furystack/inject'
|
|
4
3
|
import type { GetEntityEndpoint } from '@furystack/rest'
|
|
5
4
|
import { serializeToQueryString } from '@furystack/rest'
|
|
6
5
|
import { usingAsync } from '@furystack/utils'
|
|
7
6
|
import { describe, expect, it } from 'vitest'
|
|
8
7
|
import { useRestService } from '../helpers.js'
|
|
9
8
|
import { createGetEntityEndpoint } from './create-get-entity-endpoint.js'
|
|
10
|
-
import { MockClass
|
|
9
|
+
import type { MockClass } from './utils.js'
|
|
10
|
+
import { MockDataSet, setupContext } from './utils.js'
|
|
11
11
|
|
|
12
12
|
describe('createGetEntityEndpoint', () => {
|
|
13
|
-
it('
|
|
14
|
-
await usingAsync(
|
|
13
|
+
it('returns the entity by id', async () => {
|
|
14
|
+
await usingAsync(createInjector(), async (i) => {
|
|
15
15
|
setupContext(i)
|
|
16
16
|
const port = getPort()
|
|
17
17
|
await useRestService<{ GET: { '/:id': GetEntityEndpoint<MockClass, 'id'> } }>({
|
|
18
18
|
injector: i,
|
|
19
19
|
root: '/api',
|
|
20
20
|
port,
|
|
21
|
-
api: {
|
|
22
|
-
GET: {
|
|
23
|
-
'/:id': createGetEntityEndpoint({ model: MockClass, primaryKey: 'id' }),
|
|
24
|
-
},
|
|
25
|
-
},
|
|
21
|
+
api: { GET: { '/:id': createGetEntityEndpoint(MockDataSet) } },
|
|
26
22
|
})
|
|
27
23
|
const mockEntity: MockClass = { id: 'mock', value: 'mock' }
|
|
28
|
-
await
|
|
24
|
+
await i.get(MockDataSet).add(i, mockEntity)
|
|
29
25
|
|
|
30
26
|
const response = await fetch(`http://127.0.0.1:${port}/api/mock`, { method: 'GET' })
|
|
31
27
|
expect(response.status).toBe(200)
|
|
32
|
-
|
|
33
|
-
expect(body).toEqual(mockEntity)
|
|
28
|
+
expect(await response.json()).toEqual(mockEntity)
|
|
34
29
|
})
|
|
35
30
|
})
|
|
36
31
|
|
|
37
|
-
it('
|
|
38
|
-
await usingAsync(
|
|
32
|
+
it('honours a select query parameter', async () => {
|
|
33
|
+
await usingAsync(createInjector(), async (i) => {
|
|
39
34
|
setupContext(i)
|
|
40
35
|
const port = getPort()
|
|
41
36
|
await useRestService<{ GET: { '/:id': GetEntityEndpoint<MockClass, 'id'> } }>({
|
|
42
37
|
injector: i,
|
|
43
38
|
root: '/api',
|
|
44
39
|
port,
|
|
45
|
-
api: {
|
|
46
|
-
GET: {
|
|
47
|
-
'/:id': createGetEntityEndpoint({ model: MockClass, primaryKey: 'id' }),
|
|
48
|
-
},
|
|
49
|
-
},
|
|
40
|
+
api: { GET: { '/:id': createGetEntityEndpoint(MockDataSet) } },
|
|
50
41
|
})
|
|
51
|
-
|
|
52
|
-
await getDataSetFor(i, MockClass, 'id').add(i, mockEntity)
|
|
42
|
+
await i.get(MockDataSet).add(i, { id: 'mock', value: 'mock' })
|
|
53
43
|
|
|
54
44
|
const response = await fetch(`http://127.0.0.1:${port}/api/mock?${serializeToQueryString({ select: ['id'] })}`, {
|
|
55
45
|
method: 'GET',
|
|
56
46
|
})
|
|
57
47
|
expect(response.status).toBe(200)
|
|
58
|
-
|
|
59
|
-
expect(body).toEqual({ id: mockEntity.id })
|
|
48
|
+
expect(await response.json()).toEqual({ id: 'mock' })
|
|
60
49
|
})
|
|
61
50
|
})
|
|
62
51
|
|
|
63
|
-
it('
|
|
64
|
-
await usingAsync(
|
|
52
|
+
it('responds with 404 when the entity does not exist', async () => {
|
|
53
|
+
await usingAsync(createInjector(), async (i) => {
|
|
65
54
|
setupContext(i)
|
|
66
55
|
const port = getPort()
|
|
67
56
|
await useRestService<{ GET: { '/:id': GetEntityEndpoint<MockClass, 'id'> } }>({
|
|
68
57
|
injector: i,
|
|
69
58
|
root: '/api',
|
|
70
59
|
port,
|
|
71
|
-
api: {
|
|
72
|
-
GET: {
|
|
73
|
-
'/:id': createGetEntityEndpoint({ model: MockClass, primaryKey: 'id' }),
|
|
74
|
-
},
|
|
75
|
-
},
|
|
60
|
+
api: { GET: { '/:id': createGetEntityEndpoint(MockDataSet) } },
|
|
76
61
|
})
|
|
77
62
|
const result = await fetch(`http://127.0.0.1:${port}/api/mock`, { method: 'GET' })
|
|
78
63
|
expect(result.status).toBe(404)
|
|
79
|
-
|
|
80
|
-
expect(body).toEqual({ message: 'Entity not found' })
|
|
64
|
+
expect(await result.json()).toEqual({ message: 'Entity not found' })
|
|
81
65
|
})
|
|
82
66
|
})
|
|
83
67
|
})
|
|
@@ -1,30 +1,24 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DataSetToken } from '@furystack/repository'
|
|
2
2
|
import type { GetEntityEndpoint } from '@furystack/rest'
|
|
3
3
|
import { RequestError } from '@furystack/rest'
|
|
4
|
-
import type
|
|
5
|
-
import { JsonResult } from '../request-action-implementation.js'
|
|
6
|
-
import { getRepository } from '@furystack/repository'
|
|
4
|
+
import { JsonResult, type RequestAction } from '../request-action-implementation.js'
|
|
7
5
|
|
|
8
6
|
/**
|
|
9
|
-
* Creates a
|
|
10
|
-
* @
|
|
11
|
-
*
|
|
12
|
-
* @param options.primaryKey The field name used as primary key on the model
|
|
13
|
-
* @returns The generated endpoint
|
|
7
|
+
* Creates a GET entity endpoint backed by the DataSet resolved from the
|
|
8
|
+
* provided {@link DataSetToken}. Throws a 404 `RequestError` when the
|
|
9
|
+
* entity cannot be found.
|
|
14
10
|
*/
|
|
15
|
-
export const createGetEntityEndpoint = <T extends object, TPrimaryKey extends keyof T>(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}) => {
|
|
19
|
-
const endpoint: RequestAction<GetEntityEndpoint<T, TPrimaryKey>> = async ({ injector, getUrlParams, getQuery }) => {
|
|
11
|
+
export const createGetEntityEndpoint = <T extends object, TPrimaryKey extends keyof T>(
|
|
12
|
+
dataSet: DataSetToken<T, TPrimaryKey>,
|
|
13
|
+
): RequestAction<GetEntityEndpoint<T, TPrimaryKey>> => {
|
|
14
|
+
return async ({ injector, getUrlParams, getQuery }) => {
|
|
20
15
|
const { id } = getUrlParams()
|
|
21
16
|
const { select } = getQuery()
|
|
22
|
-
const
|
|
23
|
-
const entry = await
|
|
17
|
+
const ds = injector.get(dataSet)
|
|
18
|
+
const entry = await ds.get(injector, id, select)
|
|
24
19
|
if (!entry) {
|
|
25
20
|
throw new RequestError('Entity not found', 404)
|
|
26
21
|
}
|
|
27
22
|
return JsonResult(entry)
|
|
28
23
|
}
|
|
29
|
-
return endpoint
|
|
30
24
|
}
|