@furystack/rest-service 4.0.19
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/LICENSE +339 -0
- package/README.md +219 -0
- package/dist/actions/error-action.d.ts +14 -0
- package/dist/actions/error-action.d.ts.map +1 -0
- package/dist/actions/error-action.js +29 -0
- package/dist/actions/error-action.js.map +1 -0
- package/dist/actions/error-action.spec.d.ts +2 -0
- package/dist/actions/error-action.spec.d.ts.map +1 -0
- package/dist/actions/error-action.spec.js +51 -0
- package/dist/actions/error-action.spec.js.map +1 -0
- package/dist/actions/get-current-user.d.ts +11 -0
- package/dist/actions/get-current-user.d.ts.map +1 -0
- package/dist/actions/get-current-user.js +15 -0
- package/dist/actions/get-current-user.js.map +1 -0
- package/dist/actions/get-current-user.spec.d.ts +2 -0
- package/dist/actions/get-current-user.spec.d.ts.map +1 -0
- package/dist/actions/get-current-user.spec.js +20 -0
- package/dist/actions/get-current-user.spec.js.map +1 -0
- package/dist/actions/index.d.ts +7 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/index.js +10 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/actions/is-authenticated.d.ts +14 -0
- package/dist/actions/is-authenticated.d.ts.map +1 -0
- package/dist/actions/is-authenticated.js +17 -0
- package/dist/actions/is-authenticated.js.map +1 -0
- package/dist/actions/is-authenticated.spec.d.ts +2 -0
- package/dist/actions/is-authenticated.spec.d.ts.map +1 -0
- package/dist/actions/is-authenticated.spec.js +19 -0
- package/dist/actions/is-authenticated.spec.js.map +1 -0
- package/dist/actions/login-action.spec.d.ts +2 -0
- package/dist/actions/login-action.spec.d.ts.map +1 -0
- package/dist/actions/login-action.spec.js +35 -0
- package/dist/actions/login-action.spec.js.map +1 -0
- package/dist/actions/login.d.ts +16 -0
- package/dist/actions/login.d.ts.map +1 -0
- package/dist/actions/login.js +26 -0
- package/dist/actions/login.js.map +1 -0
- package/dist/actions/logout-action.spec.d.ts +2 -0
- package/dist/actions/logout-action.spec.d.ts.map +1 -0
- package/dist/actions/logout-action.spec.js +23 -0
- package/dist/actions/logout-action.spec.js.map +1 -0
- package/dist/actions/logout.d.ts +14 -0
- package/dist/actions/logout.d.ts.map +1 -0
- package/dist/actions/logout.js +20 -0
- package/dist/actions/logout.js.map +1 -0
- package/dist/actions/not-found-action.d.ts +10 -0
- package/dist/actions/not-found-action.d.ts.map +1 -0
- package/dist/actions/not-found-action.js +14 -0
- package/dist/actions/not-found-action.js.map +1 -0
- package/dist/actions/not-found-action.spec.d.ts +2 -0
- package/dist/actions/not-found-action.spec.d.ts.map +1 -0
- package/dist/actions/not-found-action.spec.js +17 -0
- package/dist/actions/not-found-action.spec.js.map +1 -0
- package/dist/add-cors-header.spec.d.ts +2 -0
- package/dist/add-cors-header.spec.d.ts.map +1 -0
- package/dist/add-cors-header.spec.js +99 -0
- package/dist/add-cors-header.spec.js.map +1 -0
- package/dist/api-manager.d.ts +61 -0
- package/dist/api-manager.d.ts.map +1 -0
- package/dist/api-manager.js +144 -0
- package/dist/api-manager.js.map +1 -0
- package/dist/authenticate.d.ts +5 -0
- package/dist/authenticate.d.ts.map +1 -0
- package/dist/authenticate.js +20 -0
- package/dist/authenticate.js.map +1 -0
- package/dist/authenticate.spec.d.ts +2 -0
- package/dist/authenticate.spec.d.ts.map +1 -0
- package/dist/authenticate.spec.js +59 -0
- package/dist/authenticate.spec.js.map +1 -0
- package/dist/authorize.d.ts +5 -0
- package/dist/authorize.d.ts.map +1 -0
- package/dist/authorize.js +22 -0
- package/dist/authorize.js.map +1 -0
- package/dist/authorize.spec.d.ts +2 -0
- package/dist/authorize.spec.d.ts.map +1 -0
- package/dist/authorize.spec.js +55 -0
- package/dist/authorize.spec.js.map +1 -0
- package/dist/endpoint-generators/create-delete-endpoint.d.ts +17 -0
- package/dist/endpoint-generators/create-delete-endpoint.d.ts.map +1 -0
- package/dist/endpoint-generators/create-delete-endpoint.js +24 -0
- package/dist/endpoint-generators/create-delete-endpoint.js.map +1 -0
- package/dist/endpoint-generators/create-delete-endpoint.spec.d.ts +2 -0
- package/dist/endpoint-generators/create-delete-endpoint.spec.d.ts.map +1 -0
- package/dist/endpoint-generators/create-delete-endpoint.spec.js +33 -0
- package/dist/endpoint-generators/create-delete-endpoint.spec.js.map +1 -0
- package/dist/endpoint-generators/create-get-collection-endpoint.d.ts +17 -0
- package/dist/endpoint-generators/create-get-collection-endpoint.d.ts.map +1 -0
- package/dist/endpoint-generators/create-get-collection-endpoint.js +26 -0
- package/dist/endpoint-generators/create-get-collection-endpoint.js.map +1 -0
- package/dist/endpoint-generators/create-get-collection-endpoint.spec.d.ts +2 -0
- package/dist/endpoint-generators/create-get-collection-endpoint.spec.d.ts.map +1 -0
- package/dist/endpoint-generators/create-get-collection-endpoint.spec.js +143 -0
- package/dist/endpoint-generators/create-get-collection-endpoint.spec.js.map +1 -0
- package/dist/endpoint-generators/create-get-entity-endpoint.d.ts +17 -0
- package/dist/endpoint-generators/create-get-entity-endpoint.d.ts.map +1 -0
- package/dist/endpoint-generators/create-get-entity-endpoint.js +29 -0
- package/dist/endpoint-generators/create-get-entity-endpoint.js.map +1 -0
- package/dist/endpoint-generators/create-get-entity-endpoint.spec.d.ts +2 -0
- package/dist/endpoint-generators/create-get-entity-endpoint.spec.d.ts.map +1 -0
- package/dist/endpoint-generators/create-get-entity-endpoint.spec.js +74 -0
- package/dist/endpoint-generators/create-get-entity-endpoint.spec.js.map +1 -0
- package/dist/endpoint-generators/create-patch-endpoint.d.ts +18 -0
- package/dist/endpoint-generators/create-patch-endpoint.d.ts.map +1 -0
- package/dist/endpoint-generators/create-patch-endpoint.js +26 -0
- package/dist/endpoint-generators/create-patch-endpoint.js.map +1 -0
- package/dist/endpoint-generators/create-patch-endpoint.spec.d.ts +2 -0
- package/dist/endpoint-generators/create-patch-endpoint.spec.d.ts.map +1 -0
- package/dist/endpoint-generators/create-patch-endpoint.spec.js +36 -0
- package/dist/endpoint-generators/create-patch-endpoint.spec.js.map +1 -0
- package/dist/endpoint-generators/create-post-endpoint.d.ts +18 -0
- package/dist/endpoint-generators/create-post-endpoint.d.ts.map +1 -0
- package/dist/endpoint-generators/create-post-endpoint.js +29 -0
- package/dist/endpoint-generators/create-post-endpoint.js.map +1 -0
- package/dist/endpoint-generators/create-post-endpoint.spec.d.ts +2 -0
- package/dist/endpoint-generators/create-post-endpoint.spec.d.ts.map +1 -0
- package/dist/endpoint-generators/create-post-endpoint.spec.js +34 -0
- package/dist/endpoint-generators/create-post-endpoint.spec.js.map +1 -0
- package/dist/endpoint-generators/index.d.ts +6 -0
- package/dist/endpoint-generators/index.d.ts.map +1 -0
- package/dist/endpoint-generators/index.js +9 -0
- package/dist/endpoint-generators/index.js.map +1 -0
- package/dist/endpoint-generators/utils.d.ts +9 -0
- package/dist/endpoint-generators/utils.d.ts.map +1 -0
- package/dist/endpoint-generators/utils.js +27 -0
- package/dist/endpoint-generators/utils.js.map +1 -0
- package/dist/http-authentication-settings.d.ts +17 -0
- package/dist/http-authentication-settings.d.ts.map +1 -0
- package/dist/http-authentication-settings.js +26 -0
- package/dist/http-authentication-settings.js.map +1 -0
- package/dist/http-user-context.d.ts +54 -0
- package/dist/http-user-context.d.ts.map +1 -0
- package/dist/http-user-context.js +153 -0
- package/dist/http-user-context.js.map +1 -0
- package/dist/http-user-context.spec.d.ts +4 -0
- package/dist/http-user-context.spec.d.ts.map +1 -0
- package/dist/http-user-context.spec.js +267 -0
- package/dist/http-user-context.spec.js.map +1 -0
- package/dist/incoming-message-extensions.d.ts +8 -0
- package/dist/incoming-message-extensions.d.ts.map +1 -0
- package/dist/incoming-message-extensions.js +14 -0
- package/dist/incoming-message-extensions.js.map +1 -0
- package/dist/incoming-message-extensions.spec.d.ts +2 -0
- package/dist/incoming-message-extensions.spec.d.ts.map +1 -0
- package/dist/incoming-message-extensions.spec.js +39 -0
- package/dist/incoming-message-extensions.spec.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/injector-extensions.d.ts +21 -0
- package/dist/injector-extensions.d.ts.map +1 -0
- package/dist/injector-extensions.js +14 -0
- package/dist/injector-extensions.js.map +1 -0
- package/dist/injector-extensions.spec.d.ts +2 -0
- package/dist/injector-extensions.spec.d.ts.map +1 -0
- package/dist/injector-extensions.spec.js +19 -0
- package/dist/injector-extensions.spec.js.map +1 -0
- package/dist/models/cors-options.d.ts +22 -0
- package/dist/models/cors-options.d.ts.map +1 -0
- package/dist/models/cors-options.js +3 -0
- package/dist/models/cors-options.js.map +1 -0
- package/dist/models/default-session.d.ts +14 -0
- package/dist/models/default-session.d.ts.map +1 -0
- package/dist/models/default-session.js +10 -0
- package/dist/models/default-session.js.map +1 -0
- package/dist/request-action-implementation.d.ts +54 -0
- package/dist/request-action-implementation.d.ts.map +1 -0
- package/dist/request-action-implementation.js +42 -0
- package/dist/request-action-implementation.js.map +1 -0
- package/dist/rest-service.integration.spec.d.ts +2 -0
- package/dist/rest-service.integration.spec.d.ts.map +1 -0
- package/dist/rest-service.integration.spec.js +129 -0
- package/dist/rest-service.integration.spec.js.map +1 -0
- package/dist/rest.integration.test.d.ts +58 -0
- package/dist/rest.integration.test.d.ts.map +1 -0
- package/dist/rest.integration.test.js +94 -0
- package/dist/rest.integration.test.js.map +1 -0
- package/dist/schema-validator/index.d.ts +3 -0
- package/dist/schema-validator/index.d.ts.map +1 -0
- package/dist/schema-validator/index.js +6 -0
- package/dist/schema-validator/index.js.map +1 -0
- package/dist/schema-validator/schema-validation-error.d.ts +10 -0
- package/dist/schema-validator/schema-validation-error.d.ts.map +1 -0
- package/dist/schema-validator/schema-validation-error.js +15 -0
- package/dist/schema-validator/schema-validation-error.js.map +1 -0
- package/dist/schema-validator/schema-validator.d.ts +20 -0
- package/dist/schema-validator/schema-validator.d.ts.map +1 -0
- package/dist/schema-validator/schema-validator.js +36 -0
- package/dist/schema-validator/schema-validator.js.map +1 -0
- package/dist/schema-validator/schema-validator.test.d.ts +2 -0
- package/dist/schema-validator/schema-validator.test.d.ts.map +1 -0
- package/dist/schema-validator/schema-validator.test.js +62 -0
- package/dist/schema-validator/schema-validator.test.js.map +1 -0
- package/dist/schema-validator/validate-examples.d.ts +37 -0
- package/dist/schema-validator/validate-examples.d.ts.map +1 -0
- package/dist/schema-validator/validate-examples.js +29 -0
- package/dist/schema-validator/validate-examples.js.map +1 -0
- package/dist/server-manager.d.ts +30 -0
- package/dist/server-manager.d.ts.map +1 -0
- package/dist/server-manager.js +71 -0
- package/dist/server-manager.js.map +1 -0
- package/dist/server-response-extensions.d.ts +21 -0
- package/dist/server-response-extensions.d.ts.map +1 -0
- package/dist/server-response-extensions.js +15 -0
- package/dist/server-response-extensions.js.map +1 -0
- package/dist/server-response-extensions.spec.d.ts +2 -0
- package/dist/server-response-extensions.spec.d.ts.map +1 -0
- package/dist/server-response-extensions.spec.js +49 -0
- package/dist/server-response-extensions.spec.js.map +1 -0
- package/dist/utils.d.ts +24 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +66 -0
- package/dist/utils.js.map +1 -0
- package/dist/validate.d.ts +18 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.integration.schema.d.ts +69 -0
- package/dist/validate.integration.schema.d.ts.map +1 -0
- package/dist/validate.integration.schema.js +3 -0
- package/dist/validate.integration.schema.js.map +1 -0
- package/dist/validate.integration.spec.d.ts +13 -0
- package/dist/validate.integration.spec.d.ts.map +1 -0
- package/dist/validate.integration.spec.js +223 -0
- package/dist/validate.integration.spec.js.map +1 -0
- package/dist/validate.integration.spec.schema.json +749 -0
- package/dist/validate.js +49 -0
- package/dist/validate.js.map +1 -0
- package/package.json +56 -0
- package/src/actions/error-action.spec.ts +54 -0
- package/src/actions/error-action.ts +34 -0
- package/src/actions/get-current-user.spec.ts +23 -0
- package/src/actions/get-current-user.ts +15 -0
- package/src/actions/index.ts +6 -0
- package/src/actions/is-authenticated.spec.ts +18 -0
- package/src/actions/is-authenticated.ts +13 -0
- package/src/actions/login-action.spec.ts +41 -0
- package/src/actions/login.ts +26 -0
- package/src/actions/logout-action.spec.ts +27 -0
- package/src/actions/logout.ts +16 -0
- package/src/actions/not-found-action.spec.ts +17 -0
- package/src/actions/not-found-action.ts +13 -0
- package/src/add-cors-header.spec.ts +133 -0
- package/src/api-manager.ts +222 -0
- package/src/authenticate.spec.ts +78 -0
- package/src/authenticate.ts +22 -0
- package/src/authorize.spec.ts +69 -0
- package/src/authorize.ts +19 -0
- package/src/endpoint-generators/create-delete-endpoint.spec.ts +34 -0
- package/src/endpoint-generators/create-delete-endpoint.ts +25 -0
- package/src/endpoint-generators/create-get-collection-endpoint.spec.ts +164 -0
- package/src/endpoint-generators/create-get-collection-endpoint.ts +28 -0
- package/src/endpoint-generators/create-get-entity-endpoint.spec.ts +75 -0
- package/src/endpoint-generators/create-get-entity-endpoint.ts +29 -0
- package/src/endpoint-generators/create-patch-endpoint.spec.ts +36 -0
- package/src/endpoint-generators/create-patch-endpoint.ts +27 -0
- package/src/endpoint-generators/create-post-endpoint.spec.ts +32 -0
- package/src/endpoint-generators/create-post-endpoint.ts +30 -0
- package/src/endpoint-generators/index.ts +5 -0
- package/src/endpoint-generators/utils.ts +34 -0
- package/src/http-authentication-settings.ts +23 -0
- package/src/http-user-context.spec.ts +299 -0
- package/src/http-user-context.ts +160 -0
- package/src/incoming-message-extensions.spec.ts +41 -0
- package/src/incoming-message-extensions.ts +19 -0
- package/src/index.ts +16 -0
- package/src/injector-extensions.spec.ts +19 -0
- package/src/injector-extensions.ts +35 -0
- package/src/models/cors-options.ts +21 -0
- package/src/models/default-session.ts +14 -0
- package/src/request-action-implementation.ts +70 -0
- package/src/rest-service.integration.spec.ts +166 -0
- package/src/rest.integration.test.ts +112 -0
- package/src/schema-validator/index.ts +2 -0
- package/src/schema-validator/schema-validation-error.ts +11 -0
- package/src/schema-validator/schema-validator.test.ts +72 -0
- package/src/schema-validator/schema-validator.ts +31 -0
- package/src/schema-validator/validate-examples.ts +38 -0
- package/src/server-manager.ts +88 -0
- package/src/server-response-extensions.spec.ts +53 -0
- package/src/server-response-extensions.ts +30 -0
- package/src/utils.ts +65 -0
- package/src/validate.integration.schema.ts +50 -0
- package/src/validate.integration.spec.schema.json +779 -0
- package/src/validate.integration.spec.ts +218 -0
- package/src/validate.ts +60 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { IncomingMessage } from 'http'
|
|
2
|
+
import './incoming-message-extensions'
|
|
3
|
+
import { Socket } from 'net'
|
|
4
|
+
|
|
5
|
+
describe('IncomingMessage extensions', () => {
|
|
6
|
+
describe('readPostBody', () => {
|
|
7
|
+
it('Should be extended', () => {
|
|
8
|
+
const socket = new Socket()
|
|
9
|
+
const msg = new IncomingMessage(socket)
|
|
10
|
+
expect(typeof msg.readPostBody).toBe('function')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('Should read the raw post body', async () => {
|
|
14
|
+
const exampleValue = { value: Math.random().toString() }
|
|
15
|
+
const socket = new Socket()
|
|
16
|
+
const msg = new IncomingMessage(socket)
|
|
17
|
+
setTimeout(() => {
|
|
18
|
+
msg.read = () => JSON.stringify(exampleValue)
|
|
19
|
+
msg.emit('readable')
|
|
20
|
+
msg.emit('end')
|
|
21
|
+
}, 10)
|
|
22
|
+
|
|
23
|
+
const result = await msg.readPostBodyRaw()
|
|
24
|
+
expect(result).toEqual(JSON.stringify(exampleValue))
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('Should read the post body', async () => {
|
|
28
|
+
const exampleValue = { value: Math.random().toString() }
|
|
29
|
+
const socket = new Socket()
|
|
30
|
+
const msg = new IncomingMessage(socket)
|
|
31
|
+
setTimeout(() => {
|
|
32
|
+
msg.read = () => JSON.stringify(exampleValue)
|
|
33
|
+
msg.emit('readable')
|
|
34
|
+
msg.emit('end')
|
|
35
|
+
}, 10)
|
|
36
|
+
|
|
37
|
+
const result = await msg.readPostBody()
|
|
38
|
+
expect(result).toEqual(exampleValue)
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import http from 'http'
|
|
2
|
+
import { Utils } from './utils'
|
|
3
|
+
|
|
4
|
+
declare module 'http' {
|
|
5
|
+
export interface IncomingMessage {
|
|
6
|
+
readPostBodyRaw: () => Promise<string>
|
|
7
|
+
readPostBody: <T>() => Promise<T>
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
http.IncomingMessage.prototype.readPostBody = async function <T>() {
|
|
12
|
+
const utils = new Utils()
|
|
13
|
+
return await utils.readPostBody<T>(this)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
http.IncomingMessage.prototype.readPostBodyRaw = async function () {
|
|
17
|
+
const utils = new Utils()
|
|
18
|
+
return await utils.readPostBodyRaw(this)
|
|
19
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import './injector-extensions'
|
|
2
|
+
export * from './api-manager'
|
|
3
|
+
export * from './actions'
|
|
4
|
+
export * from './authenticate'
|
|
5
|
+
export * from './authorize'
|
|
6
|
+
export * from './http-authentication-settings'
|
|
7
|
+
export * from './http-user-context'
|
|
8
|
+
export * from './incoming-message-extensions'
|
|
9
|
+
export * from './server-manager'
|
|
10
|
+
export * from './server-response-extensions'
|
|
11
|
+
export * from './utils'
|
|
12
|
+
export * from './models/default-session'
|
|
13
|
+
export * from './endpoint-generators'
|
|
14
|
+
export * from './schema-validator'
|
|
15
|
+
export * from './request-action-implementation'
|
|
16
|
+
export * from './validate'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject'
|
|
2
|
+
import { usingAsync } from '@furystack/utils'
|
|
3
|
+
import './injector-extensions'
|
|
4
|
+
|
|
5
|
+
// tslint:disable: no-string-literal
|
|
6
|
+
|
|
7
|
+
describe('Injector extensions', () => {
|
|
8
|
+
it('useRestService() Should be added to the injector prototype', async () => {
|
|
9
|
+
await usingAsync(new Injector(), async (i) => {
|
|
10
|
+
i.useHttpAuthentication().useRestService({ api: {}, port: 19999, root: '/api' })
|
|
11
|
+
})
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('useHttpAuthentication() Should be added to the injector prototype', async () => {
|
|
15
|
+
await usingAsync(new Injector(), async (i) => {
|
|
16
|
+
i.useHttpAuthentication().useHttpAuthentication()
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { User } from '@furystack/core'
|
|
2
|
+
import { Injector } from '@furystack/inject/dist/injector'
|
|
3
|
+
import { HttpAuthenticationSettings } from './http-authentication-settings'
|
|
4
|
+
import { RestApi } from '@furystack/rest'
|
|
5
|
+
import { ApiManager, ImplementApiOptions } from './api-manager'
|
|
6
|
+
import { DefaultSession } from 'models/default-session'
|
|
7
|
+
|
|
8
|
+
declare module '@furystack/inject/dist/injector' {
|
|
9
|
+
/**
|
|
10
|
+
* Extended Injector with Http API related methods
|
|
11
|
+
*/
|
|
12
|
+
export interface Injector {
|
|
13
|
+
/**
|
|
14
|
+
* Sets up the @furystack/rest-service with the provided settings
|
|
15
|
+
*/
|
|
16
|
+
useRestService: <T extends RestApi>(api: Omit<ImplementApiOptions<T>, 'injector'>) => Promise<this>
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Sets up the HTTP Authentication
|
|
20
|
+
*/
|
|
21
|
+
useHttpAuthentication: <TUser extends User, TSession extends DefaultSession>(
|
|
22
|
+
settings?: Partial<HttpAuthenticationSettings<TUser, TSession>>,
|
|
23
|
+
) => this
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Injector.prototype.useRestService = async function (api) {
|
|
28
|
+
await this.getInstance(ApiManager).addApi({ ...api, injector: this })
|
|
29
|
+
return this
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
Injector.prototype.useHttpAuthentication = function (s) {
|
|
33
|
+
this.setExplicitInstance({ ...new HttpAuthenticationSettings(), ...s }, HttpAuthenticationSettings)
|
|
34
|
+
return this
|
|
35
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORS settings
|
|
3
|
+
*/
|
|
4
|
+
export interface CorsOptions {
|
|
5
|
+
/**
|
|
6
|
+
* List of allowed origins
|
|
7
|
+
*/
|
|
8
|
+
origins: string[]
|
|
9
|
+
/**
|
|
10
|
+
* List of the allowed actions
|
|
11
|
+
*/
|
|
12
|
+
methods?: Array<'POST' | 'GET' | 'PUT' | 'DELETE' | 'PATCH'>
|
|
13
|
+
/**
|
|
14
|
+
* List of the allowed headers
|
|
15
|
+
*/
|
|
16
|
+
headers?: string[]
|
|
17
|
+
/**
|
|
18
|
+
* Enable cookies
|
|
19
|
+
*/
|
|
20
|
+
credentials?: boolean
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model class that defines the default session data
|
|
3
|
+
*/
|
|
4
|
+
export class DefaultSession {
|
|
5
|
+
/**
|
|
6
|
+
* The generated session identifier
|
|
7
|
+
*/
|
|
8
|
+
public sessionId!: string
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The user's login name for the session
|
|
12
|
+
*/
|
|
13
|
+
public username!: string
|
|
14
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject'
|
|
2
|
+
import { ServerResponse } from 'http'
|
|
3
|
+
import { IncomingMessage } from 'http'
|
|
4
|
+
|
|
5
|
+
export interface ActionResult<T> {
|
|
6
|
+
statusCode: number
|
|
7
|
+
headers: { [K: string]: string }
|
|
8
|
+
chunk: T
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const JsonResult = <T extends object>(chunk: T, statusCode = 200, headers?: { [K: string]: string }) =>
|
|
12
|
+
({
|
|
13
|
+
statusCode,
|
|
14
|
+
chunk,
|
|
15
|
+
headers: {
|
|
16
|
+
...headers,
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
},
|
|
19
|
+
} as ActionResult<T>)
|
|
20
|
+
|
|
21
|
+
export const PlainTextResult = (text: string, statusCode = 200, headers?: { [K: string]: string }) =>
|
|
22
|
+
({
|
|
23
|
+
statusCode,
|
|
24
|
+
chunk: text,
|
|
25
|
+
headers: {
|
|
26
|
+
...headers,
|
|
27
|
+
'Content-Type': 'plain/text',
|
|
28
|
+
},
|
|
29
|
+
} as ActionResult<string>)
|
|
30
|
+
|
|
31
|
+
export const XmlResult = (text: string, statusCode = 200, headers?: { [K: string]: string }) =>
|
|
32
|
+
({
|
|
33
|
+
statusCode,
|
|
34
|
+
chunk: text,
|
|
35
|
+
headers: {
|
|
36
|
+
...headers,
|
|
37
|
+
'Content-Type': 'application/xml;charset=utf-8',
|
|
38
|
+
},
|
|
39
|
+
} as ActionResult<string>)
|
|
40
|
+
|
|
41
|
+
export const EmptyResult = (statusCode = 200, headers?: { [K: string]: string }) =>
|
|
42
|
+
({
|
|
43
|
+
statusCode,
|
|
44
|
+
headers: {
|
|
45
|
+
...headers,
|
|
46
|
+
},
|
|
47
|
+
} as ActionResult<undefined>)
|
|
48
|
+
|
|
49
|
+
export const BypassResult = () =>
|
|
50
|
+
({
|
|
51
|
+
chunk: 'BypassResult',
|
|
52
|
+
} as ActionResult<'BypassResult'>)
|
|
53
|
+
|
|
54
|
+
export type RequestActionOptions<T extends { result: unknown }> = {
|
|
55
|
+
request: IncomingMessage
|
|
56
|
+
response: ServerResponse
|
|
57
|
+
injector: Injector
|
|
58
|
+
} & (T extends {
|
|
59
|
+
result: unknown
|
|
60
|
+
body: infer U
|
|
61
|
+
}
|
|
62
|
+
? { getBody: () => Promise<U> }
|
|
63
|
+
: unknown) &
|
|
64
|
+
(T extends { result: unknown; url: infer U } ? { getUrlParams: () => U } : unknown) &
|
|
65
|
+
(T extends { result: unknown; query: infer U } ? { getQuery: () => U } : unknown) &
|
|
66
|
+
(T extends { result: unknown; headers: infer U } ? { headers: U } : unknown)
|
|
67
|
+
|
|
68
|
+
export type RequestAction<T extends { result: unknown }> = (
|
|
69
|
+
options: RequestActionOptions<T>,
|
|
70
|
+
) => Promise<ActionResult<T['result']>>
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject'
|
|
2
|
+
import './injector-extensions'
|
|
3
|
+
import { usingAsync, PathHelper } from '@furystack/utils'
|
|
4
|
+
import { GetCurrentUser, IsAuthenticated, LoginAction, LogoutAction } from './actions'
|
|
5
|
+
import { RestApi } from '@furystack/rest'
|
|
6
|
+
import { User, InMemoryStore } from '@furystack/core'
|
|
7
|
+
import { DefaultSession } from './models/default-session'
|
|
8
|
+
import got from 'got'
|
|
9
|
+
import { JsonResult } from './request-action-implementation'
|
|
10
|
+
|
|
11
|
+
class UserWithPassword extends User {
|
|
12
|
+
password!: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface IntegrationTestApi extends RestApi {
|
|
16
|
+
GET: {
|
|
17
|
+
'/isAuthenticated': { result: { isAuthenticated: boolean } }
|
|
18
|
+
'/currentUser': { result: User }
|
|
19
|
+
'/testQuery': { query: { param1: string }; result: { param1Value: string } }
|
|
20
|
+
'/testUrlParams/:urlParam': { url: { urlParam: string }; result: { urlParamValue: string } }
|
|
21
|
+
}
|
|
22
|
+
POST: {
|
|
23
|
+
'/login': { result: User; body: { username: string; password: string } }
|
|
24
|
+
'/logout': { result: unknown }
|
|
25
|
+
'/testPostBody': { body: { value: string }; result: { bodyValue: string } }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const port = 19090
|
|
30
|
+
const hostName = 'localhost'
|
|
31
|
+
const root = 'test-api'
|
|
32
|
+
|
|
33
|
+
const prepareInjector = (i: Injector) =>
|
|
34
|
+
i
|
|
35
|
+
.setupStores((sm) =>
|
|
36
|
+
sm
|
|
37
|
+
.addStore(new InMemoryStore({ model: User, primaryKey: 'username' }))
|
|
38
|
+
.addStore(new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' })),
|
|
39
|
+
)
|
|
40
|
+
.useHttpAuthentication({
|
|
41
|
+
getUserStore: (sm) => sm.getStoreFor(UserWithPassword, 'username'),
|
|
42
|
+
getSessionStore: (sm) => sm.getStoreFor(DefaultSession, 'sessionId'),
|
|
43
|
+
})
|
|
44
|
+
.useRestService<IntegrationTestApi>({
|
|
45
|
+
root,
|
|
46
|
+
port,
|
|
47
|
+
hostName,
|
|
48
|
+
cors: {
|
|
49
|
+
credentials: true,
|
|
50
|
+
origins: ['http://localhost:8080'],
|
|
51
|
+
headers: ['cache', 'content-type'],
|
|
52
|
+
},
|
|
53
|
+
api: {
|
|
54
|
+
GET: {
|
|
55
|
+
'/currentUser': GetCurrentUser,
|
|
56
|
+
'/isAuthenticated': IsAuthenticated,
|
|
57
|
+
'/testQuery': async (options) => JsonResult({ param1Value: options.getQuery().param1 }),
|
|
58
|
+
'/testUrlParams/:urlParam': async (options) => JsonResult({ urlParamValue: options.getUrlParams().urlParam }),
|
|
59
|
+
},
|
|
60
|
+
POST: {
|
|
61
|
+
'/login': LoginAction,
|
|
62
|
+
'/logout': LogoutAction,
|
|
63
|
+
'/testPostBody': async (options) => {
|
|
64
|
+
const body = await options.getBody()
|
|
65
|
+
return JsonResult({ bodyValue: body.value })
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const apiUrl = PathHelper.joinPaths(`http://${hostName}:${port}`, root)
|
|
72
|
+
|
|
73
|
+
describe('@furystack/rest-service inregration tests', () => {
|
|
74
|
+
it('Should be started and disposed', async () => {
|
|
75
|
+
await usingAsync(new Injector(), async (i) => {
|
|
76
|
+
await prepareInjector(i)
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('Should respond with 404 when a route is not found', async () => {
|
|
81
|
+
await usingAsync(new Injector(), async (i) => {
|
|
82
|
+
await prepareInjector(i)
|
|
83
|
+
await expect(got(PathHelper.joinPaths(apiUrl, 'some-route-that-does-not-exists'))).rejects.toThrow(
|
|
84
|
+
'Response code 404 (Not Found)',
|
|
85
|
+
)
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('Should respond with 401 for unauthorized request errors', async () => {
|
|
90
|
+
await usingAsync(new Injector(), async (i) => {
|
|
91
|
+
await prepareInjector(i)
|
|
92
|
+
await expect(got(PathHelper.joinPaths(apiUrl, 'currentUser'), { retry: 0 })).rejects.toThrow(
|
|
93
|
+
'Response code 401 (Unauthorized)',
|
|
94
|
+
)
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('Should respond with 401 for unauthorized request errors', async () => {
|
|
99
|
+
await usingAsync(new Injector(), async (i) => {
|
|
100
|
+
await prepareInjector(i)
|
|
101
|
+
await expect(got(PathHelper.joinPaths(apiUrl, 'currentUser'), { retry: 0 })).rejects.toThrow(
|
|
102
|
+
'Response code 401 (Unauthorized)',
|
|
103
|
+
)
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('Should respond with the correct result body', async () => {
|
|
108
|
+
await usingAsync(new Injector(), async (i) => {
|
|
109
|
+
await prepareInjector(i)
|
|
110
|
+
const response = await got(PathHelper.joinPaths(apiUrl, 'isAuthenticated'), { retry: 0 })
|
|
111
|
+
expect(response.statusCode).toBe(200)
|
|
112
|
+
expect(JSON.parse(response.body)).toStrictEqual({ isAuthenticated: false })
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('Should be able to read query parameters', async () => {
|
|
117
|
+
await usingAsync(new Injector(), async (i) => {
|
|
118
|
+
await prepareInjector(i)
|
|
119
|
+
const response = await got(PathHelper.joinPaths(apiUrl, 'testQuery?param1=foo'), { retry: 0 })
|
|
120
|
+
expect(response.statusCode).toBe(200)
|
|
121
|
+
expect(JSON.parse(response.body)).toStrictEqual({ param1Value: 'foo' })
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('Should be able to read url parameters', async () => {
|
|
126
|
+
await usingAsync(new Injector(), async (i) => {
|
|
127
|
+
await prepareInjector(i)
|
|
128
|
+
const response = await got(PathHelper.joinPaths(apiUrl, 'testUrlParams/bar'), { retry: 0 })
|
|
129
|
+
expect(response.statusCode).toBe(200)
|
|
130
|
+
expect(JSON.parse(response.body)).toStrictEqual({ urlParamValue: 'bar' })
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('Should be able to read post body', async () => {
|
|
135
|
+
await usingAsync(new Injector(), async (i) => {
|
|
136
|
+
await prepareInjector(i)
|
|
137
|
+
const response = await got(PathHelper.joinPaths(apiUrl, 'testPostBody'), {
|
|
138
|
+
method: 'POST',
|
|
139
|
+
body: JSON.stringify({ value: 'baz' }),
|
|
140
|
+
retry: 0,
|
|
141
|
+
})
|
|
142
|
+
expect(response.statusCode).toBe(200)
|
|
143
|
+
expect(JSON.parse(response.body)).toStrictEqual({ bodyValue: 'baz' })
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('Should respond with OK to OPTIONS requests', async () => {
|
|
148
|
+
await usingAsync(new Injector(), async (i) => {
|
|
149
|
+
await prepareInjector(i)
|
|
150
|
+
const response = await got(PathHelper.joinPaths(apiUrl, 'testPostBody'), {
|
|
151
|
+
method: 'OPTIONS',
|
|
152
|
+
retry: 0,
|
|
153
|
+
})
|
|
154
|
+
expect(response.statusCode).toBe(200)
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it('Should reject requests outside of the API Root', async () => {
|
|
159
|
+
await usingAsync(new Injector(), async (i) => {
|
|
160
|
+
await prepareInjector(i)
|
|
161
|
+
await expect(
|
|
162
|
+
got(PathHelper.joinPaths(`http://${hostName}:${port}`, 'not-my-api-root'), { retry: 0 }),
|
|
163
|
+
).rejects.toThrowError('socket hang up')
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
})
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject'
|
|
2
|
+
import { RestApi } from '@furystack/rest'
|
|
3
|
+
import { createClient } from '@furystack/rest-client-got'
|
|
4
|
+
import { usingAsync } from '@furystack/utils'
|
|
5
|
+
import { JsonResult } from './request-action-implementation'
|
|
6
|
+
import { v4 } from 'uuid'
|
|
7
|
+
import './injector-extensions'
|
|
8
|
+
|
|
9
|
+
export interface EchoApi extends RestApi {
|
|
10
|
+
GET: {
|
|
11
|
+
'/plain': { result: unknown }
|
|
12
|
+
'/headers': { headers: { value?: string }; result: { headers: { value?: string } } }
|
|
13
|
+
'/urlParams/:id': { url: { id: string }; result: { url: { id: string } } }
|
|
14
|
+
'/query': {
|
|
15
|
+
query: { someObject: { foo: string } }
|
|
16
|
+
result: { query: { someObject: { foo: string } } }
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
POST: {
|
|
20
|
+
'/body': { body: { foo: string; bar: number }; result: { body: { foo: string; bar: number } } }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const createEchoApiServer = async () => {
|
|
25
|
+
const port = Math.round(Math.random() * 1000) + 10000
|
|
26
|
+
const root = '/api'
|
|
27
|
+
const injector = new Injector()
|
|
28
|
+
await injector.useRestService<EchoApi>({
|
|
29
|
+
port,
|
|
30
|
+
root,
|
|
31
|
+
api: {
|
|
32
|
+
GET: {
|
|
33
|
+
'/plain': async () => JsonResult({}),
|
|
34
|
+
'/headers': async ({ headers }) => JsonResult({ headers }),
|
|
35
|
+
'/query': async ({ getQuery }) => JsonResult({ query: getQuery() }),
|
|
36
|
+
'/urlParams/:id': async ({ getUrlParams }) => JsonResult({ url: getUrlParams() }),
|
|
37
|
+
},
|
|
38
|
+
POST: {
|
|
39
|
+
'/body': async ({ getBody }) => JsonResult({ body: await getBody() }),
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
const client = createClient<EchoApi>({
|
|
44
|
+
endpointUrl: `http://localhost:${port}/api`,
|
|
45
|
+
})
|
|
46
|
+
return {
|
|
47
|
+
dispose: injector.dispose.bind(injector),
|
|
48
|
+
root,
|
|
49
|
+
port,
|
|
50
|
+
client,
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
describe('REST Integration tests with GOT client', () => {
|
|
55
|
+
it('Should execute a single parameterless GET query', async () => {
|
|
56
|
+
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
57
|
+
const result = await client({
|
|
58
|
+
method: 'GET',
|
|
59
|
+
action: '/plain',
|
|
60
|
+
})
|
|
61
|
+
expect(result.response.statusCode).toBe(200)
|
|
62
|
+
expect(result.getJson()).toStrictEqual({})
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('Should execute a request with headers', async () => {
|
|
67
|
+
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
68
|
+
const value = v4()
|
|
69
|
+
const result = await client({
|
|
70
|
+
method: 'GET',
|
|
71
|
+
action: '/headers',
|
|
72
|
+
headers: {
|
|
73
|
+
value,
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
expect(result.response.statusCode).toBe(200)
|
|
77
|
+
expect(result.getJson().headers.value).toStrictEqual(value)
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('Should execute a request with query', async () => {
|
|
82
|
+
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
83
|
+
const value = v4()
|
|
84
|
+
const result = await client({
|
|
85
|
+
method: 'GET',
|
|
86
|
+
action: '/query',
|
|
87
|
+
query: {
|
|
88
|
+
someObject: {
|
|
89
|
+
foo: value,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
expect(result.response.statusCode).toBe(200)
|
|
94
|
+
expect(result.getJson().query.someObject.foo).toStrictEqual(value)
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('Should execute a request with URL parameters', async () => {
|
|
99
|
+
await usingAsync(await createEchoApiServer(), async ({ client }) => {
|
|
100
|
+
const value = v4()
|
|
101
|
+
const result = await client({
|
|
102
|
+
method: 'GET',
|
|
103
|
+
action: '/urlParams/:id',
|
|
104
|
+
url: {
|
|
105
|
+
id: value,
|
|
106
|
+
},
|
|
107
|
+
})
|
|
108
|
+
expect(result.response.statusCode).toBe(200)
|
|
109
|
+
expect(result.getJson().url.id).toEqual(value)
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
})
|