AskQL Nodejs QuickStart

Estimated Reading Time: 4 minutes

AskQL is a new query language that is also a programming language. I’ve written an introduction about it in the former post.

In this article we will see how it can be setup in a nodejs server.

Quickly setting a server

To setup a server with AskQL, we first need a server. Let’s set it up quickly

  1. Clone the express demo repository:
    git clone https://github.com/YonatanKra/askql-demo.git
  2. Enter into the folder:
    cd askql-demo
  3. Checkout the express-quick-start tag:
    git checkout express-quick-start
  4. npm i
  5. npm run dev

Now you have a working express repository.

Express is a web framework for nodejs. It helps you setup a flexible and easily extendible web server in a really short amount of time.

The setup is pretty simple – in index.js (Code snippet #1) the server is setup with 3 middleware: logRequestMiddleware, logResultsMiddleware and errorHandler. They are being used in the /ask endpoint.

There’s also a public html page that will serve as our client.

import express from 'express';
import bodyParser from 'body-parser';
import {logRequestMiddleware, logResultsMiddleware, logError} from "./logger/logger.js";
const port = 8080;
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
app.post('/ask', [logRequestMiddleware, logResultsMiddleware, logError]);
app.listen(port, () => {
console.log(`Server listening at http://localhost:${port}`);
});
view raw index.js hosted with ❤ by GitHub
Code Snippet #1: A simple express server with. Line 10: Static assets are being served. Line 11: 3 middleware are set for the /ask entry point. Line 12: The server starts to listen to port 8080.

If you go to the client (http://localhost:8080) and submit the form, you will see that the submit has been logged. The output should be something like:

Figure 1: Logging a submit in our express server

The output shown in Figure 1 is not very exciting. You can see something that looks like code (actually, it is called AskScript) but it doesn’t do anything.

Let’s install AskQL so it would be able to parse our script.

Setting up AskQL

First we need to install AskQL: npm i askql

Now that AskQL is installed, we can import its utilities and classes in our express app.

Let’s import an AskQL middleware:

import middlewareFactory from "askql/askExpressMiddleware/askExpressMiddleware.js";
const { askExpressMiddleware } = middlewareFactory;

The askExpressMiddleware is a function that accepts some resources and configuration objects and returns a middleware function:

const askMiddleware = askExpressMiddleware( 
{ resources, values },  { callNext: true, passError: true}
);

Resources are dynamic AskQL resources that can be accessed in the AskScript.

Resources can be functions, data handlers (like filter, map etc.) mathematical operators and actually anything a function can do (even 3rd party npm modules you import).

Values are static values that exist in the server.  The values object is a regular object that holds numbers, strings, booleans, arrays or other objects.

Let’s take the resources that are coming from AskQL and define some values:

import askql from 'askql';
const {resources} = askql;
const values = {    
  names: ['Johnny', 'Rita', 'Jane', 'Martha', 'Clark'],
  powers: ['Nerd', 'C#', 'Cool', 'Superman\'s mom', 'Superman']
};

The configuration object is a means to customise the middleware – for instance, how to handle errors.

Now that the middleware is ready, we can add it to the list of middleware between the two loggers and restart the server.

The final index.js looks like this:

import express from 'express';
import bodyParser from 'body-parser';
import {logRequestMiddleware, logResultsMiddleware, logError} from "./logger/logger.js";
import middlewareFactory from "askql/askExpressMiddleware/askExpressMiddleware.js";
import askql from 'askql';
const {resources} = askql;
const values = {
names: ['Johnny', 'Rita', 'Jane', 'Martha', 'Clark'],
powers: ['Nerd', 'C#', 'Cool', 'Superman\'s mom', 'Superman']
};
const { askExpressMiddleware } = middlewareFactory;
const askMiddleware = askExpressMiddleware({ resources, values }, { callNext: true, passError: true });
const port = 8080;
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
app.post('/ask', [logRequestMiddleware, askMiddleware, logResultsMiddleware, logError]);
app.listen(port, () => {
console.log(`Server listening at http://localhost:${port}`);
});
view raw index.js hosted with ❤ by GitHub

Let’s see it in action

The client is a form that sends AskScript to the ask access point (a post request).

Let’s try out the first code we can possibly think of:

ask { 'Hello World!' }

Write it down in the text area and submit.

Surprisingly, it returns “Hello World!”

Now, instead of just asking for a value from the server, let’s ask for a value from a variable that exists on our server (via the values we sent to our askMiddleware):

ask { names }

And we get all the names in the group.

Now let’s query for their powers (or maybe I should have used the word traits):

ask { powers }

That was wonderful. 

Now we see how easy it is to access values we know about on the server.  What about combining resources with values? Let’s do something more interesting:

ask {        
  let arr = [];
  for (let i = 0; i < names:length; i = i + 1) { 
    arr = arr:set(i, {
                       name: names:at(i), 
                       power:powers:at(i)
    });
  }
  arr 
}

What do you think the above piece of code will do? You probably guessed right – it is a map!

AskQL has us covered with yet another core resource:

ask {
  names:map(fun(name, i) {        
    {name, power: powers:at(i)}    
  })
}

The two last snippets would both have the same result!

What Else?

AskQL has lots of resources.

Let’s say we want to find one of our heroes according to the hero’s power? We just use the find resource:

ask {
  names:find(fun(c, i) {
    return powers:at(i):equals('Innocent')
  })
}

There are a lot more resources for AskQL.

Summary

In this post, we’ve setup a nodejs server that allows a very flexible API without doing anything server side – just expose some data.

Anyone using microservices?

Let’s say there’s a microservice that serves some crucial data. How do we access it immediately?

ask {
   fetch('https://swapi.dev/api/people'):at('results')
}

That script will return a list of Star Wars characters via the public StarWars API.

In order for the above script to run, one needs to install node-fetch: npm i node-fetch

With AskQL we are not limited by anything. We can not only use the built in resources in order to created flexible scripts. We can also create our own custom resources!

In the next post, I’ll expand on this example and show how to create a custom resource to manipulate MongoDB.

I invite you to the AskQL repository to contribute and be involved with a promising technology. There’s also the discord server where you can hang out with the core team.

Thanks a lot to Piotr from xFAANG and Yonatan Doron from Hodash.dev for the kind and thorough review.

By continuing, you accept the privacy policy

Leave a Reply

Your email address will not be published. Required fields are marked *