mirror of https://gitee.com/bigwinds/arangodb
Added Development chapter for new foxx documentation
This commit is contained in:
parent
a4795ee04c
commit
d0a22c6938
|
@ -0,0 +1,325 @@
|
||||||
|
!CHAPTER Details on FoxxController
|
||||||
|
|
||||||
|
!SUBSECTION Create
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_initializer
|
||||||
|
|
||||||
|
!SECTION HTTP Methods
|
||||||
|
|
||||||
|
!SUBSECTION get
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_get
|
||||||
|
|
||||||
|
!SUBSECTION head
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_head
|
||||||
|
|
||||||
|
!SUBSECTION post
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_post
|
||||||
|
|
||||||
|
!SUBSECTION put
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_put
|
||||||
|
|
||||||
|
!SUBSECTION patch
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_patch
|
||||||
|
|
||||||
|
!SUBSECTION delete
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_delete
|
||||||
|
|
||||||
|
!SECTION Documenting and constraining a specific route
|
||||||
|
|
||||||
|
If you now want to document your route, you can use JSDoc style comments (a
|
||||||
|
multiline comment block with the first line starting with */*** instead
|
||||||
|
of */**) above your routes to do that:
|
||||||
|
|
||||||
|
```js
|
||||||
|
/** Get all foxxes
|
||||||
|
*
|
||||||
|
* If you want to get all foxxes, please use this
|
||||||
|
* method to do that.
|
||||||
|
*/
|
||||||
|
app.get("/foxxes", function () {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
The first line will be treated as a summary (For optical reasons in the
|
||||||
|
produced documentation, the summary is restricted to 60 characters). All
|
||||||
|
following lines will be treated as additional notes shown in the detailed
|
||||||
|
view of the route documentation. With the provided information, Foxx will
|
||||||
|
generate a nice documentation for you. Furthermore you can describe your
|
||||||
|
API by chaining the following methods onto your path definition:
|
||||||
|
|
||||||
|
!SUBSECTION pathParam
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/request_context.js -->
|
||||||
|
@startDocuBlock JSF_foxx_RequestContext_pathParam
|
||||||
|
|
||||||
|
!SUBSECTION queryParam
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/request_context.js -->
|
||||||
|
@startDocuBlock JSF_foxx_RequestContext_queryParam
|
||||||
|
|
||||||
|
!SUBSECTION bodyParam
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/request_context.js -->
|
||||||
|
@startDocuBlock JSF_foxx_RequestContext_bodyParam
|
||||||
|
|
||||||
|
!SUBSECTION errorResponse
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/request_context.js -->
|
||||||
|
@startDocuBlock JSF_foxx_RequestContext_errorResponse
|
||||||
|
|
||||||
|
!SUBSECTION onlyif
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/request_context.js -->
|
||||||
|
@startDocuBlock JSF_foxx_RequestContext_onlyIf
|
||||||
|
|
||||||
|
!SUBSECTION onlyIfAuthenticated
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/request_context.js -->
|
||||||
|
@startDocuBlock JSF_foxx_RequestContext_onlyIfAuthenticated
|
||||||
|
|
||||||
|
!SECTION Documenting and constraining all routes
|
||||||
|
|
||||||
|
In addition to documenting a specific route, you can also
|
||||||
|
do the same for all routes of a controller. For this purpose
|
||||||
|
use the *allRoutes* object of the according controller.
|
||||||
|
The following methods are available.
|
||||||
|
|
||||||
|
*Examples*
|
||||||
|
|
||||||
|
Provide an error response for all routes handled by this controller:
|
||||||
|
|
||||||
|
```js
|
||||||
|
ctrl.allRoutes
|
||||||
|
.errorResponse(Unauthorized, 401, 'Not authenticated.')
|
||||||
|
.errorResponse(NotFound, 404, 'Document not found.')
|
||||||
|
.errorResponse(ImATeapot, 418, 'I\'m a teapot.');
|
||||||
|
|
||||||
|
ctrl.get('/some/route', function (req, res) {
|
||||||
|
// ...
|
||||||
|
throw new NotFound('The document does not exist');
|
||||||
|
// ...
|
||||||
|
}); // no errorResponse needed here
|
||||||
|
|
||||||
|
ctrl.get('/another/route', function (req, res) {
|
||||||
|
// ...
|
||||||
|
throw new NotFound('I made you a cookie but I ated it');
|
||||||
|
// ...
|
||||||
|
}); // no errorResponse needed here either
|
||||||
|
```
|
||||||
|
|
||||||
|
!SUBSECTION Buffer errorResponse
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/request_context.js -->
|
||||||
|
@startDocuBlock JSF_foxx_RequestContextBuffer_errorResponse
|
||||||
|
|
||||||
|
!SUBSECTION Buffer onlyIf
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/request_context.js -->
|
||||||
|
@startDocuBlock JSF_foxx_RequestContextBuffer_onlyIf
|
||||||
|
|
||||||
|
!SUBSECTION Buffer onlyIfAuthenticated
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/request_context.js -->
|
||||||
|
@startDocuBlock JSF_foxx_RequestContextBuffer_onlyIfAuthenticated
|
||||||
|
|
||||||
|
|
||||||
|
!SECTION Before and After Hooks
|
||||||
|
|
||||||
|
You can use the following two functions to do something before or respectively
|
||||||
|
after the normal routing process is happening. You could use that for logging
|
||||||
|
or to manipulate the request or response (translate it to a certain format for
|
||||||
|
example).
|
||||||
|
|
||||||
|
!SUBSECTION before
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_before
|
||||||
|
|
||||||
|
!SUBSECTION after
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_after
|
||||||
|
|
||||||
|
!SUBSECTION around
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_around
|
||||||
|
|
||||||
|
|
||||||
|
!SECTION The Request and Response Objects
|
||||||
|
|
||||||
|
When you have created your FoxxController you can now define routes on it.
|
||||||
|
You provide each with a function that will handle the request. It gets two
|
||||||
|
arguments (four, to be honest. But the other two are not relevant for now):
|
||||||
|
|
||||||
|
* The *request* object
|
||||||
|
* The *response* object
|
||||||
|
|
||||||
|
These objects are provided by the underlying ArangoDB actions and enhanced
|
||||||
|
by the *BaseMiddleware* provided by Foxx.
|
||||||
|
|
||||||
|
!SUBSECTION The Request Object
|
||||||
|
|
||||||
|
The *request* object inherits several attributes from the underlying Actions:
|
||||||
|
|
||||||
|
* *compatibility*: an integer specifying the compatibility version sent by the
|
||||||
|
client (in request header *x-arango-version*). If the client does not send this
|
||||||
|
header, ArangoDB will set this to the minimum compatible version number. The
|
||||||
|
value is 10000 * major + 100 * minor (e.g. *10400* for ArangoDB version 1.4).
|
||||||
|
|
||||||
|
* *user*: the name of the current ArangoDB user. This will be populated only
|
||||||
|
if authentication is turned on, and will be *null* otherwise.
|
||||||
|
|
||||||
|
* *database*: the name of the current database (e.g. *_system*)
|
||||||
|
|
||||||
|
* *protocol*: *http* or *https*
|
||||||
|
|
||||||
|
* *server*: a JSON object with sub-attributes *address* (containing server
|
||||||
|
host name or IP address) and *port* (server port).
|
||||||
|
|
||||||
|
* *path*: request URI path, with potential [database name](../Glossary/README.html#database_name) stripped off.
|
||||||
|
|
||||||
|
* *url*: request URI path + query string, with potential database name
|
||||||
|
stripped off
|
||||||
|
|
||||||
|
* *headers*: a JSON object with the request headers as key/value pairs.
|
||||||
|
**Note:** All header field names are lower-cased
|
||||||
|
|
||||||
|
* *cookies*: a JSON object with the request cookies as key/value pairs
|
||||||
|
|
||||||
|
* *requestType*: the request method (e.g. "GET", "POST", "PUT", ...)
|
||||||
|
|
||||||
|
* *requestBody*: the complete body of the request as a string
|
||||||
|
|
||||||
|
* *parameters*: a JSON object with all parameters set in the URL as key/value
|
||||||
|
pairs
|
||||||
|
|
||||||
|
* *urlParameters*: a JSON object with all named parameters defined for the
|
||||||
|
route as key/value pairs.
|
||||||
|
|
||||||
|
In addition to these attributes, a Foxx request objects provides the following
|
||||||
|
convenience methods:
|
||||||
|
|
||||||
|
!SUBSECTION body
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/base_middleware.js -->
|
||||||
|
@startDocuBlock JSF_foxx_BaseMiddleware_request_body
|
||||||
|
|
||||||
|
!SUBSECTION rawBody
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/base_middleware.js -->
|
||||||
|
@startDocuBlock JSF_foxx_BaseMiddleware_request_rawBody
|
||||||
|
|
||||||
|
!SUBSECTION rawBodyBuffer
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/base_middleware.js -->
|
||||||
|
@startDocuBlock JSF_foxx_BaseMiddleware_request_rawBodyBuffer
|
||||||
|
|
||||||
|
!SUBSECTION params
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/base_middleware.js -->
|
||||||
|
@startDocuBlock JSF_foxx_BaseMiddleware_request_params
|
||||||
|
|
||||||
|
!SUBSECTION cookie
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/base_middleware.js -->
|
||||||
|
@startDocuBlock JSF_foxx_BaseMiddleware_request_cookie
|
||||||
|
|
||||||
|
|
||||||
|
!SECTION The Response Object
|
||||||
|
|
||||||
|
Every response object has the body attribute from the underlying Actions
|
||||||
|
to set the raw body by hand.
|
||||||
|
|
||||||
|
You provide your response body as a string here.
|
||||||
|
|
||||||
|
!SUBSECTION Response status
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/base_middleware.js -->
|
||||||
|
@startDocuBlock JSF_foxx_BaseMiddleware_response_status
|
||||||
|
|
||||||
|
!SUBSECTION Response set
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/base_middleware.js -->
|
||||||
|
@startDocuBlock JSF_foxx_BaseMiddleware_response_set
|
||||||
|
|
||||||
|
!SUBSECTION Response json
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/base_middleware.js -->
|
||||||
|
@startDocuBlock JSF_foxx_BaseMiddleware_response_json
|
||||||
|
|
||||||
|
!SUBSECTION Response cookie
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/base_middleware.js -->
|
||||||
|
@startDocuBlock JSF_foxx_BaseMiddleware_response_cookie
|
||||||
|
|
||||||
|
!SUBSECTION Response send
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/base_middleware.js -->
|
||||||
|
@startDocuBlock JSF_foxx_BaseMiddleware_response_send
|
||||||
|
|
||||||
|
!SUBSECTION Response sendFile
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/base_middleware.js -->
|
||||||
|
@startDocuBlock JSF_foxx_BaseMiddleware_response_sendFile
|
||||||
|
|
||||||
|
!SECTION Controlling Access to Foxx Applications
|
||||||
|
|
||||||
|
Access to Foxx applications is controlled by the regular authentication mechanisms
|
||||||
|
present in ArangoDB. The server can be run with or without HTTP authentication.
|
||||||
|
|
||||||
|
If authentication is turned on,
|
||||||
|
then every access to the server is authenticated via HTTP authentication. This
|
||||||
|
includes Foxx applications. The global authentication can be toggled
|
||||||
|
via the configuration option.
|
||||||
|
|
||||||
|
If global HTTP authentication is turned on, requests to Foxx applications will
|
||||||
|
require HTTP authentication too, and only valid users present in the *_users*
|
||||||
|
system collection are allowed to use the applications.
|
||||||
|
|
||||||
|
Since ArangoDB 1.4, there is an extra option to restrict the authentication to
|
||||||
|
just system API calls, such as */_api/...* and */_admin/...*. This option can be
|
||||||
|
turned on using the
|
||||||
|
"server.authenticate-system-only" configuration option. If it is turned on,
|
||||||
|
then only system API requests need authentication whereas all requests to Foxx
|
||||||
|
applications and routes will not require authentication.
|
||||||
|
|
||||||
|
This is recommended if you want to disable HTTP authentication for Foxx applications
|
||||||
|
but still want the general database APIs to be protected with HTTP authentication.
|
||||||
|
|
||||||
|
If you need more fine grained control over the access to your Foxx application,
|
||||||
|
we built an authentication system you can use. Currently we only support cookie-based
|
||||||
|
authentication, but we will add the possibility to use Auth Tokens and external OAuth
|
||||||
|
providers in the near future. Of course you can roll your own authentication mechanism
|
||||||
|
if you want to, and you can do it in an application-specific way if required.
|
||||||
|
|
||||||
|
To use the per-application authentication, you should first turn off the global
|
||||||
|
HTTP authentication (or at least restrict it to system API calls as mentioned above).
|
||||||
|
Otherwise clients will need HTTP authentication and need additional authentication by
|
||||||
|
your Foxx application.
|
||||||
|
|
||||||
|
To have global HTTP authentication turned on for system APIs but turned off for Foxx,
|
||||||
|
your server startup parameters should look like this:
|
||||||
|
|
||||||
|
--server.disable-authentication false --server.authenticate-system-only true
|
||||||
|
|
||||||
|
**Note**: During development, you may even turn off HTTP authentication completely:
|
||||||
|
|
||||||
|
--server.disable-authentication true --server.authenticate-system-only true
|
||||||
|
|
||||||
|
Please keep in mind that turning HTTP authentication off completely will allow
|
||||||
|
unauthenticated access by anyone to all API functions, so do not use this is production.
|
||||||
|
|
||||||
|
Now it's time to configure the application-specific authentication. We built a small
|
||||||
|
[demo application](https://github.com/arangodb/foxx-authentication) to demonstrate how
|
||||||
|
this works.
|
||||||
|
|
||||||
|
To use the application-specific authentication in your own app, first activate it in your controller.
|
||||||
|
|
||||||
|
!SUBSECTION Active Authentication
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_activateAuthentication
|
||||||
|
|
||||||
|
!SUBSECTION Login
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_login
|
||||||
|
|
||||||
|
!SUBSECTION Logout
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_logout
|
||||||
|
|
||||||
|
!SUBSECTION Register
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_register
|
||||||
|
|
||||||
|
!SUBSECTION Change Password
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/controller.js -->
|
||||||
|
@startDocuBlock JSF_foxx_controller_changePassword
|
||||||
|
|
||||||
|
!SUBSUBSECTION Restricting routes
|
||||||
|
|
||||||
|
To restrict routes, see the documentation for Documenting and Restraining the routes.
|
|
@ -0,0 +1,10 @@
|
||||||
|
!Available Debugging mechanisms
|
||||||
|
|
||||||
|
<dt>Installation error on Mountpoint</dt>
|
||||||
|
<dl>
|
||||||
|
If your application cannot be installed, e.g. it contains syntactic errors, you will get the error description and the stacktrace on any request to a route within the mount point.
|
||||||
|
</dl>
|
||||||
|
<dt>Error Stacktraces on routes</dt>
|
||||||
|
<dl>
|
||||||
|
If your application could be installed but contains an unhandled error on a specific route, the request for this route will return the error message as well as the stacktrace.
|
||||||
|
</dl>
|
|
@ -0,0 +1,51 @@
|
||||||
|
!CHAPTER Application Development Mode
|
||||||
|
|
||||||
|
This chapter describes the development mode for Foxx applications.
|
||||||
|
It is only useful if you have write access to the files in ArangoDB's application folder.
|
||||||
|
The folder is located at `TODO!` by default and can be reconfigured using the startup option `--javascript.app-path`.
|
||||||
|
If you do not have access to this folder, e.g. using a hosted service like [myArangoDB](https://myarangodb.com/), you cannot make use of this feature.
|
||||||
|
You will have to stick to the procedure described in [New Versions](../Production/Upgrade).
|
||||||
|
<div class="versionDifference">
|
||||||
|
Before 2.5 the startup option `--javascript.dev-app-path` was required for the development mode.
|
||||||
|
This caused a lot of confusion and introduced problems when moving from development to production.
|
||||||
|
So we decided to unify both app paths and activate development mode for specific Apps during runtime.
|
||||||
|
The `--javascript.dev-app-path` parameter is not having any effect any more.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
!SECTION Activation
|
||||||
|
|
||||||
|
Activating the development mode is done with a single command:
|
||||||
|
|
||||||
|
unix> foxx-manager development /example
|
||||||
|
Activated development mode for Application hello-foxx version 1.5.0 on mount point /example
|
||||||
|
|
||||||
|
Now the app will *list* itself as a development app:
|
||||||
|
|
||||||
|
unix> foxx-manager list
|
||||||
|
Mount Name Author Description Version Development
|
||||||
|
--------------------- ------------ -------------- ----------------------------------------------- -------- ------------
|
||||||
|
/_admin/aardvark aardvark ArangoDB GmbH ArangoDB Admin Web Interface 1.0 false
|
||||||
|
/_api/gharial gharial ArangoDB GmbH ArangoDB Graph Module 0.1 false
|
||||||
|
/_system/cerberus cerberus ArangoDB GmbH Password Manager 0.0.1 false
|
||||||
|
/_system/sessions sessions ArangoDB GmbH Session storage for Foxx. 0.1 false
|
||||||
|
/_system/simple-auth simple-auth ArangoDB GmbH Simple password-based authentication for Foxx. 0.1 false
|
||||||
|
/example hello-foxx Frank Celler This is 'Hello World' for ArangoDB Foxx. 1.5.0 true
|
||||||
|
--------------------- ------------ -------------- ----------------------------------------------- -------- ------------
|
||||||
|
6 application(s) found
|
||||||
|
|
||||||
|
!SECTION Effects
|
||||||
|
|
||||||
|
For a Foxx application in development mode the following effects apply:
|
||||||
|
<dl>
|
||||||
|
<dt>Reload on request</dt>
|
||||||
|
<dl>
|
||||||
|
Whenever a request is routed to this application it's source is reloaded.
|
||||||
|
This means all requests are slightly slower than in production mode.
|
||||||
|
But you will get immediate live updates on your code changes.
|
||||||
|
</dl>
|
||||||
|
<dt>Exposed Debugging information</dt>
|
||||||
|
<dl>
|
||||||
|
This application will deliver error messages and stack traces to requesting client.
|
||||||
|
For more information see the [Debugging](Debugging.md) section.
|
||||||
|
</dl>
|
||||||
|
</dl>
|
|
@ -0,0 +1,5 @@
|
||||||
|
!CHAPTER Folder Structure
|
||||||
|
|
||||||
|
Now we are almost ready to write some code.
|
||||||
|
Hence it is time to introduce the folder structure created by Foxx.
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
!CHAPTER The Manifest File
|
||||||
|
|
||||||
|
In the *manifest.json* you define the components of your application.
|
||||||
|
The content is a JSON object with the following attributes (not all
|
||||||
|
attributes are required though):
|
||||||
|
|
||||||
|
* *assets*: Deliver pre-processed files
|
||||||
|
* *author*: The author name
|
||||||
|
* *contributors*: An array containing objects, each represents a contributor (with *name* and optional *email*)
|
||||||
|
* *controllers*: Map routes to FoxxControllers
|
||||||
|
* *exports*: Map names to Foxx exports
|
||||||
|
* *defaultDocument*: The default document when the applicated root (*/*) is called (defaults to *index.html*)
|
||||||
|
* *description*: A short description of the application (Meta information)
|
||||||
|
* *engines*: Should be an object with *arangodb* set to the ArangoDB version your Foxx app is compatible with.
|
||||||
|
* *files*: Deliver files
|
||||||
|
* *isSystem*: Mark an application as a system application
|
||||||
|
* *keywords*: An array of keywords to help people find your Foxx app
|
||||||
|
* *lib*: Base path for all required modules
|
||||||
|
* *license*: Short form of the license (MIT, GPL...)
|
||||||
|
* *name*: Name of the application (Meta information)
|
||||||
|
* *repository*: An object with information about where you can find the repository: *type* and *url*
|
||||||
|
* *setup*: Path to a setup script
|
||||||
|
* *teardown*: Path to a teardown script
|
||||||
|
* *thumbnail*: Path to a thumbnail that represents the application (Meta information)
|
||||||
|
* *version*: Current version of the application (Meta information)
|
||||||
|
|
||||||
|
If you install an application using the Foxx manager or are using the
|
||||||
|
development mode, your manifest will be checked for completeness and common errors.
|
||||||
|
You should have a look at the server log files after changing a manifest file to
|
||||||
|
get informed about potential errors in the manifest.
|
||||||
|
|
||||||
|
A more complete example for a Manifest file:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"name": "my_website",
|
||||||
|
"version": "1.2.1",
|
||||||
|
"description": "My Website with a blog and a shop",
|
||||||
|
"thumnail": "images/website-logo.png",
|
||||||
|
|
||||||
|
"controllers": {
|
||||||
|
"/blog": "apps/blog.js",
|
||||||
|
"/shop": "apps/shop.js"
|
||||||
|
},
|
||||||
|
|
||||||
|
"lib": "lib",
|
||||||
|
|
||||||
|
"files": {
|
||||||
|
"/images": "images"
|
||||||
|
},
|
||||||
|
|
||||||
|
"assets": {
|
||||||
|
"application.js": {
|
||||||
|
"files": [
|
||||||
|
"vendor/jquery.js",
|
||||||
|
"assets/javascripts/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"setup": "scripts/setup.js",
|
||||||
|
"teardown": "scripts/teardown.js"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
!SUBSECTION The setup and teardown scripts
|
||||||
|
|
||||||
|
You can provide a path to a JavaScript file that prepares ArangoDB for your
|
||||||
|
application (or respectively removes it entirely). These scripts have access to
|
||||||
|
*appCollection* and *appCollectionName*. Use the *setup* script to create all
|
||||||
|
collections your application needs and fill them with initial data if you want
|
||||||
|
to. Use the *teardown* script to remove all collections you have created.
|
||||||
|
|
||||||
|
Note: the setup script is called on each request in the development mode.
|
||||||
|
If your application needs to set up specific collections, you should always
|
||||||
|
check in the setup script whether they are already there.
|
||||||
|
|
||||||
|
The teardown script is called when an application is uninstalled. It is good
|
||||||
|
practice to drop any collections in the teardown script that the application used
|
||||||
|
exclusively, but this is not enforced. Maybe there are reasons to keep application
|
||||||
|
data even after removing an application. It's up to you to decide what to do.
|
||||||
|
|
||||||
|
!SUBSECTION controllers is an object that matches routes to files
|
||||||
|
|
||||||
|
* The *key* is the route you want to mount at
|
||||||
|
|
||||||
|
* The *value* is the path to the JavaScript file containing the
|
||||||
|
*FoxxController* you want to mount
|
||||||
|
|
||||||
|
You can add multiple controllers in one manifest this way.
|
||||||
|
|
||||||
|
!SUBSECTION The files
|
||||||
|
|
||||||
|
Deliver all files in a certain folder without modifying them. You can deliver
|
||||||
|
text files as well as binaries:
|
||||||
|
|
||||||
|
```js
|
||||||
|
"files": {
|
||||||
|
"/images": "images"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
!SUBSECTION The assets
|
||||||
|
|
||||||
|
The value for the asset key is an object consisting of paths that are matched
|
||||||
|
to the files they are composed of. Let's take the following example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
"assets": {
|
||||||
|
"application.js": {
|
||||||
|
"files": [
|
||||||
|
"vendor/jquery.js",
|
||||||
|
"assets/javascripts/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If a request is made to */application.js* (in development mode), the file
|
||||||
|
array provided will be processed one element at a time. The elements are
|
||||||
|
paths to files (with the option to use wildcards). The files will be
|
||||||
|
concatenated and delivered as a single file.
|
||||||
|
|
||||||
|
The content-type (or mime type) of the HTTP response when requesting
|
||||||
|
*application.js* is automatically determined by looking at the filename
|
||||||
|
extension in the asset name (*application.js* in the above example).
|
||||||
|
If the asset does not have a filename extension, the content-type is
|
||||||
|
determined by looking at the filename extension of the first file in the
|
||||||
|
*files* list. If no file extension can be determined, the asset will be
|
||||||
|
delivered with a content-type of *text/plain*.
|
||||||
|
|
||||||
|
It is possible to explicitly override the content-type for an asset by
|
||||||
|
setting the optional *contentType* attribute of an asset as follows:
|
||||||
|
|
||||||
|
```js
|
||||||
|
"assets": {
|
||||||
|
"myincludes": {
|
||||||
|
"files": [
|
||||||
|
"vendor/jquery.js",
|
||||||
|
"assets/javascripts/*"
|
||||||
|
],
|
||||||
|
"contentType": "text/javascript"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,137 @@
|
||||||
|
!CHAPTER Details on FoxxModel
|
||||||
|
|
||||||
|
The model doesn't know anything about the database. It is just a representation
|
||||||
|
of the data as an JavaScript object. You can add and overwrite the methods of
|
||||||
|
the prototype in your model prototype via the object you give to extend. In
|
||||||
|
your model file, export the model as *model*.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var Foxx = require("org/arangodb/foxx");
|
||||||
|
|
||||||
|
var TodoModel = Foxx.Model.extend({
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.model = TodoModel;
|
||||||
|
```
|
||||||
|
|
||||||
|
A Foxx Model can be initialized with an object of attributes and their values.
|
||||||
|
|
||||||
|
There's also the possibility of annotation: If you extend the model with a
|
||||||
|
*schema* property, the model's attributes will be validated against it.
|
||||||
|
|
||||||
|
You can define attributes in the schema using the bundled *joi* library.
|
||||||
|
For more information on the syntax see [the official joi documentation](https://github.com/spumko/joi).
|
||||||
|
|
||||||
|
```js
|
||||||
|
var Foxx = require("org/arangodb/foxx");
|
||||||
|
var joi = require("joi");
|
||||||
|
|
||||||
|
var PersonModel = Foxx.Model.extend({
|
||||||
|
schema: {
|
||||||
|
name: joi.string().required(),
|
||||||
|
age: joi.number().integer(),
|
||||||
|
active: joi.boolean().default(true)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.model = PersonModel;
|
||||||
|
```
|
||||||
|
|
||||||
|
This has two effects: On the one hand it provides documentation. If you annotated
|
||||||
|
your model, you can use it in the *bodyParam* method for documentation.
|
||||||
|
On the other hand it will influence the behavior of the constructor: If you provide
|
||||||
|
an object to the constructor, it will validate its attributes and set the special
|
||||||
|
*errors* property. This is especially useful if you want to to initialize
|
||||||
|
the Model from user input. On the other hand it will set the default value for all
|
||||||
|
attributes that have not been set by hand. An example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var person = new PersonModel({
|
||||||
|
name: "Pete",
|
||||||
|
admin: true
|
||||||
|
});
|
||||||
|
|
||||||
|
person.attributes // => { name: "Pete", admin: true, active: true }
|
||||||
|
person.errors // => {admin: [ValidationError: value is not allowed]}
|
||||||
|
```
|
||||||
|
|
||||||
|
The following events are emitted by a model:
|
||||||
|
|
||||||
|
- beforeCreate
|
||||||
|
- afterCreate
|
||||||
|
- beforeSave
|
||||||
|
- afterSave
|
||||||
|
- beforeUpdate
|
||||||
|
- afterUpdate
|
||||||
|
- beforeRemove
|
||||||
|
- afterRemove
|
||||||
|
|
||||||
|
Model lifecycle:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var person = new PersonModel();
|
||||||
|
person.on('beforeCreate', function() {
|
||||||
|
var model = this;
|
||||||
|
model.fancyMethod(); // Do something fancy with the model
|
||||||
|
});
|
||||||
|
var people = new Repository(appContext.collection("people"), { model: PersonModel });
|
||||||
|
|
||||||
|
people.save(person);
|
||||||
|
// beforeCreate()
|
||||||
|
// beforeSave()
|
||||||
|
// The model is created at db
|
||||||
|
// afterSave()
|
||||||
|
// afterCreate()
|
||||||
|
|
||||||
|
people.update(person, data);
|
||||||
|
// beforeUpdate(data)
|
||||||
|
// beforeSave(data)
|
||||||
|
// The model is updated at db
|
||||||
|
// afterSave(data)
|
||||||
|
// afterUpdate(data)
|
||||||
|
|
||||||
|
people.remove(person);
|
||||||
|
// beforeRemove()
|
||||||
|
// The model is deleted at db
|
||||||
|
// afterRemove()
|
||||||
|
```
|
||||||
|
|
||||||
|
!SUBSECTION Extend
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/model.js -->
|
||||||
|
@startDocuBlock JSF_foxx_model_extend
|
||||||
|
|
||||||
|
!SUBSECTION Initialize
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/model.js -->
|
||||||
|
@startDocuBlock JSF_foxx_model_initializer
|
||||||
|
|
||||||
|
!SUBSECTION Get
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/model.js -->
|
||||||
|
@startDocuBlock JSF_foxx_model_get
|
||||||
|
|
||||||
|
!SUBSECTION Set
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/model.js -->
|
||||||
|
@startDocuBlock JSF_foxx_model_set
|
||||||
|
|
||||||
|
!SUBSECTION Has
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/model.js -->
|
||||||
|
@startDocuBlock JSF_foxx_model_has
|
||||||
|
|
||||||
|
!SUBSECTION isValid
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/model.js -->
|
||||||
|
@startDocuBlock JSF_foxx_model_isvalid
|
||||||
|
|
||||||
|
!SUBSECTION Errors
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/model.js -->
|
||||||
|
@startDocuBlock JSF_foxx_model_errors
|
||||||
|
|
||||||
|
!SUBSECTION Attributes
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/model.js -->
|
||||||
|
@startDocuBlock JSF_foxx_model_attributes
|
||||||
|
|
||||||
|
!SUBSECTION forDB
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/model.js -->
|
||||||
|
@startDocuBlock JSF_foxx_model_forDB
|
||||||
|
|
||||||
|
!SUBSECTION forClient
|
||||||
|
<!-- js/server/modules/org/arangodb/foxx/model.js -->
|
||||||
|
@startDocuBlock JSF_foxx_model_forClient
|
|
@ -0,0 +1,149 @@
|
||||||
|
!CHAPTER Foxx Queries
|
||||||
|
|
||||||
|
This chapter describes helpers for performing AQL queries in Foxx. For a full overview of AQL syntax and semantics see the chapter on the ArangoDB Query Language (AQL).
|
||||||
|
|
||||||
|
!SECTION ArangoDB Query Builder
|
||||||
|
|
||||||
|
The [ArangoDB Query Builder](https://www.npmjs.org/package/aqb) NPM module comes bundled with Foxx and provides a fluid API for generating complex AQL queries while avoiding raw string concatenation.
|
||||||
|
|
||||||
|
Query Builder query objects can be used in any function that would normally expect an AQL string.
|
||||||
|
|
||||||
|
For a full overview of the query builder API [see the project documentation](https://github.com/arangodb/aqbjs).
|
||||||
|
|
||||||
|
*Examples*
|
||||||
|
|
||||||
|
```js
|
||||||
|
var db = require('org/arangodb').db;
|
||||||
|
var qb = require('aqb');
|
||||||
|
var console = require('console');
|
||||||
|
|
||||||
|
var usernames = db._query(qb.for('user').in('_users').return('user.user')).toArray();
|
||||||
|
console.log('usernames:', usernames);
|
||||||
|
```
|
||||||
|
|
||||||
|
!SECTION Foxx.createQuery
|
||||||
|
|
||||||
|
`Foxx.createQuery(cfg)`
|
||||||
|
|
||||||
|
Creates a query function that performs the given query and returns the result.
|
||||||
|
|
||||||
|
The returned query function optionally takes an object as its argument. If an object is provided, its properties will be used as the query's bind parameters. Any additional arguments will be passed to the transform function (or dropped if no transform function is defined).
|
||||||
|
|
||||||
|
*Parameter*
|
||||||
|
|
||||||
|
* *cfg*: an object with the following properties:
|
||||||
|
* *query*: an AQL query string or an ArangoDB Query Builder query object.
|
||||||
|
* *params* (optional): an array of parameter names.
|
||||||
|
* *context* (optional): an *applicationContext*.
|
||||||
|
* *model* (optional): a *Foxx.Model* that will be applied to the query results.
|
||||||
|
* *defaults* (optional): default values for the query's bind parameters. These can be overridden by passing a value for the same name to the query function.
|
||||||
|
* *transform* (optional): a function that will be applied to the return value.
|
||||||
|
|
||||||
|
If *cfg* is a string, it will be used as the value of *cfg.query* instead.
|
||||||
|
|
||||||
|
If a *context* is specified, the values of all collection bind parameters will be passed through the context's *collectionName* method.
|
||||||
|
|
||||||
|
Note that collection bind parameters in AQL need to be referenced with two at-signs instead of one, e.g. `@@myCollectionVar` and their parameter name needs to be prefixed with an at-sign as well, e.g. `{'@myCollectionVar': 'collection_name'}`.
|
||||||
|
|
||||||
|
If *params* is provided, the query function will accept positional arguments instead of an object. If *params* is a string, it will be treated as an array containing that string.
|
||||||
|
|
||||||
|
If both *model* and *transform* are provided, the *transform* function will be applied to the result array _after_ the results have been converted into model instances. The *transform* function is always passed the entire result array and its return value will be returned by the query function.
|
||||||
|
|
||||||
|
*Examples*
|
||||||
|
|
||||||
|
Basic usage example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var query = Foxx.createQuery('FOR u IN _users RETURN u.user');
|
||||||
|
var usernames = query();
|
||||||
|
```
|
||||||
|
|
||||||
|
Using bind parameters:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var query = Foxx.createQuery('FOR u IN _users RETURN u[@propName]');
|
||||||
|
var usernames = query({propName: 'user'});
|
||||||
|
```
|
||||||
|
|
||||||
|
Using named bind parameters:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var query = Foxx.createQuery({
|
||||||
|
query: 'FOR u IN _users RETURN u[@propName]',
|
||||||
|
params: ['propName']
|
||||||
|
);
|
||||||
|
var usernames = query('user');
|
||||||
|
```
|
||||||
|
|
||||||
|
Using models:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var joi = require('joi');
|
||||||
|
var UserModel = Foxx.Model.extend({
|
||||||
|
schema: {
|
||||||
|
user: joi.string().required()
|
||||||
|
},
|
||||||
|
getUsername: function () {
|
||||||
|
return this.get('user');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var query = Foxx.createQuery({
|
||||||
|
query: 'FOR u IN _users RETURN u',
|
||||||
|
model: UserModel
|
||||||
|
});
|
||||||
|
var users = query();
|
||||||
|
var username = users[0].getUsername();
|
||||||
|
```
|
||||||
|
|
||||||
|
Using a transformation:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var query = Foxx.createQuery({
|
||||||
|
query: 'FOR u IN _users SORT u.user ASC RETURN u',
|
||||||
|
transform: function (results) {
|
||||||
|
return results[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var user = query(); // first user by username
|
||||||
|
```
|
||||||
|
|
||||||
|
Using a transformation with extra arguments:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var query = Foxx.createQuery({
|
||||||
|
query: 'FOR u IN _users SORT u.user ASC RETURN u[@propName]',
|
||||||
|
transform: function (results, uppercase) {
|
||||||
|
return uppercase ? results[0].toUpperCase() : results[0].toLowerCase();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
query({propName: 'user'}, true); // username of first user in uppercase
|
||||||
|
query({propName: 'user'}, false); // username of first user in lowercase
|
||||||
|
```
|
||||||
|
|
||||||
|
Using a transformation with extra arguments (using positional arguments):
|
||||||
|
|
||||||
|
```js
|
||||||
|
var query = Foxx.createQuery({
|
||||||
|
query: 'FOR u IN _users SORT u.user ASC RETURN u[@propName]',
|
||||||
|
params: ['propName'],
|
||||||
|
transform: function (results, uppercase) {
|
||||||
|
return uppercase ? results[0].toUpperCase() : results[0].toLowerCase();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
query('user', true); // username of first user in uppercase
|
||||||
|
query('user', false); // username of first user in lowercase
|
||||||
|
```
|
||||||
|
|
||||||
|
Using a transformation with extra arguments (and no query parameters):
|
||||||
|
|
||||||
|
```js
|
||||||
|
var query = Foxx.createQuery({
|
||||||
|
query: 'FOR u IN _users SORT u.user ASC RETURN u.user',
|
||||||
|
params: false, // an empty array would work, too
|
||||||
|
transform: function (results, uppercase) {
|
||||||
|
return uppercase ? results[0].toUpperCase() : results[0].toLowerCase();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
query(true); // username of first user in uppercase
|
||||||
|
query(false); // username of first user in lowercase
|
||||||
|
```
|
|
@ -0,0 +1,177 @@
|
||||||
|
!CHAPTER Details on FoxxRepository
|
||||||
|
|
||||||
|
A repository is a gateway to the database. It gets data from the database, updates it or saves new data. It uses the given model when it returns a model and expects instances of the model for methods like save. In your repository file, export the repository as *repository*.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var Foxx = require("org/arangodb/foxx");
|
||||||
|
|
||||||
|
var TodosRepository = Foxx.Repository.extend({
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.repository = TodosRepository;
|
||||||
|
```
|
||||||
|
|
||||||
|
!SUBSECTION Initialize
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_initializer
|
||||||
|
|
||||||
|
!SECTION Defining custom queries
|
||||||
|
|
||||||
|
You can define custom query methods using Foxx.createQuery and Foxx.Repository.extend.
|
||||||
|
|
||||||
|
For more details see the chapter on [Foxx Queries](../Foxx/FoxxQueries.md).
|
||||||
|
|
||||||
|
*Examples*
|
||||||
|
|
||||||
|
Making a simple query in the repository and using it from the controller:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// in the repository
|
||||||
|
var Foxx = require("org/arangodb/foxx");
|
||||||
|
|
||||||
|
var TodosRepository = Foxx.Repository.extend({
|
||||||
|
getPendingItems: Foxx.createQuery(
|
||||||
|
'FOR todo IN my_todos FILTER todo.completed == false RETURN todo'
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
// in the controller
|
||||||
|
ctrl.get("/", function(req, res) {
|
||||||
|
req.json(todosRepository.getPendingItems());
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
It is also possible to supply parameters to the query:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// in the repository
|
||||||
|
getPendingItemById: Foxx.createQuery({
|
||||||
|
query: 'FOR todo IN my_todos FILTER todo.completed == false FILTER todo._key == @id RETURN todo',
|
||||||
|
params: ['id']
|
||||||
|
})
|
||||||
|
|
||||||
|
// in the controller
|
||||||
|
ctrl.get("/:id", function(req, res) {
|
||||||
|
var id = req.params("id");
|
||||||
|
var rv = todosRepository.getPendingItemById(id);
|
||||||
|
res.json(rv);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
The list of results can also be transformed before returning it from the repository:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// in the repository
|
||||||
|
getPendingItemById: Foxx.createQuery({
|
||||||
|
query: 'FOR todo IN my_todos FILTER todo.completed == false FILTER todo._key == @id RETURN todo',
|
||||||
|
params: ['id'],
|
||||||
|
transform: function(results, extra) {
|
||||||
|
for (var i = 0; i < results.length; i++) {
|
||||||
|
results[i].extraProperty = extra;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// in the controller
|
||||||
|
ctrl.get("/:id", function(req, res) {
|
||||||
|
var id = req.params("id");
|
||||||
|
var extra = req.params("extra");
|
||||||
|
var rv = todosRepository.getPendingItemById(id, extra);
|
||||||
|
res.json(rv);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
!SECTION Attributes of a Repository
|
||||||
|
|
||||||
|
!SUBSECTION Collection
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_collection
|
||||||
|
|
||||||
|
!SUBSECTION Model
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_model
|
||||||
|
|
||||||
|
!SUBSECTION Model schema
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_modelSchema
|
||||||
|
|
||||||
|
!SUBSECTION Prefix
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_prefix
|
||||||
|
|
||||||
|
!SECTION Defining indexes
|
||||||
|
|
||||||
|
Repository can take care of ensuring the existence of collection indexes for you.
|
||||||
|
If you define indexes for a repository, instances of the repository will have
|
||||||
|
access to additional index-specific methods like *range* or *fulltext* (see below).
|
||||||
|
|
||||||
|
The syntax for defining indexes is the same used in [*collection.ensureIndex*](../IndexHandling/README.md).
|
||||||
|
|
||||||
|
@EXAMPLES
|
||||||
|
|
||||||
|
```js
|
||||||
|
var Foxx = require('org/arangodb/foxx');
|
||||||
|
var FulltextRepository = Foxx.Repository.extend({
|
||||||
|
indexes: [
|
||||||
|
{
|
||||||
|
type: 'fulltext',
|
||||||
|
fields: ['text'],
|
||||||
|
minLength: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
!SECTION Methods of a Repository
|
||||||
|
|
||||||
|
!SUBSECTION Adding entries to the repository
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_save
|
||||||
|
|
||||||
|
!SUBSECTION Finding entries in the repository
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_byId
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_byExample
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_firstExample
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_all
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_any
|
||||||
|
|
||||||
|
!SUBSECTION Removing entries from the repository
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_remove
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_removeById
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_removeByExample
|
||||||
|
|
||||||
|
!SUBSECTION Replacing entries in the repository
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_replace
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_replaceById
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_replaceByExample
|
||||||
|
|
||||||
|
!SUBSECTION Updating entries in the repository
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_updateById
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_updateByExample
|
||||||
|
|
||||||
|
!SUBSECTION Counting entries in the repository
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_count
|
||||||
|
|
||||||
|
!SUBSECTION Index-specific repository methods
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_range
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_near
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_within
|
||||||
|
|
||||||
|
@startDocuBlock JSF_foxx_repository_fulltext
|
|
@ -0,0 +1,145 @@
|
||||||
|
!CHAPTER Foxx Sessions
|
||||||
|
|
||||||
|
Foxx provides some convenience methods to make working with sessions easier.
|
||||||
|
|
||||||
|
!SUBSECTION Activate sessions
|
||||||
|
|
||||||
|
Enables session features for the controller.
|
||||||
|
|
||||||
|
`controller.activateSessions(options)`
|
||||||
|
|
||||||
|
Once sessions have been activated, a *session* property will be added to the *request* object passed to route handlers defined on the controller, which will be a saved instance of the session model provided by the session storage.
|
||||||
|
|
||||||
|
If the option *autoCreateSession* has not explicitly been set to *false*, a new session will be created for users that do not yet have an active session.
|
||||||
|
|
||||||
|
If *type* is set to *"cookie"*, the session cookie will be updated after every route.
|
||||||
|
|
||||||
|
*Parameter*
|
||||||
|
|
||||||
|
* *options* (optional): an object with any of the following properties:
|
||||||
|
* *sessionStorageApp* (optional): mount point of the session storage app to use. Default: *"/_system/sessions"*.
|
||||||
|
* *type* (optional): sessions type, currently only *"cookie"* and *"header"* are supported. Default: *"cookie"*.
|
||||||
|
* *cookie* (optional): an object with the following properties:
|
||||||
|
* *name*: name of the session cookie if using cookie sessions. Default: *"sid"*.
|
||||||
|
* *secret* (optional): secret string to sign session cookies with if using cookie sessions.
|
||||||
|
* *algorithm* (optional): algorithm to sign session cookies with if using cookie sessions. Default: *"sha256"*.
|
||||||
|
* *header* (optional): name of the session header if using header sessions. Default: *"X-Session-Id"*.
|
||||||
|
* *jwt* (optional): whether the session ID should be wrapped in a JSON Web Token. Default: *false*.
|
||||||
|
* *autoCreateSession* (optional): whether a session should always be created if none exists. Default: *true*.
|
||||||
|
|
||||||
|
If *cookie* is set to a string, its value will be used as the *cookie.name* instead.
|
||||||
|
|
||||||
|
Optionally *jwt* can be an object with any of the following values:
|
||||||
|
|
||||||
|
* *secret* (optional): secret string to sign session JSON Web Tokens with.
|
||||||
|
* *algorithm* (optional): algorithm to sign session JSON Web Tokens with. Default: *"HS256"* if a *secret* is provided, *"none"* otherwise.
|
||||||
|
* *verify* (optional): whether incoming session JSON Web Tokens should be verified. Default: *true*.
|
||||||
|
|
||||||
|
If *jwt* is set to a string, its value will be used as the *jwt.secret* instead.
|
||||||
|
|
||||||
|
Note that if the *jwt.algorithm* is explicitly set to any algorithm other than *"none"*, not providing a *jwt.secret* will raise an exception.
|
||||||
|
|
||||||
|
*Examples*
|
||||||
|
|
||||||
|
Example configuration for using signed cookies:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var controller = new FoxxController(applicationContext);
|
||||||
|
controller.activateSessions({
|
||||||
|
sessionStorageApp: '/_system/sessions',
|
||||||
|
cookieName: 'sid',
|
||||||
|
cookieSecret: 'secret',
|
||||||
|
type: 'cookie'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Example configuration for using a header:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var controller = new FoxxController(applicationContext);
|
||||||
|
controller.activateSessions({
|
||||||
|
sessionStorageApp: '/_system/sessions',
|
||||||
|
headerName: 'X-Session-Token',
|
||||||
|
type: 'header'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Example configuration for using a JWT header:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var controller = new FoxxController(applicationContext);
|
||||||
|
controller.activateSessions({
|
||||||
|
sessionStorageApp: '/_system/sessions',
|
||||||
|
headerName: 'X-Web-Token',
|
||||||
|
jwt: 'keyboardcat',
|
||||||
|
type: 'header'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Example configuration for using a JWT header with signature algorithm "none" (and no secret):
|
||||||
|
|
||||||
|
```js
|
||||||
|
var controller = new FoxxController(applicationContext);
|
||||||
|
controller.activateSessions({
|
||||||
|
sessionStorageApp: '/_system/sessions',
|
||||||
|
headerName: 'X-Web-Token',
|
||||||
|
jwt: true,
|
||||||
|
type: 'header'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Example configuration for using a JWT header with signature verification disabled:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var controller = new FoxxController(applicationContext);
|
||||||
|
controller.activateSessions({
|
||||||
|
sessionStorageApp: '/_system/sessions',
|
||||||
|
headerName: 'X-Web-Token',
|
||||||
|
jwt: {
|
||||||
|
verify: false
|
||||||
|
},
|
||||||
|
type: 'header'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Example configuration for using signed JWT cookies:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var controller = new FoxxController(applicationContext);
|
||||||
|
controller.activateSessions({
|
||||||
|
sessionStorageApp: '/_system/sessions',
|
||||||
|
cookieName: 'token',
|
||||||
|
cookieSecret: 'secret',
|
||||||
|
jwt: 'keyboardcat',
|
||||||
|
type: 'cookie'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Example configuration for using unsigned cookies:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var controller = new FoxxController(applicationContext);
|
||||||
|
controller.activateSessions({
|
||||||
|
sessionStorageApp: '/_system/sessions',
|
||||||
|
cookieName: 'sid',
|
||||||
|
type: 'cookie'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
!SUBSECTION Define a session destruction route
|
||||||
|
|
||||||
|
Defines a route that will destroy the session.
|
||||||
|
|
||||||
|
`controller.destroySession(path, options)`
|
||||||
|
|
||||||
|
Defines a route handler on the controller that destroys the session.
|
||||||
|
|
||||||
|
When using cookie sessions, this function will clear the session cookie (if *autoCreateSession* was disabled) or create a new session cookie, before calling the *after* function.
|
||||||
|
|
||||||
|
*Parameter*
|
||||||
|
|
||||||
|
* *path*: route path as passed to *controller.get*, *controller.post*, etc.
|
||||||
|
* *options* (optional): an object with any of the following properties:
|
||||||
|
* *method* (optional): HTTP method to handle. Default: *"post"*.
|
||||||
|
* *before* (optional): function to execute before the session is destroyed. Receives the same arguments as a regular route handler.
|
||||||
|
* *after* (optional): function to execute after the session is destroyed. Receives the same arguments as a regular route handler. Default: a function that sends a *{"message": "logged out"}* JSON response.
|
Loading…
Reference in New Issue