Actions
Actions are async Javascript functions that run on your app server. They are primarily used for building APIs by receiving JSON data from the browser. This is usually where you use your database, send emails or other things that can't happen in the browser directly.
Create JSON APIs
Creating a JSON API with Waveorb server actions is very easy and should be familiar if you've used NodeJS before. An action usually has a name instead of a URL path. The name is what you use with the client to access it.
AJAX, uploads and websockets all connect to the actions in the same way. This is how an action may look:
module.exports = async function($) {
await $.filters(['authenticate', 'login-required'])
await $.validate({
values: {
project_id: {
is: 'id',
required: true
},
content: {
min: 3,
required: true
}
}
})
const { values = {} } = $.params
return await $.db('comment').create(values)
}
Normally you run filters first, then validations and then the rest of the function.
Return or throw stops the execution flow and return data to the client as JSON data.
Validations
Most of the time we need to validate the parameters sent to a server action. Here's a list of the built in validations:
// This is the name of the parameter
query: {
// Run validations on specified fields
name: {
required: true, // this means can not be undefined
eq: 5, // Equal to
ne: 5, // Not equal to
gt: 5, // Greater than
lt: 5, // Less than
gte: 5, // Greater than or equal to
lte: 5, // Less than or equal to
in: [1, 2, 3], // Must be in list
nin: [1, 2, 3], // Must not be in list
length: 5, // Length of string must be
min: 5, // Minimum length of string
max: 5, // Maximum length of string
match: /regex/, // Must match regex
unique: 'user', // Unique field in db model
exist: 'user', // Check if model exists in db
matcher: async function(val, $) {
// Validation fails on truthy value
if (!val) {
return $.t('some_error')
}
// Return nothing or undefined to pass
},
is: 'boolean', // Must be true or false
is: 'string', // Must be a string
is: 'number', // Must be a number, integer or decimal (float)
is: 'integer', // Must be an integer
is: 'decimal', // Must be a decimal number
is: 'date', // Must be a date
is: 'id', // Must be an id
is: 'object', // Must be an object
is: 'array', // Must an array
is: 'email', // Must be an email address
is: 'undefined', // Must be undefined
is: 'url' // Must be a URL
}
}
If the any of the validations doesn't pass, an error message is returned. Have a look at the default translations for a complete list of the messages.
The error message then looks like this, with each failing field and errors as an array:
{
error: { message: 'validation error' },
query: { name: ['must be a URL'] }
}
Using actions from pages
In app/actions/project
create a file called create.js
with the following content:
module.exports = async function($) {
await $.validate({
values: {
title: {
required: true
}
}
})
return { status: 'OK' }
}
Then in one of your app's pages use this HTML:
<form onsubmit="return false">
<label for="title">Title</label>
<input id="title" type="text" name="title">
<em class="error-title"></em>
<button onclick="handleSubmit(this)">Save</button>
</form>
<script>
// Set up the Waveorb client
var api = waveorb('https://waveorb.com/api')
// Define your submit function
function handleSubmit(btn) {
// Using the Haka form serializer to gather the data
var values = serialize(btn.form)
// Send the data to the action
var result = await api('/project/create', { values })
if (result.error) {
// Join all the errors and display under the right input
Object.keys(result.values).forEach(function(key) {
text(`.error-${key}`, result.values[key].join(', '))
})
} else {
// Redirect to project list
window.location = '/projects'
}
}
</script>
Example actions
These are example actions you can use as a template for your JSON API.
They are similar to the actions created by waveorb generate.
Create action
Use this action when you want to create a new document.
module.exports = async function($) {
const { values = {} } = $.params
return await $.db('model').create(values)
}
Update action
Use this action when you want to update a document.
module.exports = async function($) {
const { query = {}, values = {} } = $.params
return await $.db('model').update(query, values)
}
Get action
Use this action when you want to get a single document.
module.exports = async function($) {
const { query = {}, fields = {} } = $.params
return await $.db('model').get(query)
}
Find action
Use this action when you want to find documents. Supports fields, sort, skip and limit, and can be used for pagination.
module.exports = async function($) {
const { query = {}, fields = {}, sort = {}, skip = 0, limit = 0 } = $.params
return await $.db('model').find(query, { fields, sort, skip, limit })
}
Count action
Use this action to count documents.
module.exports = async function($) {
const { query = {} } = $.params
return { n: await $.db('model').count(query) }
}
Delete action
Use this action to delete documents.
module.exports = async function($) {
const { query = {} } = $.params
return await $.db('model').delete(query)
}
The model
in the database queries here should be replaced with the name of your model.