@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,53 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2018,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/rest
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {Context, InvocationSource} from '@loopback/context';
|
|
7
|
+
import {OperationObject} from '@loopback/openapi-v3';
|
|
8
|
+
import {OperationArgs, OperationRetval} from '../types';
|
|
9
|
+
import {RouteEntry} from './route-entry';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Base implementation of RouteEntry
|
|
13
|
+
*/
|
|
14
|
+
export abstract class BaseRoute implements RouteEntry {
|
|
15
|
+
public readonly verb: string;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Construct a new route
|
|
19
|
+
* @param verb - http verb
|
|
20
|
+
* @param path - http request path pattern
|
|
21
|
+
* @param spec - OpenAPI operation spec
|
|
22
|
+
*/
|
|
23
|
+
constructor(
|
|
24
|
+
verb: string,
|
|
25
|
+
public readonly path: string,
|
|
26
|
+
public readonly spec: OperationObject,
|
|
27
|
+
) {
|
|
28
|
+
this.verb = verb.toLowerCase();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
abstract updateBindings(requestContext: Context): void;
|
|
32
|
+
|
|
33
|
+
abstract invokeHandler(
|
|
34
|
+
requestContext: Context,
|
|
35
|
+
args: OperationArgs,
|
|
36
|
+
): Promise<OperationRetval>;
|
|
37
|
+
|
|
38
|
+
describe(): string {
|
|
39
|
+
return `"${this.verb} ${this.path}"`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
toString() {
|
|
43
|
+
return `${this.constructor.name} - ${this.verb} ${this.path}`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class RouteSource implements InvocationSource<RouteEntry> {
|
|
48
|
+
type = 'route';
|
|
49
|
+
constructor(readonly value: RouteEntry) {}
|
|
50
|
+
toString() {
|
|
51
|
+
return `${this.value.verb} ${this.value.path}`;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2018,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/rest
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
BindingScope,
|
|
8
|
+
Constructor,
|
|
9
|
+
Context,
|
|
10
|
+
instantiateClass,
|
|
11
|
+
invokeMethod,
|
|
12
|
+
ValueOrPromise,
|
|
13
|
+
} from '@loopback/context';
|
|
14
|
+
import {CoreBindings} from '@loopback/core';
|
|
15
|
+
import {ControllerSpec, OperationObject} from '@loopback/openapi-v3';
|
|
16
|
+
import assert from 'assert';
|
|
17
|
+
import debugFactory from 'debug';
|
|
18
|
+
import HttpErrors from 'http-errors';
|
|
19
|
+
import {inspect} from 'util';
|
|
20
|
+
import {RestBindings} from '../keys';
|
|
21
|
+
import {OperationArgs, OperationRetval} from '../types';
|
|
22
|
+
import {BaseRoute, RouteSource} from './base-route';
|
|
23
|
+
|
|
24
|
+
const debug = debugFactory('loopback:rest:controller-route');
|
|
25
|
+
/*
|
|
26
|
+
* A controller instance with open properties/methods
|
|
27
|
+
*/
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
+
export type ControllerInstance = {[name: string]: any} & object;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A factory function to create controller instances synchronously or
|
|
33
|
+
* asynchronously
|
|
34
|
+
*/
|
|
35
|
+
export type ControllerFactory<T extends ControllerInstance> = (
|
|
36
|
+
ctx: Context,
|
|
37
|
+
) => ValueOrPromise<T>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Controller class
|
|
41
|
+
*/
|
|
42
|
+
export type ControllerClass<T extends ControllerInstance> = Constructor<T>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* A route backed by a controller
|
|
46
|
+
*/
|
|
47
|
+
export class ControllerRoute<T> extends BaseRoute {
|
|
48
|
+
protected readonly _controllerCtor: ControllerClass<T>;
|
|
49
|
+
protected readonly _controllerName: string;
|
|
50
|
+
protected readonly _methodName: string;
|
|
51
|
+
protected readonly _controllerFactory: ControllerFactory<T>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Construct a controller based route
|
|
55
|
+
* @param verb - http verb
|
|
56
|
+
* @param path - http request path
|
|
57
|
+
* @param spec - OpenAPI operation spec
|
|
58
|
+
* @param controllerCtor - Controller class
|
|
59
|
+
* @param controllerFactory - A factory function to create a controller instance
|
|
60
|
+
* @param methodName - Controller method name, default to `x-operation-name`
|
|
61
|
+
*/
|
|
62
|
+
constructor(
|
|
63
|
+
verb: string,
|
|
64
|
+
path: string,
|
|
65
|
+
spec: OperationObject,
|
|
66
|
+
controllerCtor: ControllerClass<T>,
|
|
67
|
+
controllerFactory?: ControllerFactory<T>,
|
|
68
|
+
methodName?: string,
|
|
69
|
+
) {
|
|
70
|
+
const controllerName = spec['x-controller-name'] || controllerCtor.name;
|
|
71
|
+
methodName = methodName ?? spec['x-operation-name'];
|
|
72
|
+
|
|
73
|
+
if (!methodName) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
'methodName must be provided either via the ControllerRoute argument ' +
|
|
76
|
+
'or via "x-operation-name" extension field in OpenAPI spec. ' +
|
|
77
|
+
`Operation: "${verb} ${path}" ` +
|
|
78
|
+
`Controller: ${controllerName}.`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
super(
|
|
83
|
+
verb,
|
|
84
|
+
path,
|
|
85
|
+
// Add x-controller-name and x-operation-name if not present
|
|
86
|
+
Object.assign(
|
|
87
|
+
{
|
|
88
|
+
'x-controller-name': controllerName,
|
|
89
|
+
'x-operation-name': methodName,
|
|
90
|
+
tags: [controllerName],
|
|
91
|
+
},
|
|
92
|
+
spec,
|
|
93
|
+
),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
this._controllerFactory =
|
|
97
|
+
controllerFactory ?? createControllerFactoryForClass(controllerCtor);
|
|
98
|
+
this._controllerCtor = controllerCtor;
|
|
99
|
+
this._controllerName = controllerName || controllerCtor.name;
|
|
100
|
+
this._methodName = methodName;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
describe(): string {
|
|
104
|
+
return `${this._controllerName}.${this._methodName}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
updateBindings(requestContext: Context) {
|
|
108
|
+
/*
|
|
109
|
+
* Bind current controller to the request context in `SINGLETON` scope.
|
|
110
|
+
* Within the same request, we always get the same instance of the
|
|
111
|
+
* current controller when `requestContext.get(CoreBindings.CONTROLLER_CURRENT)`
|
|
112
|
+
* is invoked.
|
|
113
|
+
*
|
|
114
|
+
* Please note the controller class itself can be bound to other scopes,
|
|
115
|
+
* such as SINGLETON or TRANSIENT (default) in the application or server
|
|
116
|
+
* context.
|
|
117
|
+
*
|
|
118
|
+
* - SINGLETON: all requests share the same instance of a given controller
|
|
119
|
+
* - TRANSIENT: each request has its own instance of a given controller
|
|
120
|
+
*/
|
|
121
|
+
requestContext
|
|
122
|
+
.bind(CoreBindings.CONTROLLER_CURRENT)
|
|
123
|
+
.toDynamicValue(() => this._controllerFactory(requestContext))
|
|
124
|
+
.inScope(BindingScope.SINGLETON);
|
|
125
|
+
requestContext.bind(CoreBindings.CONTROLLER_CLASS).to(this._controllerCtor);
|
|
126
|
+
requestContext
|
|
127
|
+
.bind(CoreBindings.CONTROLLER_METHOD_NAME)
|
|
128
|
+
.to(this._methodName);
|
|
129
|
+
requestContext.bind(RestBindings.OPERATION_SPEC_CURRENT).to(this.spec);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async invokeHandler(
|
|
133
|
+
requestContext: Context,
|
|
134
|
+
args: OperationArgs,
|
|
135
|
+
): Promise<OperationRetval> {
|
|
136
|
+
const controller = await requestContext.get<ControllerInstance>(
|
|
137
|
+
'controller.current',
|
|
138
|
+
);
|
|
139
|
+
if (typeof controller[this._methodName] !== 'function') {
|
|
140
|
+
throw new HttpErrors.NotFound(
|
|
141
|
+
`Controller method not found: ${this.describe()}`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
// Invoke the method with dependency injection
|
|
145
|
+
return invokeMethod(controller, this._methodName, requestContext, args, {
|
|
146
|
+
source: new RouteSource(this),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Create a controller factory function for a given binding key
|
|
153
|
+
* @param key - Binding key
|
|
154
|
+
*/
|
|
155
|
+
export function createControllerFactoryForBinding<T>(
|
|
156
|
+
key: string,
|
|
157
|
+
): ControllerFactory<T> {
|
|
158
|
+
return ctx => ctx.get<T>(key);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Create a controller factory function for a given class
|
|
163
|
+
* @param controllerCtor - Controller class
|
|
164
|
+
*/
|
|
165
|
+
export function createControllerFactoryForClass<T>(
|
|
166
|
+
controllerCtor: ControllerClass<T>,
|
|
167
|
+
): ControllerFactory<T> {
|
|
168
|
+
return async ctx => {
|
|
169
|
+
// By default, we get an instance of the controller from the context
|
|
170
|
+
// using `controllers.<controllerName>` as the key
|
|
171
|
+
let inst = await ctx.get<T>(`controllers.${controllerCtor.name}`, {
|
|
172
|
+
optional: true,
|
|
173
|
+
});
|
|
174
|
+
if (inst === undefined) {
|
|
175
|
+
inst = await instantiateClass<T>(controllerCtor, ctx);
|
|
176
|
+
}
|
|
177
|
+
return inst;
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Create a controller factory function for a given instance
|
|
183
|
+
* @param controllerCtor - Controller instance
|
|
184
|
+
*/
|
|
185
|
+
export function createControllerFactoryForInstance<T>(
|
|
186
|
+
controllerInst: T,
|
|
187
|
+
): ControllerFactory<T> {
|
|
188
|
+
return ctx => controllerInst;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Create routes for a controller with the given spec
|
|
193
|
+
* @param spec - Controller spec
|
|
194
|
+
* @param controllerCtor - Controller class
|
|
195
|
+
* @param controllerFactory - Controller factory
|
|
196
|
+
*/
|
|
197
|
+
export function createRoutesForController<T>(
|
|
198
|
+
spec: ControllerSpec,
|
|
199
|
+
controllerCtor: ControllerClass<T>,
|
|
200
|
+
controllerFactory?: ControllerFactory<T>,
|
|
201
|
+
) {
|
|
202
|
+
const routes: ControllerRoute<T>[] = [];
|
|
203
|
+
assert(
|
|
204
|
+
typeof spec === 'object' && !!spec,
|
|
205
|
+
'API specification must be a non-null object',
|
|
206
|
+
);
|
|
207
|
+
if (!spec.paths || !Object.keys(spec.paths).length) {
|
|
208
|
+
return routes;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
debug(
|
|
212
|
+
'Creating route for controller with API %s',
|
|
213
|
+
inspect(spec, {depth: null}),
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const basePath = spec.basePath ?? '/';
|
|
217
|
+
for (const p in spec.paths) {
|
|
218
|
+
for (const verb in spec.paths[p]) {
|
|
219
|
+
const opSpec: OperationObject = spec.paths[p][verb];
|
|
220
|
+
const fullPath = joinPath(basePath, p);
|
|
221
|
+
const route = new ControllerRoute(
|
|
222
|
+
verb,
|
|
223
|
+
fullPath,
|
|
224
|
+
opSpec,
|
|
225
|
+
controllerCtor,
|
|
226
|
+
controllerFactory,
|
|
227
|
+
);
|
|
228
|
+
routes.push(route);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return routes;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function joinPath(basePath: string, path: string) {
|
|
235
|
+
const fullPath = [basePath, path]
|
|
236
|
+
.join('/') // Join by /
|
|
237
|
+
.replace(/(\/){2,}/g, '/') // Remove extra /
|
|
238
|
+
.replace(/\/$/, '') // Remove trailing /
|
|
239
|
+
.replace(/^(\/)?/, '/'); // Add leading /
|
|
240
|
+
return fullPath;
|
|
241
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/rest
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {Context} from '@loopback/context';
|
|
7
|
+
import {
|
|
8
|
+
executeExpressRequestHandler,
|
|
9
|
+
ExpressRequestHandler,
|
|
10
|
+
Request,
|
|
11
|
+
} from '@loopback/express';
|
|
12
|
+
import {
|
|
13
|
+
OpenApiSpec,
|
|
14
|
+
OperationObject,
|
|
15
|
+
SchemasObject,
|
|
16
|
+
} from '@loopback/openapi-v3';
|
|
17
|
+
import express from 'express';
|
|
18
|
+
import {PathParams} from 'express-serve-static-core';
|
|
19
|
+
import HttpErrors from 'http-errors';
|
|
20
|
+
import {ServeStaticOptions} from 'serve-static';
|
|
21
|
+
import {RequestContext} from '../request-context';
|
|
22
|
+
import {OperationArgs, OperationRetval, PathParameterValues} from '../types';
|
|
23
|
+
import {ResolvedRoute, RouteEntry} from './route-entry';
|
|
24
|
+
import {assignRouterSpec, RouterSpec} from './router-spec';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A registry of external, Express-style routes. These routes are invoked
|
|
28
|
+
* _after_ no LB4 route (controller or handler based) matched the incoming
|
|
29
|
+
* request.
|
|
30
|
+
*
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
export class ExternalExpressRoutes {
|
|
34
|
+
protected _externalRoutes: express.Router = express.Router();
|
|
35
|
+
protected _staticRoutes: express.Router = express.Router();
|
|
36
|
+
protected _specForExternalRoutes: RouterSpec = {paths: {}};
|
|
37
|
+
|
|
38
|
+
get routerSpec(): RouterSpec {
|
|
39
|
+
return this._specForExternalRoutes;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public registerAssets(
|
|
43
|
+
path: PathParams,
|
|
44
|
+
rootDir: string,
|
|
45
|
+
options?: ServeStaticOptions,
|
|
46
|
+
) {
|
|
47
|
+
this._staticRoutes.use(path, express.static(rootDir, options));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public mountRouter(
|
|
51
|
+
basePath: string,
|
|
52
|
+
router: ExpressRequestHandler,
|
|
53
|
+
spec: RouterSpec = {paths: {}},
|
|
54
|
+
) {
|
|
55
|
+
this._externalRoutes.use(basePath, router);
|
|
56
|
+
|
|
57
|
+
spec = rebaseOpenApiSpec(spec, basePath);
|
|
58
|
+
assignRouterSpec(this._specForExternalRoutes, spec);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
find(request: Request): ResolvedRoute {
|
|
62
|
+
return new ExternalRoute(
|
|
63
|
+
this._externalRoutes,
|
|
64
|
+
this._staticRoutes,
|
|
65
|
+
request.method,
|
|
66
|
+
request.url,
|
|
67
|
+
{
|
|
68
|
+
description: 'External route or a static asset',
|
|
69
|
+
'x-visibility': 'undocumented',
|
|
70
|
+
responses: {},
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
class ExternalRoute implements RouteEntry, ResolvedRoute {
|
|
77
|
+
// ResolvedRoute API
|
|
78
|
+
readonly pathParams: PathParameterValues = [];
|
|
79
|
+
readonly schemas: SchemasObject = {};
|
|
80
|
+
|
|
81
|
+
constructor(
|
|
82
|
+
private readonly _externalRouter: express.Router,
|
|
83
|
+
private readonly _staticAssets: express.Router,
|
|
84
|
+
public readonly verb: string,
|
|
85
|
+
public readonly path: string,
|
|
86
|
+
public readonly spec: OperationObject,
|
|
87
|
+
) {}
|
|
88
|
+
|
|
89
|
+
updateBindings(requestContext: Context): void {
|
|
90
|
+
// no-op
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async invokeHandler(
|
|
94
|
+
{request, response}: RequestContext,
|
|
95
|
+
args: OperationArgs,
|
|
96
|
+
): Promise<OperationRetval> {
|
|
97
|
+
let handled = await executeExpressRequestHandler(
|
|
98
|
+
this._externalRouter,
|
|
99
|
+
request,
|
|
100
|
+
response,
|
|
101
|
+
);
|
|
102
|
+
if (handled) return;
|
|
103
|
+
|
|
104
|
+
handled = await executeExpressRequestHandler(
|
|
105
|
+
this._staticAssets,
|
|
106
|
+
request,
|
|
107
|
+
response,
|
|
108
|
+
);
|
|
109
|
+
if (handled) return;
|
|
110
|
+
|
|
111
|
+
// Express router called next, which means no route was matched
|
|
112
|
+
throw new HttpErrors.NotFound(
|
|
113
|
+
`Endpoint "${request.method} ${request.path}" not found.`,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
describe(): string {
|
|
118
|
+
// TODO(bajtos) provide better description for Express routes with spec
|
|
119
|
+
return `External Express route "${this.verb} ${this.path}"`;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function rebaseOpenApiSpec<T extends Partial<OpenApiSpec>>(
|
|
124
|
+
spec: T,
|
|
125
|
+
basePath: string,
|
|
126
|
+
): T {
|
|
127
|
+
if (!spec.paths) return spec;
|
|
128
|
+
if (!basePath || basePath === '/') return spec;
|
|
129
|
+
|
|
130
|
+
const localPaths = spec.paths;
|
|
131
|
+
// Don't modify the spec object provided to us.
|
|
132
|
+
spec = Object.assign({}, spec);
|
|
133
|
+
spec.paths = {};
|
|
134
|
+
for (const url in localPaths) {
|
|
135
|
+
spec.paths[`${basePath}${url}`] = localPaths[url];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return spec;
|
|
139
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2018,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/rest
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {Context, invokeMethodWithInterceptors} from '@loopback/context';
|
|
7
|
+
import {OperationObject} from '@loopback/openapi-v3';
|
|
8
|
+
import {RestBindings} from '../keys';
|
|
9
|
+
import {OperationArgs, OperationRetval} from '../types';
|
|
10
|
+
import {BaseRoute, RouteSource} from './base-route';
|
|
11
|
+
|
|
12
|
+
export class Route extends BaseRoute {
|
|
13
|
+
constructor(
|
|
14
|
+
verb: string,
|
|
15
|
+
path: string,
|
|
16
|
+
public readonly spec: OperationObject,
|
|
17
|
+
protected readonly _handler: Function,
|
|
18
|
+
) {
|
|
19
|
+
super(verb, path, spec);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe(): string {
|
|
23
|
+
return this._handler.name || super.describe();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
updateBindings(requestContext: Context) {
|
|
27
|
+
requestContext.bind(RestBindings.OPERATION_SPEC_CURRENT).to(this.spec);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async invokeHandler(
|
|
31
|
+
requestContext: Context,
|
|
32
|
+
args: OperationArgs,
|
|
33
|
+
): Promise<OperationRetval> {
|
|
34
|
+
// Use `invokeMethodWithInterceptors` to invoke the handler function so
|
|
35
|
+
// that global interceptors are applied
|
|
36
|
+
return invokeMethodWithInterceptors(
|
|
37
|
+
requestContext,
|
|
38
|
+
this,
|
|
39
|
+
'_handler',
|
|
40
|
+
args,
|
|
41
|
+
{source: new RouteSource(this)},
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2018,2019. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/rest
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
// routes
|
|
7
|
+
export * from './route-entry';
|
|
8
|
+
export * from './base-route';
|
|
9
|
+
export * from './controller-route';
|
|
10
|
+
export * from './handler-route';
|
|
11
|
+
export * from './external-express-routes';
|
|
12
|
+
export * from './redirect-route';
|
|
13
|
+
|
|
14
|
+
// routers
|
|
15
|
+
export * from './rest-router';
|
|
16
|
+
export * from './trie-router';
|
|
17
|
+
export * from './regexp-router';
|
|
18
|
+
|
|
19
|
+
// helpers
|
|
20
|
+
export * from './routing-table';
|
|
21
|
+
export * from './route-sort';
|
|
22
|
+
export * from './openapi-path';
|
|
23
|
+
export * from './trie';
|
|
24
|
+
export * from './router-spec';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2018,2019. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/rest
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {parse} from 'path-to-regexp';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* OpenAPI spec 3.x does not specify the valid forms of path templates.
|
|
10
|
+
*
|
|
11
|
+
* Other ones such as [URI Template](https://tools.ietf.org/html/rfc6570#section-2.3)
|
|
12
|
+
* or [path-to-regexp](https://github.com/pillarjs/path-to-regexp#named-parameters)
|
|
13
|
+
* allows `[A-Za-z0-9_]`
|
|
14
|
+
*/
|
|
15
|
+
const POSSIBLE_VARNAME_PATTERN = /\{([^\}]+)\}/g;
|
|
16
|
+
const VALID_VARNAME_PATTERN = /^[A-Za-z0-9_]+$/;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Validate the path to be compatible with OpenAPI path template. No parameter
|
|
20
|
+
* modifier, custom pattern, or unnamed parameter is allowed.
|
|
21
|
+
*/
|
|
22
|
+
export function validateApiPath(path = '/') {
|
|
23
|
+
const tokens = parse(path);
|
|
24
|
+
for (const token of tokens) {
|
|
25
|
+
if (typeof token === 'string') continue;
|
|
26
|
+
if (typeof token === 'object') {
|
|
27
|
+
const name = token.name;
|
|
28
|
+
if (typeof name === 'string' && name !== '') {
|
|
29
|
+
throw new Error(
|
|
30
|
+
`Invalid path template: '${path}'. Please use {${name}} instead of ':${name}'`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
if (typeof name === 'number') {
|
|
34
|
+
throw new Error(`Unnamed parameter is not allowed in path '${path}'`);
|
|
35
|
+
}
|
|
36
|
+
const valid = token.prefix.match(VALID_VARNAME_PATTERN);
|
|
37
|
+
if (!valid) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`Invalid parameter name '${token.prefix}' found in path '${path}'`,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
if (['?', '+', '*'].includes(token.modifier)) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`Parameter modifier '{${token.prefix}}${token.modifier}' is not allowed in path '${path}`,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return path;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get all path variables. For example, `/root/{foo}/bar` => `['foo']`
|
|
54
|
+
*/
|
|
55
|
+
export function getPathVariables(path: string) {
|
|
56
|
+
return path.match(POSSIBLE_VARNAME_PATTERN);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Convert an OpenAPI path to Express (path-to-regexp) style
|
|
61
|
+
* @param path - OpenAPI path with optional variables as `{var}`
|
|
62
|
+
*/
|
|
63
|
+
export function toExpressPath(path: string) {
|
|
64
|
+
// Convert `.` to `\\.` so that path-to-regexp will treat it as the plain
|
|
65
|
+
// `.` character
|
|
66
|
+
return path.replace(POSSIBLE_VARNAME_PATTERN, '{:$1}').replace('.', '\\.');
|
|
67
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/rest
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {OperationObject, SchemasObject} from '@loopback/openapi-v3';
|
|
7
|
+
import {ResolvedRoute, RouteEntry} from '.';
|
|
8
|
+
import {RequestContext} from '../request-context';
|
|
9
|
+
import {OperationArgs, OperationRetval, PathParameterValues} from '../types';
|
|
10
|
+
|
|
11
|
+
export class RedirectRoute implements RouteEntry, ResolvedRoute {
|
|
12
|
+
// ResolvedRoute API
|
|
13
|
+
readonly pathParams: PathParameterValues = [];
|
|
14
|
+
readonly schemas: SchemasObject = {};
|
|
15
|
+
|
|
16
|
+
// RouteEntry implementation
|
|
17
|
+
readonly verb: string = 'get';
|
|
18
|
+
readonly path: string;
|
|
19
|
+
readonly spec: OperationObject = {
|
|
20
|
+
description: 'LoopBack Redirect route',
|
|
21
|
+
'x-visibility': 'undocumented',
|
|
22
|
+
responses: {},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
constructor(
|
|
26
|
+
public readonly sourcePath: string,
|
|
27
|
+
public readonly targetLocation: string,
|
|
28
|
+
public readonly statusCode: number = 303,
|
|
29
|
+
) {
|
|
30
|
+
this.path = sourcePath;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async invokeHandler(
|
|
34
|
+
{response}: RequestContext,
|
|
35
|
+
args: OperationArgs,
|
|
36
|
+
): Promise<OperationRetval> {
|
|
37
|
+
response.redirect(this.statusCode, this.targetLocation);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
updateBindings(requestContext: RequestContext) {
|
|
41
|
+
// no-op
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe(): string {
|
|
45
|
+
return `RedirectRoute from "${this.sourcePath}" to "${this.targetLocation}"`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* type guard type checker for this class
|
|
50
|
+
* @param obj
|
|
51
|
+
*/
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
+
static isRedirectRoute(obj: any): obj is RedirectRoute {
|
|
54
|
+
const redirectOptions = obj as RedirectRoute;
|
|
55
|
+
if (
|
|
56
|
+
redirectOptions?.targetLocation &&
|
|
57
|
+
redirectOptions.spec &&
|
|
58
|
+
redirectOptions.spec.description === 'LoopBack Redirect route'
|
|
59
|
+
) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|