@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,104 @@
|
|
|
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 {inject} from '@loopback/context';
|
|
7
|
+
import {inspect} from 'util';
|
|
8
|
+
import {RestBindings} from '../keys';
|
|
9
|
+
import {PathParameterValues} from '../types';
|
|
10
|
+
import {toExpressPath} from './openapi-path';
|
|
11
|
+
import {RestRouterOptions} from './rest-router';
|
|
12
|
+
import {createResolvedRoute, ResolvedRoute, RouteEntry} from './route-entry';
|
|
13
|
+
import {compareRoute} from './route-sort';
|
|
14
|
+
import {BaseRouter} from './router-base';
|
|
15
|
+
import {pathToRegexp, Key} from 'path-to-regexp';
|
|
16
|
+
|
|
17
|
+
const debug = require('debug')('loopback:rest:router:regexp');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Route entry with path-to-regexp
|
|
21
|
+
*/
|
|
22
|
+
interface RegExpRouteEntry extends RouteEntry {
|
|
23
|
+
regexp: RegExp;
|
|
24
|
+
keys: Key[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Router implementation based on regexp matching
|
|
29
|
+
*/
|
|
30
|
+
export class RegExpRouter extends BaseRouter {
|
|
31
|
+
private routes: RegExpRouteEntry[] = [];
|
|
32
|
+
|
|
33
|
+
// Sort the routes based on their paths and variables
|
|
34
|
+
private _sorted: boolean;
|
|
35
|
+
private _sort() {
|
|
36
|
+
if (!this._sorted) {
|
|
37
|
+
this.routes.sort(compareRoute);
|
|
38
|
+
this._sorted = true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
constructor(
|
|
43
|
+
@inject(RestBindings.ROUTER_OPTIONS, {optional: true})
|
|
44
|
+
options?: RestRouterOptions,
|
|
45
|
+
) {
|
|
46
|
+
super(options);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
protected addRouteWithPathVars(route: RouteEntry) {
|
|
50
|
+
const path = toExpressPath(route.path);
|
|
51
|
+
const keys: Key[] = [];
|
|
52
|
+
const regexp = pathToRegexp(path, keys, {
|
|
53
|
+
strict: this.options.strict,
|
|
54
|
+
end: true,
|
|
55
|
+
});
|
|
56
|
+
const entry: RegExpRouteEntry = Object.assign(route, {keys, regexp});
|
|
57
|
+
this.routes.push(entry);
|
|
58
|
+
this._sorted = false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
protected findRouteWithPathVars(
|
|
62
|
+
verb: string,
|
|
63
|
+
path: string,
|
|
64
|
+
): ResolvedRoute | undefined {
|
|
65
|
+
this._sort();
|
|
66
|
+
for (const r of this.routes) {
|
|
67
|
+
debug('trying endpoint %s', inspect(r, {depth: 5}));
|
|
68
|
+
if (r.verb !== verb.toLowerCase()) {
|
|
69
|
+
debug(' -> verb mismatch');
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const match = r.regexp.exec(path);
|
|
74
|
+
if (!match) {
|
|
75
|
+
debug(' -> path mismatch');
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const pathParams = this._buildPathParams(r, match);
|
|
80
|
+
debug(' -> found with params: %j', pathParams);
|
|
81
|
+
|
|
82
|
+
return createResolvedRoute(r, pathParams);
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
protected listRoutesWithPathVars() {
|
|
88
|
+
this._sort();
|
|
89
|
+
return this.routes;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private _buildPathParams(
|
|
93
|
+
route: RegExpRouteEntry,
|
|
94
|
+
pathMatch: RegExpExecArray,
|
|
95
|
+
): PathParameterValues {
|
|
96
|
+
const pathParams: PathParameterValues = {};
|
|
97
|
+
for (const ix in route.keys) {
|
|
98
|
+
const key = route.keys[ix];
|
|
99
|
+
const matchIndex = +ix + 1;
|
|
100
|
+
pathParams[key.name] = pathMatch[matchIndex];
|
|
101
|
+
}
|
|
102
|
+
return pathParams;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
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 {Request} from '../types';
|
|
7
|
+
import {ResolvedRoute, RouteEntry} from './route-entry';
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
/**
|
|
11
|
+
* Interface for router implementation
|
|
12
|
+
*/
|
|
13
|
+
export interface RestRouter {
|
|
14
|
+
/**
|
|
15
|
+
* Add a route to the router
|
|
16
|
+
* @param route - A route entry
|
|
17
|
+
*/
|
|
18
|
+
add(route: RouteEntry): void;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Find a matching route for the given http request
|
|
22
|
+
* @param request - Http request
|
|
23
|
+
* @returns The resolved route, if not found, `undefined` is returned
|
|
24
|
+
*/
|
|
25
|
+
find(request: Request): ResolvedRoute | undefined;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* List all routes
|
|
29
|
+
*/
|
|
30
|
+
list(): RouteEntry[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type RestRouterOptions = {
|
|
34
|
+
/**
|
|
35
|
+
* When `true` it uses trailing slash to match. (default: `false`)
|
|
36
|
+
*
|
|
37
|
+
* 1. `strict` is true:
|
|
38
|
+
* - request `/orders` matches route `/orders` but not `/orders/`
|
|
39
|
+
* - request `/orders/` matches route `/orders/` but not `/orders`
|
|
40
|
+
*
|
|
41
|
+
* 2. `strict` is false (default)
|
|
42
|
+
* - request `/orders` matches route `/orders` first and falls back to `/orders/`
|
|
43
|
+
* - request `/orders/` matches route `/orders/` first and falls back to `/orders`
|
|
44
|
+
*
|
|
45
|
+
* See `strict routing` at http://expressjs.com/en/4x/api.html#app
|
|
46
|
+
*/
|
|
47
|
+
strict?: boolean;
|
|
48
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
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} from '@loopback/context';
|
|
7
|
+
import {OperationObject, SchemasObject} from '@loopback/openapi-v3';
|
|
8
|
+
import {OperationArgs, OperationRetval, PathParameterValues} from '../types';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* An entry in the routing table
|
|
12
|
+
*/
|
|
13
|
+
export interface RouteEntry {
|
|
14
|
+
/**
|
|
15
|
+
* http verb
|
|
16
|
+
*/
|
|
17
|
+
readonly verb: string;
|
|
18
|
+
/**
|
|
19
|
+
* http path
|
|
20
|
+
*/
|
|
21
|
+
readonly path: string;
|
|
22
|
+
/**
|
|
23
|
+
* OpenAPI operation spec
|
|
24
|
+
*/
|
|
25
|
+
readonly spec: OperationObject;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Update bindings for the request context
|
|
29
|
+
* @param requestContext
|
|
30
|
+
*/
|
|
31
|
+
updateBindings(requestContext: Context): void;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A handler to invoke the resolved controller method
|
|
35
|
+
* @param requestContext
|
|
36
|
+
* @param args
|
|
37
|
+
*/
|
|
38
|
+
invokeHandler(
|
|
39
|
+
requestContext: Context,
|
|
40
|
+
args: OperationArgs,
|
|
41
|
+
): Promise<OperationRetval>;
|
|
42
|
+
|
|
43
|
+
describe(): string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* A route with path parameters resolved
|
|
48
|
+
*/
|
|
49
|
+
export interface ResolvedRoute extends RouteEntry {
|
|
50
|
+
readonly pathParams: PathParameterValues;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Server/application wide schemas shared by multiple routes,
|
|
54
|
+
* e.g. model schemas. This is a temporary workaround for
|
|
55
|
+
* missing support for $ref references, see
|
|
56
|
+
* https://github.com/strongloop/loopback-next/issues/435
|
|
57
|
+
*/
|
|
58
|
+
readonly schemas: SchemasObject;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function createResolvedRoute(
|
|
62
|
+
route: RouteEntry,
|
|
63
|
+
pathParams: PathParameterValues,
|
|
64
|
+
): ResolvedRoute {
|
|
65
|
+
return Object.create(route, {
|
|
66
|
+
pathParams: {
|
|
67
|
+
writable: false,
|
|
68
|
+
value: pathParams,
|
|
69
|
+
},
|
|
70
|
+
schemas: {
|
|
71
|
+
value: {},
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
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 {parse, Token} from 'path-to-regexp';
|
|
7
|
+
import {RouteEntry} from './route-entry';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Sorting order for http verbs
|
|
11
|
+
*/
|
|
12
|
+
const HTTP_VERBS: {[name: string]: number} = {
|
|
13
|
+
post: 1,
|
|
14
|
+
put: 2,
|
|
15
|
+
patch: 3,
|
|
16
|
+
get: 4,
|
|
17
|
+
head: 5,
|
|
18
|
+
delete: 6,
|
|
19
|
+
options: 7,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Compare two routes by verb/path for sorting
|
|
24
|
+
* @param route1 - First route entry
|
|
25
|
+
* @param route2 - Second route entry
|
|
26
|
+
*/
|
|
27
|
+
export function compareRoute(
|
|
28
|
+
route1: Pick<RouteEntry, 'verb' | 'path'>,
|
|
29
|
+
route2: Pick<RouteEntry, 'verb' | 'path'>,
|
|
30
|
+
): number {
|
|
31
|
+
// First check the path tokens
|
|
32
|
+
const path1 = route1.path.replace(/{([^}]*)}(\/|$)/g, ':$1$2');
|
|
33
|
+
const path2 = route2.path.replace(/{([^}]*)}(\/|$)/g, ':$1$2');
|
|
34
|
+
const tokensForPath1: Token[] = toTokens(path1);
|
|
35
|
+
const tokensForPath2: Token[] = toTokens(path2);
|
|
36
|
+
|
|
37
|
+
const length =
|
|
38
|
+
tokensForPath1.length > tokensForPath2.length
|
|
39
|
+
? tokensForPath1.length
|
|
40
|
+
: tokensForPath2.length;
|
|
41
|
+
|
|
42
|
+
for (let i = 0; i < length; i++) {
|
|
43
|
+
const token1 = tokensForPath1[i];
|
|
44
|
+
const token2 = tokensForPath2[i];
|
|
45
|
+
if (token1 === token2) continue;
|
|
46
|
+
if (token1 === undefined) return 1;
|
|
47
|
+
if (token2 === undefined) return -1;
|
|
48
|
+
if (token1 < token2) return -1;
|
|
49
|
+
if (token1 > token2) return 1;
|
|
50
|
+
}
|
|
51
|
+
// Then check verb
|
|
52
|
+
const verb1 = HTTP_VERBS[route1.verb.toLowerCase()] || HTTP_VERBS.get;
|
|
53
|
+
const verb2 = HTTP_VERBS[route2.verb.toLowerCase()] || HTTP_VERBS.get;
|
|
54
|
+
if (verb1 !== verb2) return verb1 - verb2;
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
*
|
|
60
|
+
* @param path - Parse a path template into tokens
|
|
61
|
+
*/
|
|
62
|
+
function toTokens(path: string) {
|
|
63
|
+
const tokens: Token[] = [];
|
|
64
|
+
parse(path).forEach(p => {
|
|
65
|
+
if (typeof p === 'string') {
|
|
66
|
+
// The string can be /orders/count
|
|
67
|
+
tokens.push(...p.split('/').filter(Boolean));
|
|
68
|
+
} else {
|
|
69
|
+
// Use `{}` for wildcard as they are larger than any other ascii chars
|
|
70
|
+
tokens.push(`{}`);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
return tokens;
|
|
74
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
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 {Request} from '../types';
|
|
7
|
+
import {getPathVariables} from './openapi-path';
|
|
8
|
+
import {createResolvedRoute, ResolvedRoute, RouteEntry} from './route-entry';
|
|
9
|
+
import {compareRoute} from './route-sort';
|
|
10
|
+
import {RestRouter, RestRouterOptions} from './rest-router';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Base router implementation that only handles path without variables
|
|
14
|
+
*/
|
|
15
|
+
export abstract class BaseRouter implements RestRouter {
|
|
16
|
+
/**
|
|
17
|
+
* A map to optimize matching for routes without variables in the path
|
|
18
|
+
*/
|
|
19
|
+
protected routesWithoutPathVars: {[key: string]: RouteEntry} = {};
|
|
20
|
+
|
|
21
|
+
constructor(protected options: RestRouterOptions = {strict: false}) {}
|
|
22
|
+
|
|
23
|
+
protected getKeyForRoute(route: RouteEntry) {
|
|
24
|
+
return this.getKey(route.verb, route.path);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
add(route: RouteEntry) {
|
|
28
|
+
if (!getPathVariables(route.path)) {
|
|
29
|
+
const key = this.getKeyForRoute(route);
|
|
30
|
+
this.routesWithoutPathVars[key] = route;
|
|
31
|
+
} else {
|
|
32
|
+
this.addRouteWithPathVars(route);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
protected getKeyForRequest(request: Request) {
|
|
37
|
+
return this.getKey(request.method, request.path);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
find(request: Request) {
|
|
41
|
+
if (this.options.strict) {
|
|
42
|
+
return this.findRoute(request.method, request.path);
|
|
43
|
+
}
|
|
44
|
+
// Non-strict mode
|
|
45
|
+
let path = request.path;
|
|
46
|
+
// First try the exact match
|
|
47
|
+
const route = this.findRoute(request.method, path);
|
|
48
|
+
if (route || path === '/') return route;
|
|
49
|
+
if (path.endsWith('/')) {
|
|
50
|
+
// Fall back to the path without trailing slash
|
|
51
|
+
path = path.substring(0, path.length - 1);
|
|
52
|
+
} else {
|
|
53
|
+
// Fall back to the path with trailing slash
|
|
54
|
+
path = path + '/';
|
|
55
|
+
}
|
|
56
|
+
return this.findRoute(request.method, path);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private findRoute(verb: string, path: string) {
|
|
60
|
+
const key = this.getKey(verb, path);
|
|
61
|
+
const route = this.routesWithoutPathVars[key];
|
|
62
|
+
if (route) return createResolvedRoute(route, {});
|
|
63
|
+
else return this.findRouteWithPathVars(verb, path);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
list() {
|
|
67
|
+
let routes = Object.values(this.routesWithoutPathVars);
|
|
68
|
+
routes = routes.concat(this.listRoutesWithPathVars());
|
|
69
|
+
// Sort the routes so that they show up in OpenAPI spec in order
|
|
70
|
+
return routes.sort(compareRoute);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Build a key for verb+path as `/<verb>/<path>`
|
|
75
|
+
* @param verb - HTTP verb/method
|
|
76
|
+
* @param path - URL path
|
|
77
|
+
*/
|
|
78
|
+
protected getKey(verb: string, path: string) {
|
|
79
|
+
verb = normalizeVerb(verb);
|
|
80
|
+
path = normalizePath(path);
|
|
81
|
+
return `/${verb}${path}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// The following abstract methods need to be implemented by its subclasses
|
|
85
|
+
/**
|
|
86
|
+
* Add a route with path variables
|
|
87
|
+
* @param route - Route
|
|
88
|
+
*/
|
|
89
|
+
protected abstract addRouteWithPathVars(route: RouteEntry): void;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Find a route with path variables for a given request
|
|
93
|
+
* @param request - Http request
|
|
94
|
+
*/
|
|
95
|
+
protected abstract findRouteWithPathVars(
|
|
96
|
+
verb: string,
|
|
97
|
+
path: string,
|
|
98
|
+
): ResolvedRoute | undefined;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* List routes with path variables
|
|
102
|
+
*/
|
|
103
|
+
protected abstract listRoutesWithPathVars(): RouteEntry[];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Normalize http verb to lowercase
|
|
108
|
+
* @param verb - Http verb
|
|
109
|
+
*/
|
|
110
|
+
function normalizeVerb(verb: string) {
|
|
111
|
+
// Use lower case, default to `get`
|
|
112
|
+
return verb?.toLowerCase() || 'get';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Normalize path to make sure it starts with `/`
|
|
117
|
+
* @param path - Path
|
|
118
|
+
*/
|
|
119
|
+
function normalizePath(path: string) {
|
|
120
|
+
// Prepend `/` if needed
|
|
121
|
+
path = path || '/';
|
|
122
|
+
path = path.startsWith('/') ? path : `/${path}`;
|
|
123
|
+
return path;
|
|
124
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
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 {OpenApiSpec} from '@loopback/openapi-v3';
|
|
7
|
+
|
|
8
|
+
export type RouterSpec = Pick<OpenApiSpec, 'paths' | 'components' | 'tags'>;
|
|
9
|
+
|
|
10
|
+
export function assignRouterSpec(target: RouterSpec, additions: RouterSpec) {
|
|
11
|
+
if (additions.components) {
|
|
12
|
+
if (!target.components) target.components = {};
|
|
13
|
+
for (const key in additions.components) {
|
|
14
|
+
if (!target.components[key]) target.components[key] = {};
|
|
15
|
+
Object.assign(target.components[key], additions.components[key]);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (const url in additions.paths) {
|
|
20
|
+
if (!(url in target.paths)) target.paths[url] = {};
|
|
21
|
+
for (const verbOrKey in additions.paths[url]) {
|
|
22
|
+
// routes registered earlier takes precedence
|
|
23
|
+
if (verbOrKey in target.paths[url]) continue;
|
|
24
|
+
target.paths[url][verbOrKey] = additions.paths[url][verbOrKey];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (additions.tags && additions.tags.length > 0) {
|
|
29
|
+
if (!target.tags) target.tags = [];
|
|
30
|
+
for (const tag of additions.tags) {
|
|
31
|
+
// tags defined earlier take precedence
|
|
32
|
+
if (target.tags.some(t => t.name === tag.name)) continue;
|
|
33
|
+
target.tags.push(tag);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|