lumen-framework 3.1.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -109
- package/bin/lumen +23 -41
- package/dist/cli.cjs +856 -479
- package/dist/cli.cjs.map +4 -4
- package/dist/index.js +3273 -1719
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +3251 -1697
- package/dist/index.mjs.map +4 -4
- package/dist/testing.js +280 -0
- package/dist/testing.js.map +7 -0
- package/dist/testing.mjs +252 -0
- package/dist/testing.mjs.map +7 -0
- package/dist/types/errors/links-only-error.d.ts +13 -0
- package/dist/types/errors/reserved-field-name-error.d.ts +13 -0
- package/dist/types/errors/unknown-attribute-error.d.ts +13 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/interfaces.d.ts +1 -1
- package/dist/types/packages/application/index.d.ts +38 -45
- package/dist/types/packages/application/initialize.d.ts +3 -5
- package/dist/types/packages/application/interfaces.d.ts +13 -5
- package/dist/types/packages/application/utils/create-controller.d.ts +14 -4
- package/dist/types/packages/application/utils/create-serializer.d.ts +2 -2
- package/dist/types/packages/application/utils/normalize-port.d.ts +1 -3
- package/dist/types/packages/application/utils/resolve-visibility.d.ts +15 -0
- package/dist/types/packages/application/utils/restrict-open-namespaces.d.ts +19 -0
- package/dist/types/packages/application/utils/validate-attributes.d.ts +17 -0
- package/dist/types/packages/application/utils/validate-links-only.d.ts +19 -0
- package/dist/types/packages/application/utils/validate-namespaced-serializers.d.ts +3 -3
- package/dist/types/packages/application/utils/validate-reserved-names.d.ts +12 -0
- package/dist/types/packages/application/utils/warn-query-param-names.d.ts +10 -0
- package/dist/types/packages/cli/commands/dbcreate.d.ts +1 -1
- package/dist/types/packages/cli/commands/dbdrop.d.ts +1 -1
- package/dist/types/packages/cli/commands/destroy.d.ts +3 -2
- package/dist/types/packages/cli/commands/generate.d.ts +5 -5
- package/dist/types/packages/cli/commands/index.d.ts +0 -1
- package/dist/types/packages/cli/generator/index.d.ts +6 -6
- package/dist/types/packages/cli/generator/interfaces.d.ts +3 -3
- package/dist/types/packages/cli/generator/utils/create-generator.d.ts +2 -2
- package/dist/types/packages/cli/generator/utils/generate-type.d.ts +9 -9
- package/dist/types/packages/cli/generator/utils/migration-conflict.d.ts +4 -4
- package/dist/types/packages/cli/templates/pnpm-workspace.d.ts +15 -0
- package/dist/types/packages/cli/utils/create-spinner.d.ts +14 -0
- package/dist/types/packages/cli/utils/print-statements.d.ts +12 -0
- package/dist/types/packages/cli/utils/server-database.d.ts +27 -0
- package/dist/types/packages/compiler/interfaces.d.ts +1 -1
- package/dist/types/packages/config/interfaces.d.ts +10 -4
- package/dist/types/packages/controller/constants.d.ts +7 -2
- package/dist/types/packages/controller/errors/related-record-not-found-error.d.ts +4 -4
- package/dist/types/packages/controller/index.d.ts +364 -473
- package/dist/types/packages/controller/interfaces.d.ts +21 -6
- package/dist/types/packages/controller/utils/find-many.d.ts +2 -5
- package/dist/types/packages/controller/utils/find-one.d.ts +2 -5
- package/dist/types/packages/controller/utils/params-to-query.d.ts +8 -10
- package/dist/types/packages/controller/utils/resolve-relationships.d.ts +1 -3
- package/dist/types/packages/controller/utils/validate-relationships.d.ts +5 -3
- package/dist/types/packages/controller/visibility/errors.d.ts +21 -0
- package/dist/types/packages/controller/visibility/index.d.ts +51 -0
- package/dist/types/packages/database/attribute/index.d.ts +4 -6
- package/dist/types/packages/database/attribute/interfaces.d.ts +1 -1
- package/dist/types/packages/database/attribute/utils/create-attribute.d.ts +3 -5
- package/dist/types/packages/database/attribute/utils/create-getter.d.ts +2 -2
- package/dist/types/packages/database/attribute/utils/create-setter.d.ts +3 -5
- package/dist/types/packages/database/constants.d.ts +1 -0
- package/dist/types/packages/database/errors/index.d.ts +1 -0
- package/dist/types/packages/database/errors/invalid-driver-error.d.ts +1 -3
- package/dist/types/packages/database/errors/migrations-pending-error.d.ts +1 -3
- package/dist/types/packages/database/errors/model-missing-error.d.ts +1 -3
- package/dist/types/packages/database/errors/relationship-config-error.d.ts +10 -0
- package/dist/types/packages/database/errors/unique-constraint-error.d.ts +1 -1
- package/dist/types/packages/database/index.d.ts +9 -6
- package/dist/types/packages/database/initialize.d.ts +3 -5
- package/dist/types/packages/database/interfaces.d.ts +115 -25
- package/dist/types/packages/database/migration/index.d.ts +5 -7
- package/dist/types/packages/database/migration/interfaces.d.ts +2 -4
- package/dist/types/packages/database/migration/utils/generate-timestamp.d.ts +9 -1
- package/dist/types/packages/database/model/index.d.ts +348 -759
- package/dist/types/packages/database/model/initialize-class.d.ts +7 -1
- package/dist/types/packages/database/model/interfaces.d.ts +30 -12
- package/dist/types/packages/database/model/utils/attribute.d.ts +14 -0
- package/dist/types/packages/database/model/utils/get-columns.d.ts +1 -3
- package/dist/types/packages/database/model/utils/persistence.d.ts +5 -14
- package/dist/types/packages/database/model/utils/process-write-error.d.ts +2 -2
- package/dist/types/packages/database/model/utils/run-hooks.d.ts +7 -3
- package/dist/types/packages/database/model/utils/validate.d.ts +4 -1
- package/dist/types/packages/database/query/errors/record-not-found-error.d.ts +1 -1
- package/dist/types/packages/database/query/index.d.ts +179 -3
- package/dist/types/packages/database/query/runner/index.d.ts +1 -3
- package/dist/types/packages/database/query/runner/utils/build-results.d.ts +3 -4
- package/dist/types/packages/database/query/utils/format-select.d.ts +1 -3
- package/dist/types/packages/database/relationship/index.d.ts +7 -6
- package/dist/types/packages/database/relationship/interfaces.d.ts +16 -3
- package/dist/types/packages/database/relationship/utils/getters.d.ts +7 -13
- package/dist/types/packages/database/relationship/utils/inverse-setters.d.ts +5 -9
- package/dist/types/packages/database/relationship/utils/setters.d.ts +7 -13
- package/dist/types/packages/database/relationship/utils/unassociate.d.ts +1 -3
- package/dist/types/packages/database/relationship/utils/update-relationship.d.ts +6 -2
- package/dist/types/packages/database/transaction/index.d.ts +9 -10
- package/dist/types/packages/database/transaction/interfaces.d.ts +7 -1
- package/dist/types/packages/database/utils/connect.d.ts +16 -3
- package/dist/types/packages/database/utils/create-migrations.d.ts +1 -3
- package/dist/types/packages/database/utils/normalize-model-name.d.ts +1 -3
- package/dist/types/packages/database/utils/pending-migrations.d.ts +1 -3
- package/dist/types/packages/database/utils/primary-key-type.d.ts +10 -0
- package/dist/types/packages/database/utils/type-for-column.d.ts +3 -5
- package/dist/types/packages/database/utils/validate-relationships.d.ts +13 -0
- package/dist/types/packages/database/validation/errors/validation-error.d.ts +4 -4
- package/dist/types/packages/database/validation/index.d.ts +3 -5
- package/dist/types/packages/database/validation/interfaces.d.ts +1 -1
- package/dist/types/packages/freezeable/map/index.d.ts +1 -3
- package/dist/types/packages/freezeable/set/index.d.ts +1 -3
- package/dist/types/packages/freezeable/utils/freeze.d.ts +5 -15
- package/dist/types/packages/freezeable/utils/is-frozen.d.ts +1 -3
- package/dist/types/packages/fs/index.d.ts +7 -7
- package/dist/types/packages/fs/interfaces.d.ts +4 -4
- package/dist/types/packages/fs/utils/parse-path.d.ts +2 -2
- package/dist/types/packages/fs/watcher/interfaces.d.ts +1 -1
- package/dist/types/packages/jsonapi/errors/invalid-content-type-error.d.ts +3 -5
- package/dist/types/packages/jsonapi/errors/not-acceptable-error.d.ts +2 -4
- package/dist/types/packages/jsonapi/errors/unsupported-media-type-error.d.ts +2 -4
- package/dist/types/packages/jsonapi/index.d.ts +1 -1
- package/dist/types/packages/jsonapi/interfaces.d.ts +47 -36
- package/dist/types/packages/jsonapi/utils/has-media-type-params.d.ts +1 -1
- package/dist/types/packages/jsonapi/utils/is-jsonapi.d.ts +1 -1
- package/dist/types/packages/jsonapi/utils/media-type.d.ts +2 -2
- package/dist/types/packages/loader/builder/index.d.ts +3 -3
- package/dist/types/packages/loader/builder/interfaces.d.ts +7 -7
- package/dist/types/packages/loader/builder/utils/create-children-builder.d.ts +2 -2
- package/dist/types/packages/loader/builder/utils/create-parent-builder.d.ts +9 -2
- package/dist/types/packages/loader/builder/utils/sort-by-namespace.d.ts +2 -2
- package/dist/types/packages/loader/index.d.ts +1 -1
- package/dist/types/packages/loader/interfaces.d.ts +2 -2
- package/dist/types/packages/loader/resolver/index.d.ts +2 -2
- package/dist/types/packages/loader/resolver/utils/closest-ancestor.d.ts +2 -2
- package/dist/types/packages/loader/resolver/utils/closest-child.d.ts +2 -2
- package/dist/types/packages/logger/constants.d.ts +3 -3
- package/dist/types/packages/logger/errors/invalid-config-error.d.ts +5 -0
- package/dist/types/packages/logger/index.d.ts +65 -142
- package/dist/types/packages/logger/interfaces.d.ts +52 -10
- package/dist/types/packages/logger/request-logger/index.d.ts +3 -5
- package/dist/types/packages/logger/request-logger/interfaces.d.ts +5 -5
- package/dist/types/packages/logger/request-logger/templates.d.ts +5 -9
- package/dist/types/packages/logger/request-logger/utils/filter-params.d.ts +6 -1
- package/dist/types/packages/logger/request-logger/utils/log-json.d.ts +2 -4
- package/dist/types/packages/logger/request-logger/utils/log-text.d.ts +1 -3
- package/dist/types/packages/logger/request-logger/utils/params-for.d.ts +9 -0
- package/dist/types/packages/logger/utils/error-name.d.ts +7 -0
- package/dist/types/packages/logger/utils/line.d.ts +1 -3
- package/dist/types/packages/logger/writer/constants.d.ts +0 -1
- package/dist/types/packages/logger/writer/index.d.ts +6 -6
- package/dist/types/packages/logger/writer/interfaces.d.ts +2 -2
- package/dist/types/packages/logger/writer/utils/format-message.d.ts +2 -2
- package/dist/types/packages/lumenify/index.d.ts +20 -5
- package/dist/types/packages/lumenify/utils/create-response-proxy.d.ts +1 -1
- package/dist/types/packages/pm/cluster/index.d.ts +56 -7
- package/dist/types/packages/pm/cluster/interfaces.d.ts +2 -1
- package/dist/types/packages/pm/index.d.ts +2 -2
- package/dist/types/packages/router/definitions/context/index.d.ts +5 -7
- package/dist/types/packages/router/definitions/context/utils/create-definition-group.d.ts +3 -5
- package/dist/types/packages/router/definitions/context/utils/create-definition.d.ts +11 -6
- package/dist/types/packages/router/definitions/context/utils/normalize-resource-args.d.ts +4 -5
- package/dist/types/packages/router/definitions/index.d.ts +5 -9
- package/dist/types/packages/router/definitions/interfaces.d.ts +4 -4
- package/dist/types/packages/router/index.d.ts +23 -11
- package/dist/types/packages/router/interfaces.d.ts +4 -4
- package/dist/types/packages/router/namespace/index.d.ts +7 -9
- package/dist/types/packages/router/namespace/interfaces.d.ts +3 -3
- package/dist/types/packages/router/namespace/utils/normalize-name.d.ts +1 -3
- package/dist/types/packages/router/namespace/utils/normalize-path.d.ts +1 -3
- package/dist/types/packages/router/resource/index.d.ts +7 -8
- package/dist/types/packages/router/resource/interfaces.d.ts +12 -4
- package/dist/types/packages/router/resource/utils/normalize-only.d.ts +3 -5
- package/dist/types/packages/router/route/action/enhancers/resource.d.ts +1 -3
- package/dist/types/packages/router/route/action/enhancers/track-perf.d.ts +1 -3
- package/dist/types/packages/router/route/action/index.d.ts +7 -2
- package/dist/types/packages/router/route/action/interfaces.d.ts +4 -0
- package/dist/types/packages/router/route/action/utils/create-page-links.d.ts +21 -5
- package/dist/types/packages/router/route/action/utils/get-action-name.d.ts +1 -3
- package/dist/types/packages/router/route/action/utils/get-controller-name.d.ts +1 -3
- package/dist/types/packages/router/route/index.d.ts +13 -9
- package/dist/types/packages/router/route/interfaces.d.ts +7 -5
- package/dist/types/packages/router/route/params/errors/client-generated-id-error.d.ts +4 -4
- package/dist/types/packages/router/route/params/errors/forbidden-parameter-error.d.ts +4 -4
- package/dist/types/packages/router/route/params/errors/index.d.ts +1 -0
- package/dist/types/packages/router/route/params/errors/invalid-parameter-error.d.ts +4 -6
- package/dist/types/packages/router/route/params/errors/parameter-not-nullable-error.d.ts +4 -6
- package/dist/types/packages/router/route/params/errors/parameter-range-error.d.ts +9 -0
- package/dist/types/packages/router/route/params/errors/parameter-required-error.d.ts +4 -6
- package/dist/types/packages/router/route/params/errors/parameter-type-error.d.ts +4 -6
- package/dist/types/packages/router/route/params/errors/parameter-value-error.d.ts +4 -6
- package/dist/types/packages/router/route/params/errors/resource-mismatch-error.d.ts +4 -6
- package/dist/types/packages/router/route/params/index.d.ts +5 -9
- package/dist/types/packages/router/route/params/interfaces.d.ts +12 -8
- package/dist/types/packages/router/route/params/parameter/forbidden-parameter.d.ts +1 -1
- package/dist/types/packages/router/route/params/parameter/ignored-parameter.d.ts +14 -0
- package/dist/types/packages/router/route/params/parameter/index.d.ts +21 -5
- package/dist/types/packages/router/route/params/parameter/interfaces.d.ts +2 -2
- package/dist/types/packages/router/route/params/parameter/utils/validate-range.d.ts +3 -0
- package/dist/types/packages/router/route/params/parameter/utils/validate-value.d.ts +1 -3
- package/dist/types/packages/router/route/params/parameter-group/index.d.ts +3 -5
- package/dist/types/packages/router/route/params/parameter-group/utils/missing-params.d.ts +8 -0
- package/dist/types/packages/router/route/params/utils/get-data-params.d.ts +5 -1
- package/dist/types/packages/router/route/params/utils/get-default-collection-params.d.ts +1 -3
- package/dist/types/packages/router/route/params/utils/get-default-member-params.d.ts +5 -2
- package/dist/types/packages/router/route/params/utils/get-query-params.d.ts +3 -9
- package/dist/types/packages/router/route/params/utils/get-url-params.d.ts +1 -3
- package/dist/types/packages/router/route/params/utils/parse-column-value.d.ts +16 -0
- package/dist/types/packages/router/route/params/utils/validate-client-id.d.ts +1 -1
- package/dist/types/packages/router/route/params/utils/validate-resource-id.d.ts +1 -3
- package/dist/types/packages/router/route/params/utils/validate-type.d.ts +3 -5
- package/dist/types/packages/router/route/utils/get-dynamic-segments.d.ts +1 -3
- package/dist/types/packages/router/route/utils/get-static-path.d.ts +6 -2
- package/dist/types/packages/router/utils/create-replacer.d.ts +10 -2
- package/dist/types/packages/serializer/index.d.ts +243 -434
- package/dist/types/packages/serializer/interfaces.d.ts +19 -1
- package/dist/types/packages/serializer/utils/include-tree.d.ts +12 -3
- package/dist/types/packages/serializer/utils/load-linkage.d.ts +9 -3
- package/dist/types/packages/server/errors/error-list.d.ts +25 -0
- package/dist/types/packages/server/errors/method-not-allowed-error.d.ts +11 -0
- package/dist/types/packages/server/index.d.ts +9 -9
- package/dist/types/packages/server/interfaces.d.ts +59 -7
- package/dist/types/packages/server/request/constants.d.ts +2 -2
- package/dist/types/packages/server/request/index.d.ts +3 -5
- package/dist/types/packages/server/request/interfaces.d.ts +72 -8
- package/dist/types/packages/server/request/parser/errors/malformed-request-error.d.ts +3 -5
- package/dist/types/packages/server/request/parser/index.d.ts +6 -1
- package/dist/types/packages/server/request/parser/utils/format.d.ts +13 -11
- package/dist/types/packages/server/request/parser/utils/normalize-document.d.ts +13 -0
- package/dist/types/packages/server/request/parser/utils/parse-nested-object.d.ts +1 -3
- package/dist/types/packages/server/request/parser/utils/parse-read.d.ts +2 -4
- package/dist/types/packages/server/request/parser/utils/parse-write.d.ts +17 -1
- package/dist/types/packages/server/request/utils/get-domain.d.ts +1 -3
- package/dist/types/packages/server/responder/index.d.ts +1 -3
- package/dist/types/packages/server/responder/utils/content-type-for.d.ts +8 -0
- package/dist/types/packages/server/responder/utils/data-for.d.ts +3 -5
- package/dist/types/packages/server/responder/utils/normalize.d.ts +2 -3
- package/dist/types/packages/server/response/index.d.ts +3 -5
- package/dist/types/packages/server/response/interfaces.d.ts +14 -3
- package/dist/types/packages/server/utils/client-ip-for.d.ts +10 -0
- package/dist/types/packages/server/utils/create-server-error.d.ts +11 -3
- package/dist/types/packages/server/utils/request-id-for.d.ts +9 -0
- package/dist/types/packages/server/utils/set-cors-headers.d.ts +2 -2
- package/dist/types/packages/server/utils/source-for.d.ts +19 -3
- package/dist/types/packages/server/utils/status-for-error.d.ts +6 -0
- package/dist/types/packages/server/utils/validate-accept.d.ts +1 -1
- package/dist/types/packages/server/utils/validate-content-type.d.ts +8 -3
- package/dist/types/packages/testing/audit-visibility.d.ts +189 -0
- package/dist/types/packages/testing/index.d.ts +4 -0
- package/dist/types/packages/testing/start-app.d.ts +52 -0
- package/dist/types/packages/testing/utils/identifiers-in.d.ts +14 -0
- package/dist/types/testing.d.ts +9 -0
- package/dist/types/utils/chalk.d.ts +16 -0
- package/dist/types/utils/pick.d.ts +2 -2
- package/package.json +54 -26
- package/dist/types/packages/cli/commands/test.d.ts +0 -4
- package/dist/types/packages/logger/utils/sql.d.ts +0 -4
- package/dist/types/packages/router/route/params/parameter-group/utils/has-required-params.d.ts +0 -5
- package/dist/types/utils/create-query-string.d.ts +0 -6
- package/dist/types/utils/has-own-property.d.ts +0 -1
|
@@ -1,455 +1,206 @@
|
|
|
1
1
|
import type Serializer from '../serializer';
|
|
2
2
|
import type { Model, ModelClass, Query } from '../database';
|
|
3
3
|
import type { Request, Response } from '../server';
|
|
4
|
-
import type {
|
|
4
|
+
import type { Visibility } from './visibility';
|
|
5
|
+
import type { ControllerOptions, BeforeAction, AfterAction } from './interfaces';
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* Think of a Controller as a server at a restaurant. A client makes a request
|
|
12
|
-
* to an application, that request is routed to the appropriate Controller and
|
|
13
|
-
* then the Controller interprets the request and returns data relative to what
|
|
14
|
-
* the client has request.
|
|
15
|
-
*
|
|
16
|
-
* #### Actions
|
|
17
|
-
*
|
|
18
|
-
* Controller actions are functions that call on a Controller in response to an
|
|
19
|
-
* incoming HTTP request. The job of Controller actions are to return the data
|
|
20
|
-
* that the Lumen Application will respond with.
|
|
21
|
-
*
|
|
22
|
-
* There is no special API for Controller actions. They are simply functions
|
|
23
|
-
* that return a value. If an action returns a Query or Promise the resolved
|
|
24
|
-
* value will be used rather than the immediate return value of the action.
|
|
25
|
-
*
|
|
26
|
-
* Below you will find a table showing the different types of responses you can
|
|
27
|
-
* get from different action return values. Keep in mind, Lumen is agnostic to
|
|
28
|
-
* whether or not the value is returned synchronously or resolved from a
|
|
29
|
-
* Promise.
|
|
30
|
-
*
|
|
31
|
-
* | Return/Resolved Value | Response |
|
|
32
|
-
* |------------------------------|--------------------------------------------|
|
|
33
|
-
* | Array<Model> or Model | Serialized JSON String |
|
|
34
|
-
* | Array or Object Literal | JSON String |
|
|
35
|
-
* | String Literal | Plain Text |
|
|
36
|
-
* | Number Literal | [HTTP Status Code](https://goo.gl/T2lMc7) |
|
|
37
|
-
* | true | [204 No Content](https://goo.gl/GxKoqz) |
|
|
38
|
-
* | false | [401 Unauthorized](https://goo.gl/60QqCW) |
|
|
39
|
-
*
|
|
40
|
-
* **Built-In Actions**
|
|
41
|
-
*
|
|
42
|
-
* Built-in actions refer to Controller actions that you get for free when
|
|
43
|
-
* extending the Controller class (show, index, create, update, destroy). These
|
|
44
|
-
* actions are highly optimized to load only the attributes and relationships
|
|
45
|
-
* that are defined in the resolved Serializer for a Controller.
|
|
46
|
-
*
|
|
47
|
-
* If applicable, built-in actions support the following features described in
|
|
48
|
-
* the [JSON API specification](http://jsonapi.org/):
|
|
49
|
-
*
|
|
50
|
-
* - [Sorting](http://jsonapi.org/format/#fetching-sorting)
|
|
51
|
-
* - [Filtering](http://jsonapi.org/format/#fetching-filtering)
|
|
52
|
-
* - [Pagination](http://jsonapi.org/format/#fetching-pagination)
|
|
53
|
-
* - [Sparse Fieldsets](http://jsonapi.org/format/#fetching-sparse-fieldsets)
|
|
54
|
-
* - [Including Related Resources](http://jsonapi.org/format/#fetching-includes)
|
|
55
|
-
*
|
|
56
|
-
* **Extending Built-In Actions**
|
|
57
|
-
*
|
|
58
|
-
* Considering the amount of functionality built-in actions provide, you will
|
|
59
|
-
* rarely need to override the default behavior of a built-in action. In the
|
|
60
|
-
* event that you do need to override a built-in action, you have the ability to
|
|
61
|
-
* opt back into the built-in logic by calling the super class.
|
|
62
|
-
*
|
|
63
|
-
* Read actions such as index and show return a Query which allows us to chain
|
|
64
|
-
* methods to the super call. In the following example we will extend the
|
|
65
|
-
* default behavior of the index action to only match records that meet an
|
|
66
|
-
* additional hard-coded set of conditions. We will still be able to use all of
|
|
67
|
-
* the functionality that the built-in index action provides.
|
|
7
|
+
* The base class of an app's controllers. A controller handles the requests
|
|
8
|
+
* for one resource; its built-in actions — `index`, `show`, `create`,
|
|
9
|
+
* `update`, `destroy`, and the relationship endpoints' `showRelationship` and
|
|
10
|
+
* `showRelated` — read and write records with sorting, filtering, paging,
|
|
11
|
+
* `include` and sparse fieldsets, so a controller is mostly configuration:
|
|
68
12
|
*
|
|
69
13
|
* ```javascript
|
|
70
14
|
* // app/controllers/posts.js
|
|
71
15
|
* import { Controller } from 'lumen-framework';
|
|
72
16
|
*
|
|
73
17
|
* class PostsController extends Controller {
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* });
|
|
78
|
-
* }
|
|
79
|
-
* }
|
|
80
|
-
*
|
|
81
|
-
* export default PostsController;
|
|
82
|
-
* ```
|
|
83
|
-
*
|
|
84
|
-
* **Custom Actions**
|
|
85
|
-
*
|
|
86
|
-
* Sometimes it is necessary to add a custom action to a Controller. Lumen allows
|
|
87
|
-
* you to do so by adding an instance method to a Controller. In the following
|
|
88
|
-
* example you will see how to add a custom action with the name `check` to a
|
|
89
|
-
* Controller. We are implementing this action to use as a health check for the
|
|
90
|
-
* application so we want to return the `Number` literal `204`.
|
|
91
|
-
*
|
|
92
|
-
* ```javascript
|
|
93
|
-
* // app/controllers/health.js
|
|
94
|
-
* import { Controller } from 'lumen-framework';
|
|
95
|
-
*
|
|
96
|
-
* class HealthController extends Controller {
|
|
97
|
-
* async check() {
|
|
98
|
-
* return 204;
|
|
99
|
-
* }
|
|
100
|
-
* }
|
|
101
|
-
*
|
|
102
|
-
* export default HealthController;
|
|
103
|
-
* ```
|
|
104
|
-
*
|
|
105
|
-
* The example above is nice but we can make the code a bit more concise with an
|
|
106
|
-
* Arrow `Function`.
|
|
107
|
-
*
|
|
108
|
-
* ```javascript
|
|
109
|
-
* // app/controllers/health.js
|
|
110
|
-
* import { Controller } from 'lumen-framework';
|
|
111
|
-
*
|
|
112
|
-
* class HealthController extends Controller {
|
|
113
|
-
* check = async () => 204;
|
|
114
|
-
* }
|
|
115
|
-
*
|
|
116
|
-
* export default HealthController;
|
|
117
|
-
* ```
|
|
118
|
-
*
|
|
119
|
-
* Using an Arrow Function instead of a traditional method Controller can be
|
|
120
|
-
* useful when immediately returning a value. However, there are a few downsides
|
|
121
|
-
* to using an Arrow `Function` for a Controller action, such as not being able
|
|
122
|
-
* to call the `super class`. This can be an issue if you are looking to extend
|
|
123
|
-
* a built-in action.
|
|
124
|
-
*
|
|
125
|
-
* Another use case for a custom action could be to return a specific scope of
|
|
126
|
-
* data from a `Model`. Let's implement
|
|
127
|
-
* a custom `drafts` route on a `PostsController`.
|
|
128
|
-
*
|
|
129
|
-
* ```javascript
|
|
130
|
-
* // app/controllers/posts.js
|
|
131
|
-
* import { Controller } from 'lumen-framework';
|
|
132
|
-
* import Post from 'app/models/posts';
|
|
133
|
-
*
|
|
134
|
-
* class PostsController extends Controller {
|
|
135
|
-
* drafts() {
|
|
136
|
-
* return Post.where({
|
|
137
|
-
* isPublic: false
|
|
138
|
-
* });
|
|
139
|
-
* }
|
|
18
|
+
* params = ['title', 'body', 'user'];
|
|
19
|
+
* sort = ['title', 'createdAt'];
|
|
20
|
+
* maxPerPage = 50;
|
|
140
21
|
* }
|
|
141
22
|
*
|
|
142
23
|
* export default PostsController;
|
|
143
24
|
* ```
|
|
144
25
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* chain a `.where()` to it.
|
|
26
|
+
* Override a built-in action, or add a custom one, with a method that takes
|
|
27
|
+
* `(request, response)`. `index` and `show` return a {@link Query}, so an
|
|
28
|
+
* override can narrow it and keep everything else:
|
|
149
29
|
*
|
|
150
30
|
* ```javascript
|
|
151
|
-
* // app/controllers/posts.js
|
|
152
|
-
* import { Controller } from 'lumen-framework';
|
|
153
|
-
*
|
|
154
31
|
* class PostsController extends Controller {
|
|
155
|
-
*
|
|
156
|
-
* return
|
|
157
|
-
* isPublic: false
|
|
158
|
-
* });
|
|
32
|
+
* index(request, response) {
|
|
33
|
+
* return super.index(request, response).where({ isPublic: true });
|
|
159
34
|
* }
|
|
160
35
|
* }
|
|
161
|
-
*
|
|
162
|
-
* export default PostsController;
|
|
163
36
|
* ```
|
|
164
37
|
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* `
|
|
177
|
-
*
|
|
178
|
-
* **Context**
|
|
179
|
-
*
|
|
180
|
-
* Middleware functions will be bound to the Controller they are added to upon
|
|
181
|
-
* the start of an Application.
|
|
182
|
-
*
|
|
183
|
-
* Due to the lexical binding of arrow functions, if you need to use the `this`
|
|
184
|
-
* keyword within a middleware function, declare the middleware function using
|
|
185
|
-
* the `function` keyword and not as an arrow function.
|
|
186
|
-
*
|
|
187
|
-
* **Scoping Middleware**
|
|
188
|
-
*
|
|
189
|
-
* Middleware is scoped by Controller and includes a parent Controller's
|
|
190
|
-
* middleware recursively until the parent Controller is the root
|
|
191
|
-
* `ApplicationController`. This allows you to implement custom logic that can
|
|
192
|
-
* be executed for resources, namespaces, or an entire Application.
|
|
193
|
-
*
|
|
194
|
-
* Let's say we want to require authentication for every route in our
|
|
195
|
-
* Application. All we have to do is move our authentication middleware function
|
|
196
|
-
* from the example above to the `ApplicationController`.
|
|
197
|
-
*
|
|
198
|
-
* ```javascript
|
|
199
|
-
* // app/controllers/application.js
|
|
200
|
-
* import { Controller } from 'lumen-framework';
|
|
201
|
-
*
|
|
202
|
-
* class ApplicationController extends Controller {
|
|
203
|
-
* beforeAction = [
|
|
204
|
-
* async function authenticate(request) {
|
|
205
|
-
* if (!request.currentUser) {
|
|
206
|
-
* // 401 Unauthorized
|
|
207
|
-
* return false;
|
|
208
|
-
* }
|
|
209
|
-
* }
|
|
210
|
-
* ];
|
|
211
|
-
* }
|
|
212
|
-
*
|
|
213
|
-
* export default ApplicationController;
|
|
214
|
-
* ```
|
|
215
|
-
*
|
|
216
|
-
* **Execuation Order**
|
|
217
|
-
*
|
|
218
|
-
* Understanding the execution order of middleware functions and a `Controller`
|
|
219
|
-
* action is essential to productivity with Lumen. Depending on what you use case
|
|
220
|
-
* is, you may want your function to execute at different times in the
|
|
221
|
-
* `request` / `response` cycle.
|
|
222
|
-
*
|
|
223
|
-
* 1. Parent `Controller` `beforeAction` hooks
|
|
224
|
-
* 2. `Controller` `beforeAction` hooks
|
|
225
|
-
* 3. `Controller` Action
|
|
226
|
-
* 4. `Controller` `afterAction` hooks
|
|
227
|
-
* 5. Parent `Controller` `afterAction` hooks
|
|
228
|
-
*
|
|
229
|
-
* **Modules**
|
|
230
|
-
*
|
|
231
|
-
* It is considered a best practice to define your middleware functions in
|
|
232
|
-
* separate file and export them for use throughout an Application. Typically
|
|
233
|
-
* this is done within an `app/middleware` directory.
|
|
234
|
-
*
|
|
235
|
-
* ```javascript
|
|
236
|
-
* // app/middleware/authenticate.js
|
|
237
|
-
* export default async function authenticate(request) {
|
|
238
|
-
* if (!request.currentUser) {
|
|
239
|
-
* // 401 Unauthorized
|
|
240
|
-
* return false;
|
|
241
|
-
* }
|
|
242
|
-
* }
|
|
243
|
-
* ```
|
|
244
|
-
*
|
|
245
|
-
* This keeps the Controller code clean, easier to read, and easier to modify.
|
|
246
|
-
*
|
|
247
|
-
* ```javascript
|
|
248
|
-
* // app/controllers/application.js
|
|
249
|
-
* import { Controller } from 'lumen-framework';
|
|
250
|
-
* import authenticate from 'app/middleware/authenticate';
|
|
251
|
-
*
|
|
252
|
-
* class ApplicationController extends Controller {
|
|
253
|
-
* beforeAction = [
|
|
254
|
-
* authenticate
|
|
255
|
-
* ];
|
|
256
|
-
* }
|
|
257
|
-
*
|
|
258
|
-
* export default ApplicationController;
|
|
259
|
-
* ```
|
|
260
|
-
*
|
|
261
|
-
* @class Controller
|
|
262
|
-
* @public
|
|
38
|
+
* What an action returns becomes the response: a query, record or array of
|
|
39
|
+
* records is serialized as a JSON:API document; another object or array is
|
|
40
|
+
* sent as JSON, a string as the body; a number is that status, `true` a
|
|
41
|
+
* `204 No Content`, `false` a `401 Unauthorized`, and `undefined` a
|
|
42
|
+
* `404 Not Found`.
|
|
43
|
+
*
|
|
44
|
+
* A namespace's `ApplicationController` (`app/controllers/application.js`,
|
|
45
|
+
* `app/controllers/admin/application.js`) holds what applies to the whole
|
|
46
|
+
* namespace: its hooks run around every action in it, and it declares the
|
|
47
|
+
* {@link Controller.visibility} rules and the settings
|
|
48
|
+
* `rejectUnlistedAttributes`, `rejectUnlistedRelationships` and
|
|
49
|
+
* `maxIncludeDepth` for every controller in it. See the
|
|
50
|
+
* [controllers guide](https://github.com/nickschot/lux/blob/main/docs/guides/controllers.md).
|
|
263
51
|
*/
|
|
264
52
|
declare class Controller {
|
|
265
53
|
/**
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
* For security reasons, query parameters passed to Controller actions from an
|
|
270
|
-
* incoming request other than sort, filter, and page must have their key
|
|
271
|
-
* whitelisted.
|
|
54
|
+
* Query parameters an action may read beyond the JSON:API ones (`sort`,
|
|
55
|
+
* `filter`, `page`, `include`, `fields`). Any other query parameter is a
|
|
56
|
+
* `400 Bad Request`. A listed one arrives in `request.params`:
|
|
272
57
|
*
|
|
273
58
|
* ```javascript
|
|
274
|
-
* class
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
59
|
+
* class PostsController extends Controller {
|
|
60
|
+
* query = ['search'];
|
|
61
|
+
*
|
|
62
|
+
* index(request, response) {
|
|
63
|
+
* const { search } = request.params;
|
|
64
|
+
* const posts = super.index(request, response);
|
|
65
|
+
*
|
|
66
|
+
* return search ? posts.where({ body: search }) : posts;
|
|
67
|
+
* }
|
|
280
68
|
* }
|
|
281
69
|
* ```
|
|
282
70
|
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
* @public
|
|
71
|
+
* Name them with a character other than a–z (`search-term`, `searchTerm`):
|
|
72
|
+
* JSON:API reserves all-lowercase names for itself, and Lumen warns about
|
|
73
|
+
* them at boot.
|
|
287
74
|
*/
|
|
288
75
|
query: Array<string>;
|
|
289
76
|
/**
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
* Serializer that represents a Controller's resource. If the Serializer
|
|
295
|
-
* cannot be resolved, this property will default to an empty array.
|
|
296
|
-
*
|
|
297
|
-
* @property sort
|
|
298
|
-
* @type {Array}
|
|
299
|
-
* @default []
|
|
300
|
-
* @public
|
|
77
|
+
* The attributes `?sort=` accepts, each also with `-` for descending.
|
|
78
|
+
* Defaults to every attribute the controller's serializer outputs; anything
|
|
79
|
+
* else is a `400 Bad Request`. Each must be a column of the model's table,
|
|
80
|
+
* or the app refuses to boot.
|
|
301
81
|
*/
|
|
302
82
|
sort: Array<string>;
|
|
303
83
|
/**
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
* If you do not override this property all of the attributes specified in the
|
|
308
|
-
* Serializer that represents a Controller's resource. If the Serializer
|
|
309
|
-
* cannot be resolved, this property will default to an empty array.
|
|
310
|
-
*
|
|
311
|
-
* @property filter
|
|
312
|
-
* @type {Array}
|
|
313
|
-
* @default []
|
|
314
|
-
* @public
|
|
84
|
+
* The attributes `?filter[…]=` accepts. Defaults to every attribute the
|
|
85
|
+
* controller's serializer outputs; anything else is a `400 Bad Request`.
|
|
86
|
+
* Each must be a column of the model's table, or the app refuses to boot.
|
|
315
87
|
*/
|
|
316
88
|
filter: Array<string>;
|
|
317
89
|
/**
|
|
318
|
-
*
|
|
319
|
-
* from an incoming `POST` or `PATCH` request body.
|
|
90
|
+
* The attributes and relationships a `POST` or `PATCH` body may set.
|
|
320
91
|
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
92
|
+
* ```javascript
|
|
93
|
+
* class PostsController extends Controller {
|
|
94
|
+
* params = ['title', 'body', 'user'];
|
|
95
|
+
* }
|
|
96
|
+
* ```
|
|
324
97
|
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
* @
|
|
98
|
+
* An attribute the model has but this list doesn't name is ignored (dropped
|
|
99
|
+
* from `request.params`), so clients may send read-only attributes back; a
|
|
100
|
+
* relationship like that is answered with `403 Forbidden`.
|
|
101
|
+
* {@link Controller.rejectUnlistedAttributes} and
|
|
102
|
+
* {@link Controller.rejectUnlistedRelationships} change either. A member the
|
|
103
|
+
* model doesn't have at all is a `400 Bad Request`.
|
|
329
104
|
*/
|
|
330
105
|
params: Array<string>;
|
|
331
106
|
/**
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
* actions, however, they are expected to return `undefined`. If a middleware
|
|
337
|
-
* function returns a value other than `undefined` the `request` / `response`
|
|
338
|
-
* cycle will end before remaining middleware and/or Controller actions are
|
|
339
|
-
* executed. This makes the `beforeAction` hook a very powerful tool for
|
|
340
|
-
* dealing with many common tasks, such as authentication.
|
|
341
|
-
*
|
|
342
|
-
* Functions called from the `beforeAction` hook will have `request` and
|
|
343
|
-
* `response` objects passed as arguments.
|
|
344
|
-
*
|
|
345
|
-
* **Example:**
|
|
107
|
+
* Hooks that run before each action, called with `(request, response)`.
|
|
108
|
+
* Returning nothing lets the request continue; returning anything else ends
|
|
109
|
+
* it, with that value as the response (`false` → `401 Unauthorized`, a
|
|
110
|
+
* number → that status):
|
|
346
111
|
*
|
|
347
112
|
* ```javascript
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
* function isAdmin(user) {
|
|
353
|
-
* if (user) {
|
|
354
|
-
* return user.isAdmin;
|
|
355
|
-
* }
|
|
356
|
-
*
|
|
357
|
-
* return false;
|
|
358
|
-
* }
|
|
359
|
-
*
|
|
360
|
-
* async function authentication(request) {
|
|
361
|
-
* const { method, currentUser } = request;
|
|
362
|
-
* const isUnsafe = UNSAFE_METHODS.test(method);
|
|
363
|
-
*
|
|
364
|
-
* if (isUnsafe && !isAdmin(currentUser)) {
|
|
365
|
-
* return false; // 401 Unauthorized if the current user is not an admin.
|
|
113
|
+
* async function requireUser(request) {
|
|
114
|
+
* if (!request.currentUser) {
|
|
115
|
+
* return false;
|
|
366
116
|
* }
|
|
367
117
|
* }
|
|
368
118
|
*
|
|
369
119
|
* class PostsController extends Controller {
|
|
370
|
-
* beforeAction = [
|
|
371
|
-
* authentication
|
|
372
|
-
* ];
|
|
120
|
+
* beforeAction = [requireUser];
|
|
373
121
|
* }
|
|
374
|
-
*
|
|
375
|
-
* export default PostsController;
|
|
376
122
|
* ```
|
|
377
123
|
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
*
|
|
124
|
+
* The hooks of a namespace's `ApplicationController` run around every action
|
|
125
|
+
* in the namespace, before the controller's own. Hooks run after the
|
|
126
|
+
* request's parameters are validated, and are called with `this` as the
|
|
127
|
+
* controller that declares them (use `function`, not an arrow function, to
|
|
128
|
+
* read it).
|
|
382
129
|
*/
|
|
383
|
-
beforeAction: Array<
|
|
130
|
+
beforeAction: Array<BeforeAction>;
|
|
384
131
|
/**
|
|
385
|
-
*
|
|
386
|
-
* `
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
* argument. The `payload` argument is a reference to the resolved data of
|
|
391
|
-
* the Controller action that was called within the current `request` /
|
|
392
|
-
* `response` cycle. You need to explicitly return this `payload` in order for
|
|
393
|
-
* the afterAction to resolve with it's data. If you return a modified value
|
|
394
|
-
* from a function added to the `afterAction` hook, that value will be used
|
|
395
|
-
* instead of the resolved data from the preceding Controller action.
|
|
396
|
-
* Subsequent hooks called from an `afterAction` hook will will use the value
|
|
397
|
-
* returned or resolved from the preceding hook. This makes `afterAction` a
|
|
398
|
-
* great place to modify the data you are sending back to the client.
|
|
399
|
-
*
|
|
400
|
-
* **Example:**
|
|
132
|
+
* Hooks that run after each action, called with
|
|
133
|
+
* `(request, response, payload)`. `payload` is the action's result — for a
|
|
134
|
+
* resource, the JSON:API document about to be sent. What a hook returns is
|
|
135
|
+
* sent instead, and passed to the next hook, so return `payload` when
|
|
136
|
+
* leaving it as it is:
|
|
401
137
|
*
|
|
402
138
|
* ```javascript
|
|
403
|
-
*
|
|
404
|
-
*
|
|
405
|
-
*
|
|
406
|
-
* const { action } = request;
|
|
407
|
-
*
|
|
408
|
-
* if (payload && action !== preflight) {
|
|
409
|
-
* return {
|
|
410
|
-
* ...payload,
|
|
411
|
-
* meta: {
|
|
412
|
-
* copyright: '2016 (c) Postlight'
|
|
413
|
-
* }
|
|
414
|
-
* };
|
|
139
|
+
* async function addVersion(request, response, payload) {
|
|
140
|
+
* if (payload && payload.jsonapi) {
|
|
141
|
+
* return { ...payload, meta: { ...payload.meta, apiVersion: '2' } };
|
|
415
142
|
* }
|
|
416
143
|
*
|
|
417
144
|
* return payload;
|
|
418
145
|
* }
|
|
419
146
|
*
|
|
420
147
|
* class ApplicationController extends Controller {
|
|
421
|
-
* afterAction = [
|
|
422
|
-
* addCopyright
|
|
423
|
-
* ];
|
|
148
|
+
* afterAction = [addVersion];
|
|
424
149
|
* }
|
|
425
|
-
*
|
|
426
|
-
* export default ApplicationController;
|
|
427
150
|
* ```
|
|
428
151
|
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
* @default []
|
|
432
|
-
* @public
|
|
152
|
+
* A namespace `ApplicationController`'s `afterAction` hooks run after the
|
|
153
|
+
* controller's own.
|
|
433
154
|
*/
|
|
434
|
-
afterAction: Array<
|
|
155
|
+
afterAction: Array<AfterAction>;
|
|
435
156
|
/**
|
|
436
|
-
* The
|
|
437
|
-
* action if a `?page[size]` query parameter is not specified.
|
|
438
|
-
*
|
|
439
|
-
* @property defaultPerPage
|
|
440
|
-
* @type {Number}
|
|
441
|
-
* @default 25
|
|
442
|
-
* @public
|
|
157
|
+
* The page size of `index` when the request gives no `?page[size]=`.
|
|
443
158
|
*/
|
|
444
159
|
defaultPerPage: number;
|
|
160
|
+
/**
|
|
161
|
+
* The largest `?page[size]=` `index` accepts. A larger one is a
|
|
162
|
+
* `400 Bad Request`, as is a `page[size]` or `page[number]` below 1.
|
|
163
|
+
*/
|
|
164
|
+
maxPerPage: number;
|
|
165
|
+
/**
|
|
166
|
+
* Answer an attribute the model has but `params` does not list with
|
|
167
|
+
* `403 Forbidden` (an unsupported update, per JSON:API) instead of ignoring
|
|
168
|
+
* it. Off by default: clients like ember-data send every attribute back on
|
|
169
|
+
* save, read-only ones (`createdAt`) included.
|
|
170
|
+
*
|
|
171
|
+
* Set on a namespace's `ApplicationController`, it applies to every
|
|
172
|
+
* controller in the namespace (and in namespaces nested in it) that does not
|
|
173
|
+
* set it itself — whatever class those controllers extend.
|
|
174
|
+
*
|
|
175
|
+
* @default false
|
|
176
|
+
*/
|
|
177
|
+
rejectUnlistedAttributes: boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Answer a relationship the model has but `params` does not list with
|
|
180
|
+
* `403 Forbidden` (an unsupported update, per JSON:API). Turn it off to
|
|
181
|
+
* ignore such relationships instead, for clients that send every
|
|
182
|
+
* `belongsTo` back on save (ember-data). Like `rejectUnlistedAttributes`,
|
|
183
|
+
* setting it on a namespace's `ApplicationController` sets it for the whole
|
|
184
|
+
* namespace:
|
|
185
|
+
*
|
|
186
|
+
* ```javascript
|
|
187
|
+
* class ApplicationController extends Controller {
|
|
188
|
+
* rejectUnlistedRelationships = false;
|
|
189
|
+
* }
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* @default true
|
|
193
|
+
*/
|
|
194
|
+
rejectUnlistedRelationships: boolean;
|
|
445
195
|
/**
|
|
446
196
|
* How many relationships deep an `?include` path may go on this
|
|
447
197
|
* controller's routes. `comments.reactions.user` is 3 levels deep; with `1`
|
|
448
198
|
* only direct relationships (`comments`) can be included. Paths deeper than
|
|
449
|
-
* this are rejected with `400 Bad Request
|
|
199
|
+
* this are rejected with `400 Bad Request`; `0` turns `?include` off.
|
|
450
200
|
*
|
|
451
|
-
* Set
|
|
452
|
-
*
|
|
201
|
+
* Set on a namespace's `ApplicationController`, it applies to every
|
|
202
|
+
* controller in the namespace (and in namespaces nested in it) that does not
|
|
203
|
+
* set it itself — whatever class those controllers extend.
|
|
453
204
|
*
|
|
454
205
|
* ```javascript
|
|
455
206
|
* class ApplicationController extends Controller {
|
|
@@ -461,10 +212,10 @@ declare class Controller {
|
|
|
461
212
|
* relationships, and each nested level costs its own queries per request, so
|
|
462
213
|
* keep this small.
|
|
463
214
|
*
|
|
464
|
-
* @
|
|
465
|
-
*
|
|
215
|
+
* In a namespace without {@link Controller.visibility} rules it defaults to
|
|
216
|
+
* `0`: nothing there scopes the included records.
|
|
217
|
+
*
|
|
466
218
|
* @default 3
|
|
467
|
-
* @public
|
|
468
219
|
*/
|
|
469
220
|
maxIncludeDepth: number;
|
|
470
221
|
/**
|
|
@@ -489,168 +240,308 @@ declare class Controller {
|
|
|
489
240
|
* serialize or `include` (down to each controller's `maxIncludeDepth`) has
|
|
490
241
|
* no Serializer in that namespace, listing each missing one.
|
|
491
242
|
*
|
|
492
|
-
* @property serializerFallback
|
|
493
|
-
* @type {Boolean}
|
|
494
243
|
* @default true
|
|
495
|
-
* @public
|
|
496
244
|
*/
|
|
497
245
|
serializerFallback: boolean;
|
|
498
246
|
/**
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
247
|
+
* Which rows of each type a request may see, declared once per namespace on
|
|
248
|
+
* its `ApplicationController`. Each rule receives a query of its type and
|
|
249
|
+
* the request, and returns the query narrowed:
|
|
250
|
+
*
|
|
251
|
+
* ```javascript
|
|
252
|
+
* // app/controllers/application.js
|
|
253
|
+
* class ApplicationController extends Controller {
|
|
254
|
+
* static visibility = {
|
|
255
|
+
* posts: query => query.isPublic(),
|
|
256
|
+
* comments: (query, { currentUser }) =>
|
|
257
|
+
* query.where({ userId: currentUser.id })
|
|
258
|
+
* };
|
|
259
|
+
* }
|
|
260
|
+
* ```
|
|
261
|
+
*
|
|
262
|
+
* Lumen applies the rule wherever it loads rows of that type for a request
|
|
263
|
+
* in the namespace: `index` and its page links, `show`, `update` and
|
|
264
|
+
* `destroy` (a hidden record is `404 Not Found`, like a missing one), every
|
|
265
|
+
* relationship's resource linkage, `included` resources at any depth, and
|
|
266
|
+
* the related records referenced by a `create` or `update` (a hidden one is
|
|
267
|
+
* reported as not found). A to-one relationship to a hidden record is
|
|
268
|
+
* serialized as `null`; a to-many one leaves it out.
|
|
269
|
+
*
|
|
270
|
+
* Rules must be synchronous and may only add conditions (`where`, `not`,
|
|
271
|
+
* `whereBetween`, `whereRaw`, or model scopes built from them). Load what
|
|
272
|
+
* a rule needs in a `beforeAction` hook and read it from the request.
|
|
273
|
+
*
|
|
274
|
+
* A nested namespace follows its parent namespace's rules unless its
|
|
275
|
+
* `ApplicationController` declares its own — whether that class extends
|
|
276
|
+
* `Controller` or the parent's `ApplicationController`, and also when the
|
|
277
|
+
* namespace has no `ApplicationController`. Replace them, or build on them
|
|
278
|
+
* through `super` in a class that extends the parent's:
|
|
279
|
+
*
|
|
280
|
+
* ```javascript
|
|
281
|
+
* // app/controllers/admin/application.js
|
|
282
|
+
* class AdminApplicationController extends Controller {
|
|
283
|
+
* static visibility = {}; // admins see everything
|
|
284
|
+
* }
|
|
285
|
+
*
|
|
286
|
+
* // app/controllers/members/application.js
|
|
287
|
+
* class MembersApplicationController extends ApplicationController {
|
|
288
|
+
* static visibility = { ...super.visibility, drafts: … };
|
|
289
|
+
* }
|
|
290
|
+
* ```
|
|
291
|
+
*
|
|
292
|
+
* Declaring `visibility` on any other controller is a boot error: types are
|
|
293
|
+
* included across controllers, so a rule must hold for the whole
|
|
294
|
+
* namespace.
|
|
295
|
+
*
|
|
296
|
+
* Rules do not apply to queries an application builds itself, such as a
|
|
297
|
+
* custom action's `Post.where(...)` or a relationship read from a model
|
|
298
|
+
* (`await post.comments`). Narrow those with `visible()`.
|
|
299
|
+
*
|
|
300
|
+
* **Visibility rules and model scopes**
|
|
301
|
+
*
|
|
302
|
+
* A model scope (`static scopes` on a Model, e.g. `Post.isPublic()`) is a
|
|
303
|
+
* reusable piece of a query: it narrows the one query it is called on, and
|
|
304
|
+
* only when application code calls it. A visibility rule is an access
|
|
305
|
+
* policy: Lumen applies it to every query it issues for a request. The two
|
|
306
|
+
* compose — a rule is usually written with a scope.
|
|
307
|
+
*
|
|
308
|
+
* | | Model scope | Visibility rule |
|
|
309
|
+
* |-------------------|----------------------|-------------------------|
|
|
310
|
+
* | Declared on | the Model | a namespace's |
|
|
311
|
+
* | | | `ApplicationController` |
|
|
312
|
+
* | Applied | where code calls it | to every query Lumen |
|
|
313
|
+
* | | | issues for the request |
|
|
314
|
+
* | Sees the request | no | yes |
|
|
315
|
+
* | Per namespace | no | yes |
|
|
316
|
+
* | May use | any query method | conditions only |
|
|
317
|
+
* | `unscope()` | removes it | cannot remove it |
|
|
318
|
+
*
|
|
319
|
+
* Scoping a built-in action is not the same as hiding records. With
|
|
320
|
+
*
|
|
321
|
+
* ```javascript
|
|
322
|
+
* class PostsController extends Controller {
|
|
323
|
+
* index(request) {
|
|
324
|
+
* return super.index(request).isPublic();
|
|
325
|
+
* }
|
|
326
|
+
* }
|
|
327
|
+
* ```
|
|
328
|
+
*
|
|
329
|
+
* private posts are left out of `GET /posts`, but are still served by
|
|
330
|
+
* `GET /posts/:id`, listed in the `posts` linkage of a user and in
|
|
331
|
+
* `included` for `/users?include=posts`, linked from a comment's `post`,
|
|
332
|
+
* and accepted as the `post` of a new comment. `posts: query =>
|
|
333
|
+
* query.isPublic()` as a visibility rule closes every one of those paths.
|
|
334
|
+
*
|
|
335
|
+
* A namespace without rules, its own or a parent's, gets conservative
|
|
336
|
+
* defaults: `maxIncludeDepth` is `0` (no includes), resources serve no
|
|
337
|
+
* relationship or related endpoints unless they ask for them, and the app
|
|
338
|
+
* warns at boot. `static visibility = {}` declares that a namespace may see
|
|
339
|
+
* everything, and lifts them.
|
|
340
|
+
*/
|
|
341
|
+
static visibility: Visibility;
|
|
342
|
+
/**
|
|
343
|
+
* Narrow `query` with the visibility rule for its type that applies to
|
|
344
|
+
* `request`'s namespace, as the built-in actions do.
|
|
345
|
+
*
|
|
346
|
+
* ```javascript
|
|
347
|
+
* class PostsController extends Controller {
|
|
348
|
+
* drafts(request) {
|
|
349
|
+
* return this.visible(Post.where({ isPublic: false }), request);
|
|
350
|
+
* }
|
|
351
|
+
* }
|
|
352
|
+
* ```
|
|
353
|
+
*
|
|
354
|
+
* @param query - A query of any type.
|
|
355
|
+
* @param request - The request object.
|
|
356
|
+
* @returns The same query, narrowed.
|
|
357
|
+
*/
|
|
358
|
+
visible<Q extends Query<unknown>>(query: Q, request: Request): Q;
|
|
359
|
+
/**
|
|
360
|
+
* The Serializer to serialize (and validate the `fields` of) related
|
|
361
|
+
* resources of this Controller's responses with: the related model's
|
|
362
|
+
* Serializer in this Controller's namespace, falling back to the root one.
|
|
502
363
|
*
|
|
503
364
|
* Always this Controller's namespace — not its Serializer's, which is the
|
|
504
365
|
* root one when the namespace has no Serializer for this resource.
|
|
505
366
|
*
|
|
506
|
-
* @
|
|
507
|
-
* @private
|
|
367
|
+
* @internal
|
|
508
368
|
*/
|
|
509
369
|
serializerFor(model: ModelClass): Serializer<Model>;
|
|
510
370
|
/**
|
|
511
371
|
* The resolved Model for a Controller instance.
|
|
512
372
|
*
|
|
513
|
-
* @
|
|
514
|
-
* @type {Model}
|
|
515
|
-
* @private
|
|
373
|
+
* @internal
|
|
516
374
|
*/
|
|
517
375
|
model: ModelClass<Model>;
|
|
518
376
|
/**
|
|
519
377
|
* A reference to the root Controller for the namespace that a Controller
|
|
520
378
|
* instance is a member of.
|
|
521
379
|
*
|
|
522
|
-
* @
|
|
523
|
-
* @type {?Controller}
|
|
524
|
-
* @private
|
|
380
|
+
* @internal
|
|
525
381
|
*/
|
|
526
382
|
parent: Controller | null;
|
|
527
383
|
/**
|
|
528
384
|
* The namespace that a Controller instance is a member of.
|
|
529
385
|
*
|
|
530
|
-
* @
|
|
531
|
-
* @type {String}
|
|
532
|
-
* @private
|
|
386
|
+
* @internal
|
|
533
387
|
*/
|
|
534
388
|
namespace: string;
|
|
535
389
|
/**
|
|
536
390
|
* The resolved Serializer for a Controller instance.
|
|
537
391
|
*
|
|
538
|
-
* @
|
|
539
|
-
* @type {Serializer}
|
|
540
|
-
* @private
|
|
392
|
+
* @internal
|
|
541
393
|
*/
|
|
542
394
|
serializer: Serializer<Model>;
|
|
543
395
|
/**
|
|
544
396
|
* A Map instance containing a reference to all the Controller within an
|
|
545
397
|
* Application instance.
|
|
546
398
|
*
|
|
547
|
-
* @
|
|
548
|
-
* @type {Map}
|
|
549
|
-
* @private
|
|
399
|
+
* @internal
|
|
550
400
|
*/
|
|
551
401
|
controllers: Map<string, Controller>;
|
|
402
|
+
/**
|
|
403
|
+
* The visibility rules of this Controller's namespace, resolved at boot
|
|
404
|
+
* from the `static visibility` of the closest `ApplicationController`, from
|
|
405
|
+
* its own namespace's up, that declares rules.
|
|
406
|
+
*
|
|
407
|
+
* @internal
|
|
408
|
+
*/
|
|
409
|
+
visibility: Visibility;
|
|
410
|
+
/**
|
|
411
|
+
* Whether this Controller's namespace, or one it is nested in, declares
|
|
412
|
+
* visibility rules — `static visibility = {}` included. Without any, the
|
|
413
|
+
* namespace gets conservative defaults (see `restrictOpenNamespaces()`).
|
|
414
|
+
* Resolved at boot.
|
|
415
|
+
*
|
|
416
|
+
* @internal
|
|
417
|
+
*/
|
|
418
|
+
hasVisibilityRules: boolean;
|
|
552
419
|
/**
|
|
553
420
|
* A boolean value representing whether or not a Controller instance has a
|
|
554
421
|
* Model.
|
|
555
422
|
*
|
|
556
|
-
* @
|
|
557
|
-
* @type {Boolean}
|
|
558
|
-
* @private
|
|
423
|
+
* @internal
|
|
559
424
|
*/
|
|
560
425
|
hasModel: boolean;
|
|
561
426
|
/**
|
|
562
427
|
* A boolean value representing whether or not a Controller instance is within
|
|
563
428
|
* a namespace.
|
|
564
429
|
*
|
|
565
|
-
* @
|
|
566
|
-
* @type {Boolean}
|
|
567
|
-
* @private
|
|
430
|
+
* @internal
|
|
568
431
|
*/
|
|
569
432
|
hasNamespace: boolean;
|
|
570
433
|
/**
|
|
571
434
|
* A boolean value representing whether or not a Controller instance has a
|
|
572
435
|
* Serializer.
|
|
573
436
|
*
|
|
574
|
-
* @
|
|
575
|
-
* @type {Boolean}
|
|
576
|
-
* @private
|
|
437
|
+
* @internal
|
|
577
438
|
*/
|
|
578
439
|
hasSerializer: boolean;
|
|
579
|
-
constructor({ model, namespace, serializer }:
|
|
440
|
+
constructor({ model, namespace, serializer }: ControllerOptions);
|
|
580
441
|
/**
|
|
581
|
-
*
|
|
582
|
-
*
|
|
583
|
-
* information, see the [fetching resources](https://goo.gl/q7FVgZ) section of
|
|
584
|
-
* the JSON API specification.
|
|
442
|
+
* `GET /posts`: the records, sorted, filtered and paged by the request's
|
|
443
|
+
* query parameters, with its `include` and `fields`. Visibility rules apply.
|
|
585
444
|
*
|
|
586
|
-
* @
|
|
587
|
-
* @param
|
|
588
|
-
*
|
|
589
|
-
* @
|
|
590
|
-
* @public
|
|
445
|
+
* @param request - The request.
|
|
446
|
+
* @param response - The response. Unused by the built-in action, but every
|
|
447
|
+
* action is called with it, so an override can take it.
|
|
448
|
+
* @returns A query of the page of records; narrow it in an override.
|
|
591
449
|
*/
|
|
592
|
-
index(
|
|
450
|
+
index(request: Request, response?: Response): Query<Array<Model>>;
|
|
593
451
|
/**
|
|
594
|
-
*
|
|
595
|
-
*
|
|
596
|
-
*
|
|
597
|
-
*
|
|
598
|
-
* @
|
|
599
|
-
* @param
|
|
600
|
-
*
|
|
601
|
-
* @
|
|
602
|
-
* id url parameter.
|
|
603
|
-
* @public
|
|
452
|
+
* `GET /posts/1`: the record with the route's id, with the request's
|
|
453
|
+
* `include` and `fields`. Visibility rules apply; a record the request may
|
|
454
|
+
* not see, like a missing one, is a `404 Not Found`.
|
|
455
|
+
*
|
|
456
|
+
* @param request - The request.
|
|
457
|
+
* @param response - The response. Unused by the built-in action, but every
|
|
458
|
+
* action is called with it, so an override can take it.
|
|
459
|
+
* @returns A query of the record; narrow it in an override.
|
|
604
460
|
*/
|
|
605
|
-
show(
|
|
461
|
+
show(request: Request, response?: Response): Query<Model>;
|
|
606
462
|
/**
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
463
|
+
* `GET /posts/1/relationships/comments`, a relationship endpoint: resolves
|
|
464
|
+
* the resource that owns the relationship (`request.route.relationship`),
|
|
465
|
+
* whose resource linkage is the response.
|
|
466
|
+
*
|
|
467
|
+
* The resource is resolved through this controller's `show`, asking for its
|
|
468
|
+
* primary key only, so whatever `show` enforces holds here too: an override
|
|
469
|
+
* that narrows its query or rejects the request applies, and a resource the
|
|
470
|
+
* request may not see is a `404 Not Found`. Hooks see the action
|
|
471
|
+
* `showRelationship` (`request.route.type` is `relationship`).
|
|
472
|
+
*
|
|
473
|
+
* @param request - The request.
|
|
474
|
+
* @param response - The response. Unused by the built-in action, but every
|
|
475
|
+
* action is called with it, so an override can take it.
|
|
476
|
+
* @returns A query of the owning record.
|
|
616
477
|
*/
|
|
617
|
-
|
|
478
|
+
showRelationship(request: Request, response?: Response): Query<Model>;
|
|
618
479
|
/**
|
|
619
|
-
*
|
|
620
|
-
*
|
|
621
|
-
*
|
|
622
|
-
*
|
|
623
|
-
*
|
|
624
|
-
*
|
|
625
|
-
*
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
*
|
|
480
|
+
* `GET /posts/1/comments`, a related endpoint: the resources the
|
|
481
|
+
* relationship `request.route.relationship` of the record with the route's id
|
|
482
|
+
* points to.
|
|
483
|
+
*
|
|
484
|
+
* The query parameters are those of the related type's controller: for a
|
|
485
|
+
* to-many relationship they page, sort and filter like its `index`, for a
|
|
486
|
+
* to-one one they include and select like its `show`. Visibility rules apply
|
|
487
|
+
* to the related resources; the owning record is resolved with
|
|
488
|
+
* {@link Controller.showRelationship} first, so one the request may not see
|
|
489
|
+
* is a `404 Not Found`. Hooks see the action `showRelated`
|
|
490
|
+
* (`request.route.type` is `related`).
|
|
491
|
+
*
|
|
492
|
+
* @param request - The request.
|
|
493
|
+
* @param response - The response. Unused by the built-in action, but every
|
|
494
|
+
* action is called with it, so an override can take it.
|
|
495
|
+
* @returns A query of the related records (to-many), or of the related record
|
|
496
|
+
* (to-one, resolving with `undefined` when there is none).
|
|
497
|
+
*/
|
|
498
|
+
showRelated(request: Request, response?: Response): Query<Array<Model>> | Query<Model>;
|
|
499
|
+
/**
|
|
500
|
+
* `POST /posts`: creates a record from the request body's attributes and
|
|
501
|
+
* relationships, after checking that every related record exists and is
|
|
502
|
+
* visible (a `404 Not Found` otherwise). Answers `201 Created` with a
|
|
503
|
+
* `Location` header.
|
|
504
|
+
*
|
|
505
|
+
* @param request - The request.
|
|
506
|
+
* @param response - The response, for the status and `Location` header.
|
|
507
|
+
* @returns Resolves with the new record.
|
|
508
|
+
*/
|
|
509
|
+
create(request: Request, response: Response): Promise<Model>;
|
|
510
|
+
/**
|
|
511
|
+
* `PATCH /posts/1`: updates the record with the route's id from the request
|
|
512
|
+
* body, after checking that every related record exists and is visible.
|
|
513
|
+
* A record the request may not see is a `404 Not Found`.
|
|
514
|
+
*
|
|
515
|
+
* @param request - The request.
|
|
516
|
+
* @param response - The response. Unused by the built-in action, but every
|
|
517
|
+
* action is called with it, so an override can take it.
|
|
518
|
+
* @returns Resolves with the updated record, or with `204` (`204 No Content`)
|
|
519
|
+
* when nothing changed.
|
|
629
520
|
*/
|
|
630
|
-
update(
|
|
521
|
+
update(request: Request, response?: Response): Promise<number | Model>;
|
|
631
522
|
/**
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
* section of the JSON API specification.
|
|
523
|
+
* `DELETE /posts/1`: deletes the record with the route's id. A record the
|
|
524
|
+
* request may not see is a `404 Not Found`.
|
|
635
525
|
*
|
|
636
|
-
* @
|
|
637
|
-
* @param
|
|
638
|
-
*
|
|
639
|
-
* @
|
|
640
|
-
* @public
|
|
526
|
+
* @param request - The request.
|
|
527
|
+
* @param response - The response. Unused by the built-in action, but every
|
|
528
|
+
* action is called with it, so an override can take it.
|
|
529
|
+
* @returns Resolves with `204` (`204 No Content`).
|
|
641
530
|
*/
|
|
642
|
-
destroy(
|
|
531
|
+
destroy(request: Request, response?: Response): Promise<number>;
|
|
643
532
|
/**
|
|
644
|
-
*
|
|
533
|
+
* Answers `OPTIONS` requests: `204 No Content`, with the path's methods in
|
|
534
|
+
* `Allow`.
|
|
645
535
|
*
|
|
646
|
-
* @
|
|
647
|
-
* @param
|
|
648
|
-
*
|
|
649
|
-
* @
|
|
650
|
-
* @public
|
|
536
|
+
* @param request - The request. Unused.
|
|
537
|
+
* @param response - The response. Unused by the built-in action, but every
|
|
538
|
+
* action is called with it, so an override can take it.
|
|
539
|
+
* @returns Resolves with `204`.
|
|
651
540
|
*/
|
|
652
|
-
preflight(): Promise<number>;
|
|
541
|
+
preflight(request?: Request, response?: Response): Promise<number>;
|
|
653
542
|
}
|
|
654
543
|
export default Controller;
|
|
655
|
-
export { BUILT_IN_ACTIONS } from './constants';
|
|
656
|
-
export
|
|
544
|
+
export { BUILT_IN_ACTIONS, NAMESPACE_SETTINGS } from './constants';
|
|
545
|
+
export { Scope } from './visibility';
|
|
546
|
+
export type { Visibility } from './visibility';
|
|
547
|
+
export type { ControllerOptions, BuiltInAction, BeforeAction, AfterAction } from './interfaces';
|