Trigger CC via HTTP

Version Compatibility

This feature is compatible with v1.1.0 and later of CloudCode.

You can trigger a CloudCode Task via HTTP. This is referred to as a Web Task.

In this way, CloudCode can be used to create a JSON-based HTTP API.

The task will need to have the "Web Request" trigger enabled in the task's configuration.

The hostnames (with .poweredbyjourney.com suffix) for an app's web-triggered CloudCode tasks are configured by editing an app deployment in the Deployments workspace in OXIDE.

After deploying, enabled tasks are accessible on https://<your_app_deployment_hostname>.poweredbyjourney.com/<task>.

Note that domain names are globally unique, so care is required when choosing hostnames for each of your apps and app deployments. Consider using the organization name, app name, and a -testing or -staging suffix for the corresponding deployments. e.g.

  • https://acme-my-app-testing.poweredbyjourney.com/my_web_task,

  • https://acme-my-app-staging.poweredbyjourney.com/my_web_task,

  • https://acme-my-app.poweredbyjourney.com/my_web_task.

A Minimal Example

Here's a minimal example of a task that can handle GET requests:

// This MUST be defined, and either return access.unauthorized() or access.authorized().
export async function authenticate({request, access}) {
    return access.authorized();
}

export async function get({params, request, response}) {
    return {hello: 'world'};
}

Authentication Example

This is an example implementation of authentication for a POST request.

// This MUST either return access.unauthorized() or access.authorized().
// Any object passed into access.authorized() will be available as authContext in the task.
// The access.unauthorized({status: 403, body: "Message"}) call allows for custom error responses.
// If this function is not defined, an error is thrown, or
// a different value is returned, the request fails with 500.
export async function authenticate({request, access, params}) {
    // Authentication is up to the developer. In this example,
    // We check for a token in the Authorization header, and
    // do a database lookup based on this.
    const auth = request.header('Authorization');
    const match = /^Bearer (\w+)$/.exec(auth);
    if(match == null) {
       return access.unauthorized();
    }
    const token = match[1];
    const client = await DB.api_client.first('token = ?', token);
    if(client == null) {
        return access.unauthorized();
        // The response can also be customized:
        //   return access.unauthorized({body: 'Forbidden', status: 403});
        // or JSON:
        //   return access.unauthorized({body: {message: 'Forbidden'}, status: 403});
    } else {
        // The parameter here (client) will be available as `authContext` in
        // in handler.
        return access.authorized(client);
    }
}

export async function post({params, request, response, authContext}) {
    const client = authContext;
    return {user: client.name};
}

Request and Response Details

export async function post({params, request, response, authContext}) {
    // params is a convenience object containing all the parameters for the request. It is a combination of:
    // 1. Query string parameters
    // 2. Request body, in the case of a JSON POST request.
    
    // request details:
    request.method; // GET, POST, etc
    request.url.href; // The full URL for the request: https://developer.mozilla.org/en-US/docs/Web/API/URL
    request.headers; // Headers object: https://developer.mozilla.org/en-US/docs/Web/API/Headers
  
    request.hostname; // full hostname of the request
    request.subdomain; // just the subdomain
    request.searchParams; // Query parameters, as URLSearchParams: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
    request.path; // path of the request, excluding hostname and query parameters
    
    request.json(); // Body of the request as JSON, null for GET, or throw an Error if invalid JSON
    request.text(); // Body of the request as a string, or null for GET
    request.header(key); // Value of a request header
    
    
    // response details (all optional, only if more control is desired):
    response.contentType('application/json'); // Set the Content-Type header
    response.status(code); // Set the response status code
    response.body(string | json); // Set the response body
    
    // If a value is returned, it is automatically used as the response body.
    // Content-Type is automatically set in this case.
    const body = {hello: 'world'};
    return body;
  
    // If no value is returned, the value passed into `response.body` will be used as the body.
}

Limitations

  • Custom domains are not supported - only *.poweredbyjourney.com.

  • Custom paths are not supported.

  • Only application/json is supported for request format, and application/json, text/html or text/plain for response format. Binary data specifically is not supported.

Last updated