1.0.0-alpha.7 • Published 3 years ago

@itsrems/wave-sqlite v1.0.0-alpha.7

Weekly downloads
111
License
MIT
Repository
github
Last release
3 years ago

Wave

An all-in-one backend framework for NodeJS, built with love & Typescript by itsRems.

@itsrems/wave

The wave server package, used to build backend applications.

Requirements

Wave requires NodeJS v12+ and a redis instance to connect to. It also requires a storage driver (if you plan on using collections - WHICH DO NOT WORK AT THE TIME OF WRITING THESE DOCS).

The default redis instance wave will try to connect to is 127.0.0.1:6379, but you can change this using config.

While this is not required, I strongly recommend using typescript. This is what wave was built on and more importantly, for. If you're not using typescript already, give it a try !

Getting Started

Installing

yarn add @itsrems/wave or npm i @itsrems/wave

Actions

Actions are both your functions and "routes", all in one.

They are queue-based using bee-queue, allowing for easy scaling of any wave-based app.

Defining an action is a simple as this:

import { action } from '@itsrems/wave';

const myAction = action('my-action');

The first parameter is your action's name, and it should be unique. This is also the name you'll use to call it from link (more on that in the link section).

Actions also take a generic to type the payload. Here's an example

import { action } from '@itsrems/wave';

const myAction = action<{
  username: string;
}>('my-action');

Your action is now typed in such a way that the payload object will match { username: string }.

This is all fun and games but our action is pretty... useless (unless... ?). Let's change that !

We'll call the process function and pass along a function for our action to run on call.

import { action } from '@itsrems/wave';

const myAction = action<{
  username: string;
}>('my-action').process(async function ({ username }) {
  console.log(`My super action got a new request ! The username I was provided is: ${username}`);
  return {
    status: 'success',
    data: `You are a super cool person !`
  }
});

In the return section, we're returning a standard wave "action return payload". This will always be an object with two props: data and status.

Your status is going to be a string, and it can be anything you want it to be. You should use this to specify whether or not your action ran properly, and what went wrong if it failed. Examples: success, error, duplicate, ...

With this out of the way, our action is ready to be called ! But first, we need to start wave.

Does that sound like one of those horribly complicated tasks ? Fear not ! It's dead simple.

import { action, start } from '@itsrems/wave';

const myAction = action<{
  username: string;
}>('my-action').process(async function ({ username }) {
  console.log(`My super action got a new request ! The username I was provided is: ${username}`);
  return {
    status: 'success',
    data: `You are a super cool person !`
  }
});

start();

That's... it ! Provided you have a redis server open on your computer with the default port, and that your 1500 is free, wave should start.

Let's celebrate by calling our action.

import { action, start } from '@itsrems/wave';

const myAction = action<{
  username: string;
}>('my-action').process(async function ({ username }) {
  console.log(`My super action got a new request ! The username I was provided is: ${username}`);
  return {
    status: 'success',
    data: `You are a super cool person !`
  }
});

// Wrapping our app so we can wait for wave to start before calling our action
// This is not required as wave will not run any action before it's ready, leaving promises pending for as long as it starts. Magic !
async function myApp () {
  await start();
  const { status, data } = await myAction.call({ username: 'nico' });
  console.log(status, data);
}

myApp();

If all went well, you should see something a bit like this: output

One more cool thing we can do is cache this action.

While the actual process of how we cache actions is a bit complicated to explain, know that we generate the cache key using the action's name and the payload, making the caching safe to use in situations where the output depends on the payload.

So, let's cache it !

import { action, start } from '@itsrems/wave';

const myAction = action<{
  username: string;
}>('my-action').process(async function ({ username }) {
  // Force our function to wait for 2.5s when ran uncached
  await new Promise((resolve) => {
    setTimeout(() => (resolve(true)), 2500);
  });
  console.log(`My super action got a new request ! The username I was provided is: ${username}`);
  return {
    status: 'success',
    data: `You are a super cool person !`
  }
}).cache(30, 'seconds'); // Cache our action for 30 seconds (the 2nd parameter is optional - the default time unit is minutes).

// Wrapping our app so we can wait for wave to start before calling our action
// This is not required as wave will not run any action before it's ready, leaving promises pending for as long as it starts. Magic !
async function myApp () {
  await start();
  console.log(await testCall()); // this will run uncached 
  console.log(await testCall()); // this will be much faster
}

async function testCall () {
  const start = Date.now();
  const { status, data } = await myAction.call({ username: 'nico' });
  const latency = Date.now() - start;
  return { data, latency };
}

myApp();

You should see something like this appear in your console: console

We can see a few things here: first, the latency of the first call was of only 2ms compared to the ~2.5s of the first call. 2nd, we can see that our console didn't output the username on the 2nd run. This is because as the action was cache, the function wasn't actually ran.

Instead, we made a cache key, checked for it inside our redis server, and got an output - only the 2nd time, as the first run took care of actually running our function and saving the result. Neat, right ?

Collections

@todo

Config

@todo

Storage

@todo

@itsrems/link

Link is the communication library for use in the browser