@loopback/rest 4.0.0-alpha.8 → 5.0.1
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 +1822 -0
- package/LICENSE +1 -1
- package/README.md +30 -58
- package/dist/body-parsers/body-parser.d.ts +25 -0
- package/dist/body-parsers/body-parser.helpers.d.ts +44 -0
- package/dist/body-parsers/body-parser.helpers.js +102 -0
- package/dist/body-parsers/body-parser.helpers.js.map +1 -0
- package/dist/body-parsers/body-parser.js +159 -0
- package/dist/body-parsers/body-parser.js.map +1 -0
- package/dist/body-parsers/body-parser.json.d.ts +9 -0
- package/dist/body-parsers/body-parser.json.js +43 -0
- package/dist/body-parsers/body-parser.json.js.map +1 -0
- package/dist/body-parsers/body-parser.raw.d.ts +12 -0
- package/dist/body-parsers/body-parser.raw.js +39 -0
- package/dist/body-parsers/body-parser.raw.js.map +1 -0
- package/dist/body-parsers/body-parser.stream.d.ts +12 -0
- package/dist/body-parsers/body-parser.stream.js +28 -0
- package/dist/body-parsers/body-parser.stream.js.map +1 -0
- package/dist/body-parsers/body-parser.text.d.ts +9 -0
- package/dist/body-parsers/body-parser.text.js +38 -0
- package/dist/body-parsers/body-parser.text.js.map +1 -0
- package/dist/body-parsers/body-parser.urlencoded.d.ts +9 -0
- package/dist/body-parsers/body-parser.urlencoded.js +36 -0
- package/dist/body-parsers/body-parser.urlencoded.js.map +1 -0
- package/dist/body-parsers/index.d.ts +8 -0
- package/dist/body-parsers/index.js +16 -0
- package/dist/body-parsers/index.js.map +1 -0
- package/dist/body-parsers/types.d.ts +51 -0
- package/dist/body-parsers/types.js +12 -0
- package/dist/body-parsers/types.js.map +1 -0
- package/dist/coercion/coerce-parameter.d.ts +9 -0
- package/dist/coercion/coerce-parameter.js +166 -0
- package/dist/coercion/coerce-parameter.js.map +1 -0
- package/dist/coercion/utils.d.ts +43 -0
- package/dist/coercion/utils.js +96 -0
- package/dist/coercion/utils.js.map +1 -0
- package/dist/coercion/validator.d.ts +49 -0
- package/dist/coercion/validator.js +85 -0
- package/dist/coercion/validator.js.map +1 -0
- package/dist/http-handler.d.ts +38 -0
- package/dist/http-handler.js +68 -0
- package/dist/http-handler.js.map +1 -0
- package/dist/index.d.ts +36 -1
- package/dist/index.js +40 -6
- package/dist/index.js.map +1 -0
- package/dist/keys.d.ts +198 -0
- package/dist/keys.js +202 -0
- package/dist/keys.js.map +1 -0
- package/dist/parse-json.d.ts +11 -0
- package/dist/parse-json.js +42 -0
- package/dist/parse-json.js.map +1 -0
- package/dist/parser.d.ts +11 -0
- package/dist/parser.js +76 -0
- package/dist/parser.js.map +1 -0
- package/{dist6/src/providers/find-route.d.ts → dist/providers/find-route.provider.d.ts} +3 -1
- package/dist/providers/find-route.provider.js +36 -0
- package/dist/providers/find-route.provider.js.map +1 -0
- package/dist/providers/index.d.ts +6 -0
- package/dist/providers/index.js +14 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/{src/providers/invoke-method.d.ts → providers/invoke-method.provider.d.ts} +3 -1
- package/dist/providers/invoke-method.provider.js +30 -0
- package/dist/providers/invoke-method.provider.js.map +1 -0
- package/dist/providers/log-error.provider.d.ts +6 -0
- package/dist/providers/log-error.provider.js +21 -0
- package/dist/providers/log-error.provider.js.map +1 -0
- package/dist/providers/parse-params.provider.d.ts +15 -0
- package/dist/providers/parse-params.provider.js +41 -0
- package/dist/providers/parse-params.provider.js.map +1 -0
- package/dist/providers/reject.provider.d.ts +10 -0
- package/dist/providers/reject.provider.js +47 -0
- package/dist/providers/reject.provider.js.map +1 -0
- package/dist/{src/providers/send.d.ts → providers/send.provider.d.ts} +1 -4
- package/dist/{src/providers/send.js → providers/send.provider.js} +4 -6
- package/dist/providers/send.provider.js.map +1 -0
- package/dist/request-context.d.ts +36 -0
- package/dist/request-context.js +104 -0
- package/dist/request-context.js.map +1 -0
- package/dist/rest-http-error.d.ts +37 -0
- package/dist/rest-http-error.js +51 -0
- package/dist/rest-http-error.js.map +1 -0
- package/dist/rest.application.d.ts +232 -0
- package/dist/rest.application.js +174 -0
- package/dist/rest.application.js.map +1 -0
- package/dist/rest.component.d.ts +15 -0
- package/dist/rest.component.js +72 -0
- package/dist/rest.component.js.map +1 -0
- package/dist/rest.server.d.ts +443 -0
- package/dist/rest.server.js +748 -0
- package/dist/rest.server.js.map +1 -0
- package/dist/router/base-route.d.ts +29 -0
- package/dist/router/base-route.js +41 -0
- package/dist/router/base-route.js.map +1 -0
- package/dist/router/controller-route.d.ts +61 -0
- package/dist/router/controller-route.js +160 -0
- package/dist/router/controller-route.js.map +1 -0
- package/dist/router/external-express-routes.d.ts +24 -0
- package/dist/router/external-express-routes.js +90 -0
- package/dist/router/external-express-routes.js.map +1 -0
- package/dist/router/handler-route.d.ts +12 -0
- package/dist/router/handler-route.js +30 -0
- package/dist/router/handler-route.js.map +1 -0
- package/dist/router/index.d.ts +14 -0
- package/dist/router/index.js +25 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router/openapi-path.d.ts +14 -0
- package/dist/router/openapi-path.js +64 -0
- package/dist/router/openapi-path.js.map +1 -0
- package/dist/router/redirect-route.d.ts +23 -0
- package/dist/router/redirect-route.js +50 -0
- package/dist/router/redirect-route.js.map +1 -0
- package/dist/router/regexp-router.d.ts +25 -0
- package/dist/router/regexp-router.js +84 -0
- package/dist/router/regexp-router.js.map +1 -0
- package/dist/router/rest-router.d.ts +35 -0
- package/dist/{src/internal-types.js → router/rest-router.js} +2 -2
- package/dist/router/rest-router.js.map +1 -0
- package/dist/router/route-entry.d.ts +46 -0
- package/dist/router/route-entry.js +20 -0
- package/dist/router/route-entry.js.map +1 -0
- package/dist/router/route-sort.d.ts +7 -0
- package/dist/router/route-sort.js +75 -0
- package/dist/router/route-sort.js.map +1 -0
- package/dist/router/router-base.d.ts +42 -0
- package/dist/router/router-base.js +101 -0
- package/dist/router/router-base.js.map +1 -0
- package/dist/router/router-spec.d.ts +3 -0
- package/dist/router/router-spec.js +40 -0
- package/dist/router/router-spec.js.map +1 -0
- package/dist/router/routing-table.d.ts +32 -0
- package/dist/router/routing-table.js +86 -0
- package/dist/router/routing-table.js.map +1 -0
- package/dist/router/trie-router.d.ts +13 -0
- package/dist/router/trie-router.js +55 -0
- package/dist/router/trie-router.js.map +1 -0
- package/dist/router/trie.d.ts +59 -0
- package/dist/router/trie.js +180 -0
- package/dist/router/trie.js.map +1 -0
- package/{dist6/src → dist}/sequence.d.ts +28 -23
- package/dist/sequence.js +112 -0
- package/dist/sequence.js.map +1 -0
- package/dist/spec-enhancers/consolidate.spec-enhancer.d.ts +68 -0
- package/dist/spec-enhancers/consolidate.spec-enhancer.js +145 -0
- package/dist/spec-enhancers/consolidate.spec-enhancer.js.map +1 -0
- package/dist/spec-enhancers/info.spec-enhancer.d.ts +19 -0
- package/dist/spec-enhancers/info.spec-enhancer.js +89 -0
- package/dist/spec-enhancers/info.spec-enhancer.js.map +1 -0
- package/dist/types.d.ts +178 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/dist/validation/ajv-factory.provider.d.ts +12 -0
- package/dist/validation/ajv-factory.provider.js +87 -0
- package/dist/validation/ajv-factory.provider.js.map +1 -0
- package/dist/validation/request-body.validator.d.ts +14 -0
- package/dist/validation/request-body.validator.js +161 -0
- package/dist/validation/request-body.validator.js.map +1 -0
- package/dist/writer.d.ts +9 -0
- package/dist/writer.js +62 -0
- package/dist/writer.js.map +1 -0
- package/package.json +66 -38
- package/src/body-parsers/body-parser.helpers.ts +148 -0
- package/src/body-parsers/body-parser.json.ts +46 -0
- package/src/body-parsers/body-parser.raw.ts +42 -0
- package/src/body-parsers/body-parser.stream.ts +27 -0
- package/src/body-parsers/body-parser.text.ts +44 -0
- package/src/body-parsers/body-parser.ts +208 -0
- package/src/body-parsers/body-parser.urlencoded.ts +42 -0
- package/src/body-parsers/index.ts +13 -0
- package/src/body-parsers/types.ts +60 -0
- package/src/coercion/coerce-parameter.ts +207 -0
- package/src/coercion/utils.ts +103 -0
- package/src/coercion/validator.ts +98 -0
- package/src/http-handler.ts +84 -41
- package/src/index.ts +37 -30
- package/src/keys.ts +273 -20
- package/src/parse-json.ts +42 -0
- package/src/parser.ts +89 -104
- package/src/providers/{find-route.ts → find-route.provider.ts} +10 -7
- package/src/providers/index.ts +7 -9
- package/src/providers/{invoke-method.ts → invoke-method.provider.ts} +8 -5
- package/src/providers/log-error.provider.ts +27 -0
- package/src/providers/parse-params.provider.ts +42 -0
- package/src/providers/reject.provider.ts +44 -0
- package/src/providers/{send.ts → send.provider.ts} +2 -5
- package/src/request-context.ts +123 -0
- package/src/rest-http-error.ts +87 -0
- package/src/rest.application.ts +390 -0
- package/src/rest.component.ts +111 -0
- package/src/rest.server.ts +1192 -0
- package/src/router/base-route.ts +53 -0
- package/src/router/controller-route.ts +241 -0
- package/src/router/external-express-routes.ts +139 -0
- package/src/router/handler-route.ts +44 -0
- package/src/router/index.ts +24 -0
- package/src/router/openapi-path.ts +67 -0
- package/src/router/redirect-route.ts +64 -0
- package/src/router/regexp-router.ts +104 -0
- package/src/router/rest-router.ts +48 -0
- package/src/router/route-entry.ts +74 -0
- package/src/router/route-sort.ts +74 -0
- package/src/router/router-base.ts +124 -0
- package/src/router/router-spec.ts +36 -0
- package/src/router/routing-table.ts +83 -279
- package/src/router/trie-router.ts +57 -0
- package/src/router/trie.ts +233 -0
- package/src/sequence.ts +44 -37
- package/src/spec-enhancers/consolidate.spec-enhancer.ts +182 -0
- package/src/spec-enhancers/info.spec-enhancer.ts +92 -0
- package/src/types.ts +216 -0
- package/src/validation/ajv-factory.provider.ts +94 -0
- package/src/validation/request-body.validator.ts +208 -0
- package/src/writer.ts +41 -68
- package/api-docs/.DS_Store +0 -0
- package/api-docs/apple-touch-icon-114x114-precomposed.png +0 -0
- package/api-docs/apple-touch-icon-144x144-precomposed.png +0 -0
- package/api-docs/apple-touch-icon-57x57-precomposed.png +0 -0
- package/api-docs/apple-touch-icon-72x72-precomposed.png +0 -0
- package/api-docs/apple-touch-icon-precomposed.png +0 -0
- package/api-docs/apple-touch-icon.png +0 -0
- package/api-docs/css/bootstrap.min.css +0 -9
- package/api-docs/css/code-themes/arta.css +0 -158
- package/api-docs/css/code-themes/ascetic.css +0 -50
- package/api-docs/css/code-themes/brown_paper.css +0 -104
- package/api-docs/css/code-themes/brown_papersq.png +0 -0
- package/api-docs/css/code-themes/dark.css +0 -103
- package/api-docs/css/code-themes/default.css +0 -135
- package/api-docs/css/code-themes/far.css +0 -111
- package/api-docs/css/code-themes/github.css +0 -127
- package/api-docs/css/code-themes/googlecode.css +0 -144
- package/api-docs/css/code-themes/idea.css +0 -121
- package/api-docs/css/code-themes/ir_black.css +0 -104
- package/api-docs/css/code-themes/magula.css +0 -121
- package/api-docs/css/code-themes/monokai.css +0 -114
- package/api-docs/css/code-themes/pojoaque.css +0 -104
- package/api-docs/css/code-themes/pojoaque.jpg +0 -0
- package/api-docs/css/code-themes/rainbow.css +0 -114
- package/api-docs/css/code-themes/school_book.css +0 -111
- package/api-docs/css/code-themes/school_book.png +0 -0
- package/api-docs/css/code-themes/sl-theme.css +0 -45
- package/api-docs/css/code-themes/solarized_dark.css +0 -88
- package/api-docs/css/code-themes/solarized_light.css +0 -88
- package/api-docs/css/code-themes/sunburst.css +0 -158
- package/api-docs/css/code-themes/tomorrow-night-blue.css +0 -52
- package/api-docs/css/code-themes/tomorrow-night-bright.css +0 -51
- package/api-docs/css/code-themes/tomorrow-night-eighties.css +0 -51
- package/api-docs/css/code-themes/tomorrow-night.css +0 -52
- package/api-docs/css/code-themes/tomorrow.css +0 -49
- package/api-docs/css/code-themes/vs.css +0 -86
- package/api-docs/css/code-themes/xcode.css +0 -154
- package/api-docs/css/code-themes/zenburn.css +0 -115
- package/api-docs/css/main.css +0 -139
- package/api-docs/favicon.ico +0 -0
- package/api-docs/fonts/0ihfXUL2emPh0ROJezvraLO3LdcAZYWl9Si6vvxL-qU.woff +0 -0
- package/api-docs/fonts/OsJ2DjdpjqFRVUSto6IffLO3LdcAZYWl9Si6vvxL-qU.woff +0 -0
- package/api-docs/fonts/_aijTyevf54tkVDLy-dlnLO3LdcAZYWl9Si6vvxL-qU.woff +0 -0
- package/api-docs/index.html +0 -7082
- package/api-docs/js/main.js +0 -19
- package/api-docs/js/vendor/bootstrap.min.js +0 -6
- package/api-docs/js/vendor/jquery-1.10.1.min.js +0 -6
- package/api-docs/js/vendor/jquery.scrollTo-1.4.3.1.js +0 -218
- package/api-docs/js/vendor/modernizr-2.6.2-respond-1.1.0.min.js +0 -11
- package/dist/src/http-handler.d.ts +0 -19
- package/dist/src/http-handler.js +0 -43
- package/dist/src/http-handler.js.map +0 -1
- package/dist/src/index.d.ts +0 -14
- package/dist/src/index.js +0 -33
- package/dist/src/index.js.map +0 -1
- package/dist/src/internal-types.d.ts +0 -67
- package/dist/src/internal-types.js.map +0 -1
- package/dist/src/keys.d.ts +0 -22
- package/dist/src/keys.js +0 -35
- package/dist/src/keys.js.map +0 -1
- package/dist/src/parser.d.ts +0 -11
- package/dist/src/parser.js +0 -98
- package/dist/src/parser.js.map +0 -1
- package/dist/src/providers/bind-element.d.ts +0 -7
- package/dist/src/providers/bind-element.js +0 -34
- package/dist/src/providers/bind-element.js.map +0 -1
- package/dist/src/providers/find-route.d.ts +0 -9
- package/dist/src/providers/find-route.js +0 -42
- package/dist/src/providers/find-route.js.map +0 -1
- package/dist/src/providers/get-from-context.d.ts +0 -7
- package/dist/src/providers/get-from-context.js +0 -34
- package/dist/src/providers/get-from-context.js.map +0 -1
- package/dist/src/providers/index.d.ts +0 -8
- package/dist/src/providers/index.js +0 -18
- package/dist/src/providers/index.js.map +0 -1
- package/dist/src/providers/invoke-method.js +0 -36
- package/dist/src/providers/invoke-method.js.map +0 -1
- package/dist/src/providers/log-error-provider.d.ts +0 -6
- package/dist/src/providers/log-error-provider.js +0 -17
- package/dist/src/providers/log-error-provider.js.map +0 -1
- package/dist/src/providers/parse-params.d.ts +0 -13
- package/dist/src/providers/parse-params.js +0 -22
- package/dist/src/providers/parse-params.js.map +0 -1
- package/dist/src/providers/reject.d.ts +0 -6
- package/dist/src/providers/reject.js +0 -40
- package/dist/src/providers/reject.js.map +0 -1
- package/dist/src/providers/send.js.map +0 -1
- package/dist/src/rest-component.d.ts +0 -12
- package/dist/src/rest-component.js +0 -50
- package/dist/src/rest-component.js.map +0 -1
- package/dist/src/rest-server.d.ts +0 -211
- package/dist/src/rest-server.js +0 -426
- package/dist/src/rest-server.js.map +0 -1
- package/dist/src/router/metadata.d.ts +0 -150
- package/dist/src/router/metadata.js +0 -410
- package/dist/src/router/metadata.js.map +0 -1
- package/dist/src/router/routing-table.d.ts +0 -68
- package/dist/src/router/routing-table.js +0 -204
- package/dist/src/router/routing-table.js.map +0 -1
- package/dist/src/sequence.d.ts +0 -81
- package/dist/src/sequence.js +0 -104
- package/dist/src/sequence.js.map +0 -1
- package/dist/src/writer.d.ts +0 -17
- package/dist/src/writer.js +0 -87
- package/dist/src/writer.js.map +0 -1
- package/dist6/index.d.ts +0 -1
- package/dist6/index.js +0 -12
- package/dist6/src/http-handler.d.ts +0 -19
- package/dist6/src/http-handler.js +0 -53
- package/dist6/src/http-handler.js.map +0 -1
- package/dist6/src/index.d.ts +0 -14
- package/dist6/src/index.js +0 -33
- package/dist6/src/index.js.map +0 -1
- package/dist6/src/internal-types.d.ts +0 -67
- package/dist6/src/internal-types.js +0 -7
- package/dist6/src/internal-types.js.map +0 -1
- package/dist6/src/keys.d.ts +0 -22
- package/dist6/src/keys.js +0 -35
- package/dist6/src/keys.js.map +0 -1
- package/dist6/src/parser.d.ts +0 -11
- package/dist6/src/parser.js +0 -108
- package/dist6/src/parser.js.map +0 -1
- package/dist6/src/providers/bind-element.d.ts +0 -7
- package/dist6/src/providers/bind-element.js +0 -34
- package/dist6/src/providers/bind-element.js.map +0 -1
- package/dist6/src/providers/find-route.js +0 -42
- package/dist6/src/providers/find-route.js.map +0 -1
- package/dist6/src/providers/get-from-context.d.ts +0 -7
- package/dist6/src/providers/get-from-context.js +0 -34
- package/dist6/src/providers/get-from-context.js.map +0 -1
- package/dist6/src/providers/index.d.ts +0 -8
- package/dist6/src/providers/index.js +0 -18
- package/dist6/src/providers/index.js.map +0 -1
- package/dist6/src/providers/invoke-method.d.ts +0 -7
- package/dist6/src/providers/invoke-method.js +0 -44
- package/dist6/src/providers/invoke-method.js.map +0 -1
- package/dist6/src/providers/log-error-provider.d.ts +0 -6
- package/dist6/src/providers/log-error-provider.js +0 -17
- package/dist6/src/providers/log-error-provider.js.map +0 -1
- package/dist6/src/providers/parse-params.d.ts +0 -13
- package/dist6/src/providers/parse-params.js +0 -22
- package/dist6/src/providers/parse-params.js.map +0 -1
- package/dist6/src/providers/reject.d.ts +0 -6
- package/dist6/src/providers/reject.js +0 -40
- package/dist6/src/providers/reject.js.map +0 -1
- package/dist6/src/providers/send.d.ts +0 -15
- package/dist6/src/providers/send.js +0 -24
- package/dist6/src/providers/send.js.map +0 -1
- package/dist6/src/rest-component.d.ts +0 -12
- package/dist6/src/rest-component.js +0 -50
- package/dist6/src/rest-component.js.map +0 -1
- package/dist6/src/rest-server.d.ts +0 -211
- package/dist6/src/rest-server.js +0 -444
- package/dist6/src/rest-server.js.map +0 -1
- package/dist6/src/router/metadata.d.ts +0 -150
- package/dist6/src/router/metadata.js +0 -410
- package/dist6/src/router/metadata.js.map +0 -1
- package/dist6/src/router/routing-table.d.ts +0 -68
- package/dist6/src/router/routing-table.js +0 -218
- package/dist6/src/router/routing-table.js.map +0 -1
- package/dist6/src/sequence.js +0 -114
- package/dist6/src/sequence.js.map +0 -1
- package/dist6/src/writer.d.ts +0 -17
- package/dist6/src/writer.js +0 -87
- package/dist6/src/writer.js.map +0 -1
- package/index.d.ts +0 -6
- package/index.js +0 -9
- package/src/internal-types.ts +0 -96
- package/src/providers/bind-element.ts +0 -15
- package/src/providers/get-from-context.ts +0 -16
- package/src/providers/log-error-provider.ts +0 -23
- package/src/providers/parse-params.ts +0 -20
- package/src/providers/reject.ts +0 -27
- package/src/rest-component.ts +0 -54
- package/src/rest-server.ts +0 -584
- package/src/router/metadata.ts +0 -517
|
@@ -0,0 +1,748 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2018,2020. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/rest
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.createBodyParserBinding = exports.RestServer = void 0;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
9
|
+
const context_1 = require("@loopback/context");
|
|
10
|
+
const core_1 = require("@loopback/core");
|
|
11
|
+
const express_1 = require("@loopback/express");
|
|
12
|
+
const http_server_1 = require("@loopback/http-server");
|
|
13
|
+
const openapi_v3_1 = require("@loopback/openapi-v3");
|
|
14
|
+
const assert_1 = tslib_1.__importStar(require("assert"));
|
|
15
|
+
const cors_1 = tslib_1.__importDefault(require("cors"));
|
|
16
|
+
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
17
|
+
const express_2 = tslib_1.__importDefault(require("express"));
|
|
18
|
+
const js_yaml_1 = require("js-yaml");
|
|
19
|
+
const lodash_1 = require("lodash");
|
|
20
|
+
const strong_error_handler_1 = require("strong-error-handler");
|
|
21
|
+
const body_parsers_1 = require("./body-parsers");
|
|
22
|
+
const http_handler_1 = require("./http-handler");
|
|
23
|
+
const keys_1 = require("./keys");
|
|
24
|
+
const request_context_1 = require("./request-context");
|
|
25
|
+
const router_1 = require("./router");
|
|
26
|
+
const router_spec_1 = require("./router/router-spec");
|
|
27
|
+
const sequence_1 = require("./sequence");
|
|
28
|
+
const debug = debug_1.default('loopback:rest:server');
|
|
29
|
+
const SequenceActions = keys_1.RestBindings.SequenceActions;
|
|
30
|
+
/**
|
|
31
|
+
* A REST API server for use with Loopback.
|
|
32
|
+
* Add this server to your application by importing the RestComponent.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const app = new MyApplication();
|
|
37
|
+
* app.component(RestComponent);
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* To add additional instances of RestServer to your application, use the
|
|
41
|
+
* `.server` function:
|
|
42
|
+
* ```ts
|
|
43
|
+
* app.server(RestServer, 'nameOfYourServer');
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* By default, one instance of RestServer will be created when the RestComponent
|
|
47
|
+
* is bootstrapped. This instance can be retrieved with
|
|
48
|
+
* `app.getServer(RestServer)`, or by calling `app.get('servers.RestServer')`
|
|
49
|
+
* Note that retrieving other instances of RestServer must be done using the
|
|
50
|
+
* server's name:
|
|
51
|
+
* ```ts
|
|
52
|
+
* const server = await app.getServer('foo')
|
|
53
|
+
* // OR
|
|
54
|
+
* const server = await app.get('servers.foo');
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
let RestServer = /** @class */ (() => {
|
|
58
|
+
let RestServer = class RestServer extends express_1.BaseMiddlewareRegistry {
|
|
59
|
+
/**
|
|
60
|
+
*
|
|
61
|
+
* Creates an instance of RestServer.
|
|
62
|
+
*
|
|
63
|
+
* @param app - The application instance (injected via
|
|
64
|
+
* CoreBindings.APPLICATION_INSTANCE).
|
|
65
|
+
* @param config - The configuration options (injected via
|
|
66
|
+
* RestBindings.CONFIG).
|
|
67
|
+
*
|
|
68
|
+
*/
|
|
69
|
+
constructor(app, config = {}) {
|
|
70
|
+
var _a;
|
|
71
|
+
super(app);
|
|
72
|
+
/*
|
|
73
|
+
* Registry of external routes & static assets
|
|
74
|
+
*/
|
|
75
|
+
this._externalRoutes = new router_1.ExternalExpressRoutes();
|
|
76
|
+
this.config = resolveRestServerConfig(config);
|
|
77
|
+
this.bind(keys_1.RestBindings.PORT).to(this.config.port);
|
|
78
|
+
this.bind(keys_1.RestBindings.HOST).to(config.host);
|
|
79
|
+
this.bind(keys_1.RestBindings.PATH).to(config.path);
|
|
80
|
+
this.bind(keys_1.RestBindings.PROTOCOL).to((_a = config.protocol) !== null && _a !== void 0 ? _a : 'http');
|
|
81
|
+
this.bind(keys_1.RestBindings.HTTPS_OPTIONS).to(config);
|
|
82
|
+
if (config.requestBodyParser) {
|
|
83
|
+
this.bind(keys_1.RestBindings.REQUEST_BODY_PARSER_OPTIONS).to(config.requestBodyParser);
|
|
84
|
+
}
|
|
85
|
+
if (config.sequence) {
|
|
86
|
+
this.sequence(config.sequence);
|
|
87
|
+
}
|
|
88
|
+
if (config.router) {
|
|
89
|
+
this.bind(keys_1.RestBindings.ROUTER_OPTIONS).to(config.router);
|
|
90
|
+
}
|
|
91
|
+
this.basePath(config.basePath);
|
|
92
|
+
this.bind(keys_1.RestBindings.BASE_PATH).toDynamicValue(() => this._basePath);
|
|
93
|
+
this.bind(keys_1.RestBindings.HANDLER).toDynamicValue(() => this.httpHandler);
|
|
94
|
+
}
|
|
95
|
+
get OASEnhancer() {
|
|
96
|
+
this._setupOASEnhancerIfNeeded();
|
|
97
|
+
return this._OASEnhancer;
|
|
98
|
+
}
|
|
99
|
+
get requestHandler() {
|
|
100
|
+
if (this._requestHandler == null) {
|
|
101
|
+
this._setupRequestHandlerIfNeeded();
|
|
102
|
+
}
|
|
103
|
+
return this._requestHandler;
|
|
104
|
+
}
|
|
105
|
+
get httpHandler() {
|
|
106
|
+
this._setupHandlerIfNeeded();
|
|
107
|
+
return this._httpHandler;
|
|
108
|
+
}
|
|
109
|
+
get listening() {
|
|
110
|
+
return this._httpServer ? this._httpServer.listening : false;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The base url for the server, including the basePath if set. For example,
|
|
114
|
+
* the value will be 'http://localhost:3000/api' if `basePath` is set to
|
|
115
|
+
* '/api'.
|
|
116
|
+
*/
|
|
117
|
+
get url() {
|
|
118
|
+
let serverUrl = this.rootUrl;
|
|
119
|
+
if (!serverUrl)
|
|
120
|
+
return serverUrl;
|
|
121
|
+
serverUrl = serverUrl + (this._basePath || '');
|
|
122
|
+
return serverUrl;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* The root url for the server without the basePath. For example, the value
|
|
126
|
+
* will be 'http://localhost:3000' regardless of the `basePath`.
|
|
127
|
+
*/
|
|
128
|
+
get rootUrl() {
|
|
129
|
+
return this._httpServer && this._httpServer.url;
|
|
130
|
+
}
|
|
131
|
+
_setupOASEnhancerIfNeeded() {
|
|
132
|
+
if (this._OASEnhancer != null)
|
|
133
|
+
return;
|
|
134
|
+
this.add(context_1.createBindingFromClass(openapi_v3_1.OASEnhancerService, {
|
|
135
|
+
key: openapi_v3_1.OASEnhancerBindings.OAS_ENHANCER_SERVICE,
|
|
136
|
+
}));
|
|
137
|
+
this._OASEnhancer = this.getSync(openapi_v3_1.OASEnhancerBindings.OAS_ENHANCER_SERVICE);
|
|
138
|
+
}
|
|
139
|
+
_setupRequestHandlerIfNeeded() {
|
|
140
|
+
if (this._expressApp != null)
|
|
141
|
+
return;
|
|
142
|
+
this._expressApp = express_2.default();
|
|
143
|
+
this._applyExpressSettings();
|
|
144
|
+
this._requestHandler = this._expressApp;
|
|
145
|
+
// Allow CORS support for all endpoints so that users
|
|
146
|
+
// can test with online SwaggerUI instance
|
|
147
|
+
this.expressMiddleware(cors_1.default, this.config.cors, {
|
|
148
|
+
injectConfiguration: false,
|
|
149
|
+
key: 'middleware.cors',
|
|
150
|
+
group: 'cors',
|
|
151
|
+
});
|
|
152
|
+
// Set up endpoints for OpenAPI spec/ui
|
|
153
|
+
this._setupOpenApiSpecEndpoints();
|
|
154
|
+
// Mount our router & request handler
|
|
155
|
+
this._expressApp.use(this._basePath, (req, res, next) => {
|
|
156
|
+
this._handleHttpRequest(req, res).catch(next);
|
|
157
|
+
});
|
|
158
|
+
// Mount our error handler
|
|
159
|
+
this._expressApp.use(this._unexpectedErrorHandler());
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get an Express handler for unexpected errors
|
|
163
|
+
*/
|
|
164
|
+
_unexpectedErrorHandler() {
|
|
165
|
+
const handleUnExpectedError = (err, req, res, next) => {
|
|
166
|
+
// Handle errors reported by Express middleware such as CORS
|
|
167
|
+
// First try to use the `REJECT` action
|
|
168
|
+
this.get(SequenceActions.REJECT, { optional: true })
|
|
169
|
+
.then(reject => {
|
|
170
|
+
if (reject) {
|
|
171
|
+
// TODO(rfeng): There is a possibility that the error is thrown
|
|
172
|
+
// from the `REJECT` action in the sequence
|
|
173
|
+
return reject({ request: req, response: res }, err);
|
|
174
|
+
}
|
|
175
|
+
// Use strong-error handler directly
|
|
176
|
+
strong_error_handler_1.writeErrorToResponse(err, req, res);
|
|
177
|
+
})
|
|
178
|
+
.catch(unexpectedErr => next(unexpectedErr));
|
|
179
|
+
};
|
|
180
|
+
return handleUnExpectedError;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Apply express settings.
|
|
184
|
+
*/
|
|
185
|
+
_applyExpressSettings() {
|
|
186
|
+
assertExists(this._expressApp, 'this._expressApp');
|
|
187
|
+
const settings = this.config.expressSettings;
|
|
188
|
+
for (const key in settings) {
|
|
189
|
+
this._expressApp.set(key, settings[key]);
|
|
190
|
+
}
|
|
191
|
+
if (this.config.router && typeof this.config.router.strict === 'boolean') {
|
|
192
|
+
this._expressApp.set('strict routing', this.config.router.strict);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Mount /openapi.json, /openapi.yaml for specs and /swagger-ui, /explorer
|
|
197
|
+
* to redirect to externally hosted API explorer
|
|
198
|
+
*/
|
|
199
|
+
_setupOpenApiSpecEndpoints() {
|
|
200
|
+
assertExists(this._expressApp, 'this._expressApp');
|
|
201
|
+
if (this.config.openApiSpec.disabled)
|
|
202
|
+
return;
|
|
203
|
+
const router = express_2.default.Router();
|
|
204
|
+
const mapping = this.config.openApiSpec.endpointMapping;
|
|
205
|
+
// Serving OpenAPI spec
|
|
206
|
+
for (const p in mapping) {
|
|
207
|
+
this.addOpenApiSpecEndpoint(p, mapping[p], router);
|
|
208
|
+
}
|
|
209
|
+
const explorerPaths = ['/swagger-ui', '/explorer'];
|
|
210
|
+
router.get(explorerPaths, (req, res, next) => this._redirectToSwaggerUI(req, res, next));
|
|
211
|
+
this.expressMiddleware('middleware.apiSpec.defaults', router, {
|
|
212
|
+
group: 'apiSpec',
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Add a new non-controller endpoint hosting a form of the OpenAPI spec.
|
|
217
|
+
*
|
|
218
|
+
* @param path Path at which to host the copy of the OpenAPI
|
|
219
|
+
* @param form Form that should be rendered from that path
|
|
220
|
+
*/
|
|
221
|
+
addOpenApiSpecEndpoint(path, form, router) {
|
|
222
|
+
if (router == null) {
|
|
223
|
+
const key = `middleware.apiSpec.${path}.${form}`;
|
|
224
|
+
if (this.contains(key)) {
|
|
225
|
+
throw new Error(`The path ${path} is already configured for OpenApi hosting`);
|
|
226
|
+
}
|
|
227
|
+
const newRouter = express_2.default.Router();
|
|
228
|
+
newRouter.get(path, (req, res) => this._serveOpenApiSpec(req, res, form));
|
|
229
|
+
this.expressMiddleware(() => newRouter, {}, {
|
|
230
|
+
injectConfiguration: false,
|
|
231
|
+
key: `middleware.apiSpec.${path}.${form}`,
|
|
232
|
+
group: 'apiSpec',
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
router.get(path, (req, res) => this._serveOpenApiSpec(req, res, form));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
_handleHttpRequest(request, response) {
|
|
240
|
+
return this.httpHandler.handleRequest(request, response);
|
|
241
|
+
}
|
|
242
|
+
_setupHandlerIfNeeded() {
|
|
243
|
+
if (this._httpHandler)
|
|
244
|
+
return;
|
|
245
|
+
// Watch for binding events
|
|
246
|
+
// See https://github.com/strongloop/loopback-next/issues/433
|
|
247
|
+
const routesObserver = {
|
|
248
|
+
filter: binding => context_1.filterByKey(keys_1.RestBindings.API_SPEC.key)(binding) ||
|
|
249
|
+
(context_1.filterByKey(/^(controllers|routes)\..+/)(binding) &&
|
|
250
|
+
// Exclude controller routes to avoid circular events
|
|
251
|
+
!context_1.filterByTag(keys_1.RestTags.CONTROLLER_ROUTE)(binding)),
|
|
252
|
+
observe: () => {
|
|
253
|
+
// Rebuild the HttpHandler instance whenever a controller/route was
|
|
254
|
+
// added/deleted.
|
|
255
|
+
this._createHttpHandler();
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
this._routesEventSubscription = this.subscribe(routesObserver);
|
|
259
|
+
this._createHttpHandler();
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Create an instance of HttpHandler and populates it with routes
|
|
263
|
+
*/
|
|
264
|
+
_createHttpHandler() {
|
|
265
|
+
/**
|
|
266
|
+
* Check if there is custom router in the context
|
|
267
|
+
*/
|
|
268
|
+
const router = this.getSync(keys_1.RestBindings.ROUTER, { optional: true });
|
|
269
|
+
const routingTable = new router_1.RoutingTable(router, this._externalRoutes);
|
|
270
|
+
this._httpHandler = new http_handler_1.HttpHandler(this, this.config, routingTable);
|
|
271
|
+
// Remove controller routes
|
|
272
|
+
for (const b of this.findByTag(keys_1.RestTags.CONTROLLER_ROUTE)) {
|
|
273
|
+
this.unbind(b.key);
|
|
274
|
+
}
|
|
275
|
+
for (const b of this.find(`${core_1.CoreBindings.CONTROLLERS}.*`)) {
|
|
276
|
+
const controllerName = b.key.replace(/^controllers\./, '');
|
|
277
|
+
const ctor = b.valueConstructor;
|
|
278
|
+
if (!ctor) {
|
|
279
|
+
throw new Error(`The controller ${controllerName} was not bound via .toClass()`);
|
|
280
|
+
}
|
|
281
|
+
const apiSpec = openapi_v3_1.getControllerSpec(ctor);
|
|
282
|
+
if (!apiSpec) {
|
|
283
|
+
// controller methods are specified through app.api() spec
|
|
284
|
+
debug('Skipping controller %s - no API spec provided', controllerName);
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
debug('Registering controller %s', controllerName);
|
|
288
|
+
if (apiSpec.components) {
|
|
289
|
+
this._httpHandler.registerApiComponents(apiSpec.components);
|
|
290
|
+
}
|
|
291
|
+
const controllerFactory = router_1.createControllerFactoryForBinding(b.key);
|
|
292
|
+
const routes = router_1.createRoutesForController(apiSpec, ctor, controllerFactory);
|
|
293
|
+
for (const route of routes) {
|
|
294
|
+
const binding = this.bindRoute(route);
|
|
295
|
+
binding
|
|
296
|
+
.tag(keys_1.RestTags.CONTROLLER_ROUTE)
|
|
297
|
+
.tag({ [keys_1.RestTags.CONTROLLER_BINDING]: b.key });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
for (const b of this.findByTag(keys_1.RestTags.REST_ROUTE)) {
|
|
301
|
+
// TODO(bajtos) should we support routes defined asynchronously?
|
|
302
|
+
const route = this.getSync(b.key);
|
|
303
|
+
this._httpHandler.registerRoute(route);
|
|
304
|
+
}
|
|
305
|
+
// TODO(bajtos) should we support API spec defined asynchronously?
|
|
306
|
+
const spec = this.getSync(keys_1.RestBindings.API_SPEC);
|
|
307
|
+
for (const path in spec.paths) {
|
|
308
|
+
for (const verb in spec.paths[path]) {
|
|
309
|
+
const routeSpec = spec.paths[path][verb];
|
|
310
|
+
this._setupOperation(verb, path, routeSpec);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
_setupOperation(verb, path, spec) {
|
|
315
|
+
const handler = spec['x-operation'];
|
|
316
|
+
if (typeof handler === 'function') {
|
|
317
|
+
// Remove a field value that cannot be represented in JSON.
|
|
318
|
+
// Start by creating a shallow-copy of the spec, so that we don't
|
|
319
|
+
// modify the original spec object provided by user.
|
|
320
|
+
spec = Object.assign({}, spec);
|
|
321
|
+
delete spec['x-operation'];
|
|
322
|
+
const route = new router_1.Route(verb, path, spec, handler);
|
|
323
|
+
this._httpHandler.registerRoute(route);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const controllerName = spec['x-controller-name'];
|
|
327
|
+
if (typeof controllerName === 'string') {
|
|
328
|
+
const b = this.getBinding(`controllers.${controllerName}`, {
|
|
329
|
+
optional: true,
|
|
330
|
+
});
|
|
331
|
+
if (!b) {
|
|
332
|
+
throw new Error(`Unknown controller ${controllerName} used by "${verb} ${path}"`);
|
|
333
|
+
}
|
|
334
|
+
const ctor = b.valueConstructor;
|
|
335
|
+
if (!ctor) {
|
|
336
|
+
throw new Error(`The controller ${controllerName} was not bound via .toClass()`);
|
|
337
|
+
}
|
|
338
|
+
const controllerFactory = router_1.createControllerFactoryForBinding(b.key);
|
|
339
|
+
const route = new router_1.ControllerRoute(verb, path, spec, ctor, controllerFactory);
|
|
340
|
+
this._httpHandler.registerRoute(route);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
throw new Error(`There is no handler configured for operation "${verb} ${path}`);
|
|
344
|
+
}
|
|
345
|
+
async _serveOpenApiSpec(request, response, specForm) {
|
|
346
|
+
const requestContext = new request_context_1.RequestContext(request, response, this, this.config);
|
|
347
|
+
specForm = specForm !== null && specForm !== void 0 ? specForm : { version: '3.0.0', format: 'json' };
|
|
348
|
+
const specObj = await this.getApiSpec(requestContext);
|
|
349
|
+
if (specForm.format === 'json') {
|
|
350
|
+
const spec = JSON.stringify(specObj, null, 2);
|
|
351
|
+
response.setHeader('content-type', 'application/json; charset=utf-8');
|
|
352
|
+
response.end(spec, 'utf-8');
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
const yaml = js_yaml_1.safeDump(specObj, {});
|
|
356
|
+
response.setHeader('content-type', 'text/yaml; charset=utf-8');
|
|
357
|
+
response.end(yaml, 'utf-8');
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
async _redirectToSwaggerUI(request, response, next) {
|
|
361
|
+
const config = this.config.apiExplorer;
|
|
362
|
+
if (config.disabled) {
|
|
363
|
+
debug('Redirect to swagger-ui was disabled by configuration.');
|
|
364
|
+
next();
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
debug('Redirecting to swagger-ui from %j.', request.originalUrl);
|
|
368
|
+
const requestContext = new request_context_1.RequestContext(request, response, this, this.config);
|
|
369
|
+
const protocol = requestContext.requestedProtocol;
|
|
370
|
+
const baseUrl = protocol === 'http' ? config.httpUrl : config.url;
|
|
371
|
+
const openApiUrl = `${requestContext.requestedBaseUrl}/openapi.json`;
|
|
372
|
+
const fullUrl = `${baseUrl}?url=${openApiUrl}`;
|
|
373
|
+
response.redirect(302, fullUrl);
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Register a controller class with this server.
|
|
377
|
+
*
|
|
378
|
+
* @param controllerCtor - The controller class
|
|
379
|
+
* (constructor function).
|
|
380
|
+
* @returns The newly created binding, you can use the reference to
|
|
381
|
+
* further modify the binding, e.g. lock the value to prevent further
|
|
382
|
+
* modifications.
|
|
383
|
+
*
|
|
384
|
+
* @example
|
|
385
|
+
* ```ts
|
|
386
|
+
* class MyController {
|
|
387
|
+
* }
|
|
388
|
+
* app.controller(MyController).lock();
|
|
389
|
+
* ```
|
|
390
|
+
*
|
|
391
|
+
*/
|
|
392
|
+
controller(controllerCtor) {
|
|
393
|
+
return this.bind('controllers.' + controllerCtor.name).toClass(controllerCtor);
|
|
394
|
+
}
|
|
395
|
+
route(routeOrVerb, path, spec, controllerCtorOrHandler, controllerFactory, methodName) {
|
|
396
|
+
if (typeof routeOrVerb === 'object') {
|
|
397
|
+
const r = routeOrVerb;
|
|
398
|
+
// Encode the path to escape special chars
|
|
399
|
+
return this.bindRoute(r);
|
|
400
|
+
}
|
|
401
|
+
if (!path) {
|
|
402
|
+
throw new assert_1.AssertionError({
|
|
403
|
+
message: 'path is required for a controller-based route',
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
if (!spec) {
|
|
407
|
+
throw new assert_1.AssertionError({
|
|
408
|
+
message: 'spec is required for a controller-based route',
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
if (arguments.length === 4) {
|
|
412
|
+
if (!controllerCtorOrHandler) {
|
|
413
|
+
throw new assert_1.AssertionError({
|
|
414
|
+
message: 'handler function is required for a handler-based route',
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
return this.route(new router_1.Route(routeOrVerb, path, spec, controllerCtorOrHandler));
|
|
418
|
+
}
|
|
419
|
+
if (!controllerCtorOrHandler) {
|
|
420
|
+
throw new assert_1.AssertionError({
|
|
421
|
+
message: 'controller is required for a controller-based route',
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
if (!methodName) {
|
|
425
|
+
throw new assert_1.AssertionError({
|
|
426
|
+
message: 'methodName is required for a controller-based route',
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
return this.route(new router_1.ControllerRoute(routeOrVerb, path, spec, controllerCtorOrHandler, controllerFactory, methodName));
|
|
430
|
+
}
|
|
431
|
+
bindRoute(r) {
|
|
432
|
+
const namespace = keys_1.RestBindings.ROUTES;
|
|
433
|
+
const encodedPath = encodeURIComponent(r.path).replace(/\./g, '%2E');
|
|
434
|
+
return this.bind(`${namespace}.${r.verb} ${encodedPath}`)
|
|
435
|
+
.to(r)
|
|
436
|
+
.tag(keys_1.RestTags.REST_ROUTE)
|
|
437
|
+
.tag({ [keys_1.RestTags.ROUTE_VERB]: r.verb, [keys_1.RestTags.ROUTE_PATH]: r.path });
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Register a route redirecting callers to a different URL.
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* ```ts
|
|
444
|
+
* server.redirect('/explorer', '/explorer/');
|
|
445
|
+
* ```
|
|
446
|
+
*
|
|
447
|
+
* @param fromPath - URL path of the redirect endpoint
|
|
448
|
+
* @param toPathOrUrl - Location (URL path or full URL) where to redirect to.
|
|
449
|
+
* If your server is configured with a custom `basePath`, then the base path
|
|
450
|
+
* is prepended to the target location.
|
|
451
|
+
* @param statusCode - HTTP status code to respond with,
|
|
452
|
+
* defaults to 303 (See Other).
|
|
453
|
+
*/
|
|
454
|
+
redirect(fromPath, toPathOrUrl, statusCode) {
|
|
455
|
+
return this.route(new router_1.RedirectRoute(fromPath, this._basePath + toPathOrUrl, statusCode));
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Mount static assets to the REST server.
|
|
459
|
+
* See https://expressjs.com/en/4x/api.html#express.static
|
|
460
|
+
* @param path - The path(s) to serve the asset.
|
|
461
|
+
* See examples at https://expressjs.com/en/4x/api.html#path-examples
|
|
462
|
+
* @param rootDir - The root directory from which to serve static assets
|
|
463
|
+
* @param options - Options for serve-static
|
|
464
|
+
*/
|
|
465
|
+
static(path, rootDir, options) {
|
|
466
|
+
this._externalRoutes.registerAssets(path, rootDir, options);
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Set the OpenAPI specification that defines the REST API schema for this
|
|
470
|
+
* server. All routes, parameter definitions and return types will be defined
|
|
471
|
+
* in this way.
|
|
472
|
+
*
|
|
473
|
+
* Note that this will override any routes defined via decorators at the
|
|
474
|
+
* controller level (this function takes precedent).
|
|
475
|
+
*
|
|
476
|
+
* @param spec - The OpenAPI specification, as an object.
|
|
477
|
+
* @returns Binding for the spec
|
|
478
|
+
*
|
|
479
|
+
*/
|
|
480
|
+
api(spec) {
|
|
481
|
+
return this.bind(keys_1.RestBindings.API_SPEC).to(spec);
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Get the OpenAPI specification describing the REST API provided by
|
|
485
|
+
* this application.
|
|
486
|
+
*
|
|
487
|
+
* This method merges operations (HTTP endpoints) from the following sources:
|
|
488
|
+
* - `app.api(spec)`
|
|
489
|
+
* - `app.controller(MyController)`
|
|
490
|
+
* - `app.route(route)`
|
|
491
|
+
* - `app.route('get', '/greet', operationSpec, MyController, 'greet')`
|
|
492
|
+
*
|
|
493
|
+
* If the optional `requestContext` is provided, then the `servers` list
|
|
494
|
+
* in the returned spec will be updated to work in that context.
|
|
495
|
+
* Specifically:
|
|
496
|
+
* 1. if `config.openApi.setServersFromRequest` is enabled, the servers
|
|
497
|
+
* list will be replaced with the context base url
|
|
498
|
+
* 2. Any `servers` entries with a path of `/` will have that path
|
|
499
|
+
* replaced with `requestContext.basePath`
|
|
500
|
+
*
|
|
501
|
+
* @param requestContext - Optional context to update the `servers` list
|
|
502
|
+
* in the returned spec
|
|
503
|
+
*/
|
|
504
|
+
async getApiSpec(requestContext) {
|
|
505
|
+
let spec = await this.get(keys_1.RestBindings.API_SPEC);
|
|
506
|
+
const components = this.httpHandler.getApiComponents();
|
|
507
|
+
// Apply deep clone to prevent getApiSpec() callers from
|
|
508
|
+
// accidentally modifying our internal routing data
|
|
509
|
+
spec.paths = lodash_1.cloneDeep(this.httpHandler.describeApiPaths());
|
|
510
|
+
if (components) {
|
|
511
|
+
const defs = lodash_1.cloneDeep(components);
|
|
512
|
+
spec.components = { ...spec.components, ...defs };
|
|
513
|
+
}
|
|
514
|
+
router_spec_1.assignRouterSpec(spec, this._externalRoutes.routerSpec);
|
|
515
|
+
if (requestContext) {
|
|
516
|
+
spec = this.updateSpecFromRequest(spec, requestContext);
|
|
517
|
+
}
|
|
518
|
+
// Apply OAS enhancers to the OpenAPI specification
|
|
519
|
+
this.OASEnhancer.spec = spec;
|
|
520
|
+
spec = await this.OASEnhancer.applyAllEnhancers();
|
|
521
|
+
return spec;
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Update or rebuild OpenAPI Spec object to be appropriate for the context of
|
|
525
|
+
* a specific request for the spec, leveraging both app config and request
|
|
526
|
+
* path information.
|
|
527
|
+
*
|
|
528
|
+
* @param spec base spec object from which to start
|
|
529
|
+
* @param requestContext request to use to infer path information
|
|
530
|
+
* @returns Updated or rebuilt spec object to use in the context of the request
|
|
531
|
+
*/
|
|
532
|
+
updateSpecFromRequest(spec, requestContext) {
|
|
533
|
+
if (this.config.openApiSpec.setServersFromRequest) {
|
|
534
|
+
spec = Object.assign({}, spec);
|
|
535
|
+
spec.servers = [{ url: requestContext.requestedBaseUrl }];
|
|
536
|
+
}
|
|
537
|
+
const basePath = requestContext.basePath;
|
|
538
|
+
if (spec.servers && basePath) {
|
|
539
|
+
for (const s of spec.servers) {
|
|
540
|
+
// Update the default server url to honor `basePath`
|
|
541
|
+
if (s.url === '/') {
|
|
542
|
+
s.url = basePath;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return spec;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Configure a custom sequence class for handling incoming requests.
|
|
550
|
+
*
|
|
551
|
+
* @example
|
|
552
|
+
* ```ts
|
|
553
|
+
* class MySequence implements SequenceHandler {
|
|
554
|
+
* constructor(
|
|
555
|
+
* @inject('send) public send: Send)) {
|
|
556
|
+
* }
|
|
557
|
+
*
|
|
558
|
+
* public async handle({response}: RequestContext) {
|
|
559
|
+
* send(response, 'hello world');
|
|
560
|
+
* }
|
|
561
|
+
* }
|
|
562
|
+
* ```
|
|
563
|
+
*
|
|
564
|
+
* @param value - The sequence to invoke for each incoming request.
|
|
565
|
+
*/
|
|
566
|
+
sequence(value) {
|
|
567
|
+
this.bind(keys_1.RestBindings.SEQUENCE).toClass(value);
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Configure a custom sequence function for handling incoming requests.
|
|
571
|
+
*
|
|
572
|
+
* @example
|
|
573
|
+
* ```ts
|
|
574
|
+
* app.handler(({request, response}, sequence) => {
|
|
575
|
+
* sequence.send(response, 'hello world');
|
|
576
|
+
* });
|
|
577
|
+
* ```
|
|
578
|
+
*
|
|
579
|
+
* @param handlerFn - The handler to invoke for each incoming request.
|
|
580
|
+
*/
|
|
581
|
+
handler(handlerFn) {
|
|
582
|
+
class SequenceFromFunction extends sequence_1.DefaultSequence {
|
|
583
|
+
async handle(context) {
|
|
584
|
+
return handlerFn(context, this);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
this.sequence(SequenceFromFunction);
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Bind a body parser to the server context
|
|
591
|
+
* @param parserClass - Body parser class
|
|
592
|
+
* @param address - Optional binding address
|
|
593
|
+
*/
|
|
594
|
+
bodyParser(bodyParserClass, address) {
|
|
595
|
+
const binding = createBodyParserBinding(bodyParserClass, address);
|
|
596
|
+
this.add(binding);
|
|
597
|
+
return binding;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Configure the `basePath` for the rest server
|
|
601
|
+
* @param path - Base path
|
|
602
|
+
*/
|
|
603
|
+
basePath(path = '') {
|
|
604
|
+
if (this._requestHandler != null) {
|
|
605
|
+
throw new Error('Base path cannot be set as the request handler has been created');
|
|
606
|
+
}
|
|
607
|
+
// Trim leading and trailing `/`
|
|
608
|
+
path = path.replace(/(^\/)|(\/$)/, '');
|
|
609
|
+
if (path)
|
|
610
|
+
path = '/' + path;
|
|
611
|
+
this._basePath = path;
|
|
612
|
+
this.config.basePath = path;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Start this REST API's HTTP/HTTPS server.
|
|
616
|
+
*/
|
|
617
|
+
async start() {
|
|
618
|
+
// Set up the Express app if not done yet
|
|
619
|
+
this._setupRequestHandlerIfNeeded();
|
|
620
|
+
// Setup the HTTP handler so that we can verify the configuration
|
|
621
|
+
// of API spec, controllers and routes at startup time.
|
|
622
|
+
this._setupHandlerIfNeeded();
|
|
623
|
+
const port = await this.get(keys_1.RestBindings.PORT);
|
|
624
|
+
const host = await this.get(keys_1.RestBindings.HOST);
|
|
625
|
+
const path = await this.get(keys_1.RestBindings.PATH);
|
|
626
|
+
const protocol = await this.get(keys_1.RestBindings.PROTOCOL);
|
|
627
|
+
const httpsOptions = await this.get(keys_1.RestBindings.HTTPS_OPTIONS);
|
|
628
|
+
if (this.config.listenOnStart === false) {
|
|
629
|
+
debug('RestServer is not listening as listenOnStart flag is set to false.');
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
const serverOptions = {};
|
|
633
|
+
if (protocol === 'https')
|
|
634
|
+
Object.assign(serverOptions, httpsOptions);
|
|
635
|
+
Object.assign(serverOptions, { port, host, protocol, path });
|
|
636
|
+
this._httpServer = new http_server_1.HttpServer(this.requestHandler, serverOptions);
|
|
637
|
+
await this._httpServer.start();
|
|
638
|
+
this.bind(keys_1.RestBindings.PORT).to(this._httpServer.port);
|
|
639
|
+
this.bind(keys_1.RestBindings.HOST).to(this._httpServer.host);
|
|
640
|
+
this.bind(keys_1.RestBindings.URL).to(this._httpServer.url);
|
|
641
|
+
debug('RestServer listening at %s', this._httpServer.url);
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Stop this REST API's HTTP/HTTPS server.
|
|
645
|
+
*/
|
|
646
|
+
async stop() {
|
|
647
|
+
// Kill the server instance.
|
|
648
|
+
if (!this._httpServer)
|
|
649
|
+
return;
|
|
650
|
+
await this._httpServer.stop();
|
|
651
|
+
this._httpServer = undefined;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Mount an Express router to expose additional REST endpoints handled
|
|
655
|
+
* via legacy Express-based stack.
|
|
656
|
+
*
|
|
657
|
+
* @param basePath - Path where to mount the router at, e.g. `/` or `/api`.
|
|
658
|
+
* @param router - The Express router to handle the requests.
|
|
659
|
+
* @param spec - A partial OpenAPI spec describing endpoints provided by the
|
|
660
|
+
* router. LoopBack will prepend `basePath` to all endpoints automatically.
|
|
661
|
+
* This argument is optional. You can leave it out if you don't want to
|
|
662
|
+
* document the routes.
|
|
663
|
+
*/
|
|
664
|
+
mountExpressRouter(basePath, router, spec) {
|
|
665
|
+
this._externalRoutes.mountRouter(basePath, router, spec);
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
RestServer = tslib_1.__decorate([
|
|
669
|
+
tslib_1.__param(0, context_1.inject(core_1.CoreBindings.APPLICATION_INSTANCE)),
|
|
670
|
+
tslib_1.__param(1, context_1.inject(keys_1.RestBindings.CONFIG, { optional: true })),
|
|
671
|
+
tslib_1.__metadata("design:paramtypes", [core_1.Application, Object])
|
|
672
|
+
], RestServer);
|
|
673
|
+
return RestServer;
|
|
674
|
+
})();
|
|
675
|
+
exports.RestServer = RestServer;
|
|
676
|
+
/**
|
|
677
|
+
* An assertion type guard for TypeScript to instruct the compiler that the
|
|
678
|
+
* given value is not `null` or `undefined.
|
|
679
|
+
* @param val - A value can be `undefined` or `null`
|
|
680
|
+
* @param name - Name of the value
|
|
681
|
+
*/
|
|
682
|
+
function assertExists(val, name) {
|
|
683
|
+
assert_1.default(val != null, `The value of ${name} cannot be null or undefined`);
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Create a binding for the given body parser class
|
|
687
|
+
* @param parserClass - Body parser class
|
|
688
|
+
* @param key - Optional binding address
|
|
689
|
+
*/
|
|
690
|
+
function createBodyParserBinding(parserClass, key) {
|
|
691
|
+
const address = key !== null && key !== void 0 ? key : `${keys_1.RestBindings.REQUEST_BODY_PARSER}.${parserClass.name}`;
|
|
692
|
+
return context_1.Binding.bind(address)
|
|
693
|
+
.toClass(parserClass)
|
|
694
|
+
.inScope(context_1.BindingScope.TRANSIENT)
|
|
695
|
+
.tag(body_parsers_1.REQUEST_BODY_PARSER_TAG);
|
|
696
|
+
}
|
|
697
|
+
exports.createBodyParserBinding = createBodyParserBinding;
|
|
698
|
+
const OPENAPI_SPEC_MAPPING = {
|
|
699
|
+
'/openapi.json': { version: '3.0.0', format: 'json' },
|
|
700
|
+
'/openapi.yaml': { version: '3.0.0', format: 'yaml' },
|
|
701
|
+
};
|
|
702
|
+
const DEFAULT_CONFIG = {
|
|
703
|
+
port: 3000,
|
|
704
|
+
openApiSpec: {},
|
|
705
|
+
apiExplorer: {},
|
|
706
|
+
cors: {
|
|
707
|
+
origin: '*',
|
|
708
|
+
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
|
709
|
+
preflightContinue: false,
|
|
710
|
+
optionsSuccessStatus: 204,
|
|
711
|
+
maxAge: 86400,
|
|
712
|
+
credentials: true,
|
|
713
|
+
},
|
|
714
|
+
expressSettings: {},
|
|
715
|
+
router: {},
|
|
716
|
+
listenOnStart: true,
|
|
717
|
+
};
|
|
718
|
+
function resolveRestServerConfig(config) {
|
|
719
|
+
const result = Object.assign(lodash_1.cloneDeep(DEFAULT_CONFIG), config);
|
|
720
|
+
// Can't check falsiness, 0 is a valid port.
|
|
721
|
+
if (result.port == null) {
|
|
722
|
+
result.port = 3000;
|
|
723
|
+
}
|
|
724
|
+
if (result.host == null) {
|
|
725
|
+
// Set it to '' so that the http server will listen on all interfaces
|
|
726
|
+
result.host = undefined;
|
|
727
|
+
}
|
|
728
|
+
if (!result.openApiSpec.endpointMapping) {
|
|
729
|
+
// mapping may be mutated by addOpenApiSpecEndpoint, be sure that doesn't
|
|
730
|
+
// pollute the default mapping configuration
|
|
731
|
+
result.openApiSpec.endpointMapping = lodash_1.cloneDeep(OPENAPI_SPEC_MAPPING);
|
|
732
|
+
}
|
|
733
|
+
result.apiExplorer = normalizeApiExplorerConfig(config.apiExplorer);
|
|
734
|
+
if (result.openApiSpec.disabled) {
|
|
735
|
+
// Disable apiExplorer if the OpenAPI spec endpoint is disabled
|
|
736
|
+
result.apiExplorer.disabled = true;
|
|
737
|
+
}
|
|
738
|
+
return result;
|
|
739
|
+
}
|
|
740
|
+
function normalizeApiExplorerConfig(input) {
|
|
741
|
+
var _a, _b, _c;
|
|
742
|
+
const config = input !== null && input !== void 0 ? input : {};
|
|
743
|
+
const url = (_a = config.url) !== null && _a !== void 0 ? _a : 'https://explorer.loopback.io';
|
|
744
|
+
config.httpUrl = (_c = (_b = config.httpUrl) !== null && _b !== void 0 ? _b : config.url) !== null && _c !== void 0 ? _c : 'http://explorer.loopback.io';
|
|
745
|
+
config.url = url;
|
|
746
|
+
return config;
|
|
747
|
+
}
|
|
748
|
+
//# sourceMappingURL=rest.server.js.map
|