Skip to content
This repository has been archived by the owner on Oct 19, 2018. It is now read-only.
/ cubic-core Public archive

PSA: moved into cubic-js/cubic as monorepo

License

Notifications You must be signed in to change notification settings

cubic-js/cubic-core

Repository files navigation

cubic API

Request processing node for Cubic endpoint components.

npm build dependencies



Usage

const Cubic = require('cubic')
const Core = require('cubic-core')
const cubic = new Cubic()

cubic.use(new Core(options))

This will create a core node that connects to the API node on localhost:3003 and listen to any incoming requests. We'll being using this for our application logic.


How does it work?

Whenever a user requests a URL on the API node, that request is actually being processed at the core node.

The API checks every core node for an endpoint component that matches the desired URL and the first core node to respond affirmatively gets to process the request and return a response.

model

Should no core node find a matching endpoint, we return a '404, not found'. Should all core nodes fail to respond to the initial check within one second, we respond with a '503, All nodes currently busy'.


Endpoint components

To respond to requests, cubic-core looks for endpoint components in the /api folder in the current working directory. These components are automatically routed based on folder and file names.

An endpoint saved as /api/test/foo.js would automatically be exposed as localhost:3003/test/foo. Custom URLs can still be specified through the endpoint schema.

Endpoint components usually extend the default endpoint class which contains information on rate limiting, caching and more:

const Endpoint = cubic.nodes.core.Endpoint

class Foo extends Endpoint {
  /**
   * Set custom schema information (optional)
   */
  constructor(api, db, url) {
    super(api, db, url)
    this.schema = options
  }

  /**
   * Main method which will be called on a request
   */
  async main(req, res) {
    res.send('bar')   // Respond with a simple 'bar'
    this.cache('bar') // And cache the response for follow-up requests
  }
}

module.exports = Foo

Endpoint Parent Properties

The Endpoint class that we're extending in each endpoint comes with a few utilities that can be used within the class like this:

Caching

this.cache(data, exp, url)

Allows storing a value in redis, which will be sent as a response to requests within the given timeframe. The response is looked up on the api node directly, not on the core node.

Param Default Description
data none Value to store in the cache.
exp default value in cubic-api (optional) Duration for which the cached value should persist.
url this.url (optional) URL to store the cached value on.

Publish

this.publish(data, url)

Publishes data in cubic's Pub/Sub model. This is important for real-time data, as every subscribed client will receive the published changes immediately.

pub/sub model

Param Default Description
data none Data to publish to subscribed clients.
url this.url (optional) URL to publish the data on. Useful when a POST endpoint changes the data of another GET endpoint.

Have a look at cubic-client for instructions on how to subscribe to endpoints.

Endpoint Schema

this.schema

Provides basic information about the endpoint, including rate limiting, custom URL and more. See options for all options.

Database client

this.db

Every endpoint gets passed the database client that is connected to the database specified in options.

API client

this.api

The cubic-client instance used to connect to our target API. Can be useful if we need to make requests on endpoints hosted by other core nodes. Under the hood, it's also used for this.publish and this.cache.


Options

Constructor

cubic.use(new Core(options))
Option Default Description
endpointPath process.cwd()/api Folder to read API endpoints from.
endpointPathExclude /a^/ Sub-path to exclude from endpoints. Default regex matches nothing.
endpointParent internal Parent class that API endpoints will extend.
baseUrl none Path to prepend to each route found in endpoints folder.
publicPath process.cwd()/assets Folder containing publically accessible files.
apiUrl 'http://localhost:3003' API node to connect to
authUrl 'http://localhost:3030' Auth node to authenticate at
userKey none User key to authenticate with. These are registered and assigned automatically in dev mode. In production, you need to register them yourself. (see cubic-auth for reference)
userSecret none User secret to authenticate with. Handled the same way as above.
mongoUrl 'mongodb://localhost' Mongodb connection string.
mongoDb 'cubic-core' Database to select by default.
redisUrl `'redis://localhost'`` Redis connection string.

Endpoint Schema

class Endpoint extends EndpointParent {
  constructor() {
    this.schema = options
  }
}
Option Default Description
method 'GET' RESTful method to listen for.
scope '' Authorization scope required to use this endpoint. E.g. 'read_contacts'
description none (optional) Description for the current endpoint. Useful for automatic API documentation.
query [] (optional) Array specifying rules for query params (see object format below)
limit see below Object describing rate limit specifications. See keys and default values below

Endpoint Query Object

this.schema.query = [{
  name: 'time',
  default: () => moment().endOf('day').valueOf() // Returns value at time of execution rather than construction
}]
Option Default Description
name none Name of the given query key. For example in /route?foo=value the query key name is 'foo'
default none (optional) Default value for query key. Can be raw value or a function returning a value. If a default value is given, its data type is automatically enforced on user input. E.g. you can't provide numbers if the default value is a string.
required false (optional) Whether the query key is required on user input. Will return a 400 error if no matching key is given.
description '' (optional) Description for the given key. Useful for automated API documentation.

Endpoint Rate Limits

this.schema.limit = {
  interval: 5000,
  maxInInterval: 20
}
Option Default Description
disable false (optional) Whether rate limits should be enforced on this endpoint. The default rate limit is applied on all endpoints and we recommend keeping it that way. If some API clients like your service workers need to bypass rate limits, you can add the ignore_rate_limit scope to their user account.
interval 5000 Interval in ms for the token bucket to refill.
maxInInterval 20 Maximum number of requests within a single interval.

License

MIT