Effortless Function as a Service: A Simple Guide to Implementing it with Query

gc-victor

Víctor García

Posted on December 21, 2023

Effortless Function as a Service: A Simple Guide to Implementing it with Query

Query is a Rust server that provides an API, CLI, and authentication for remote interaction with SQLite databases. It has introduced "functions" to enhance your product with hosted JavaScript code accessing remote SQLite databases.

Let's explore a practical example of a Query function:

export async function handleRequest(req) {
    const db = new Database("example.sql");

    const result = await db.query("SELECT * FROM example WHERE id = ?", [1]);

    return new Response(JSON.stringify({ data: result }), {
        status: 200,
        headers: {
            "content-type": "application/json",
        },
    });
}
Enter fullscreen mode Exit fullscreen mode

In this example, the function fetches data from a database table and responds with a JSON object containing the result.

A Query function follows a specific format. It exports an asynchronous function named handleRequest that takes a Request and returns a Response.

A connection to a database is required to interact with databases using the Query function. It can be achieved by utilizing the Database constructor.

const db = new Database("example.sql");
Enter fullscreen mode Exit fullscreen mode

The Database constructor takes the name of the database. Once connected, it provides two essential methods:

  • query: Reads data from the database.
  • execute: Writes data to the database.

Both query and execute can accept parameters as an array or an object with placeholders like :AAA, $AAA, or @AAA.

Remember, when working with Query and LiteFS proxy, use GET to read data and DELETE|POST|PUT|PATCH to write data.

Query follows a specific folder structure to organize functions and define routes. Here's an example:

functions
├── get.index.js // GET "/"
├── post.index.js // POST "/"
├── example
    ├── get.index.js // GET "/example"
    ├── get.[slug].js // GET "/example/:slug"
    [slug]
    ├── get.index.js  // GET "/:slug"
...
Enter fullscreen mode Exit fullscreen mode

The prefix determines the method used in a file (delete|get|patch|post|put).*. The remaining part of the file name defines the final segment of the route. For instance, if the file name ends with index, it represents the root of the route.

If you're looking to deploy and replicate your databases across the globe quickly, Fly.io provides a seamless solution to run a Query Server in just a few minutes.

To incorporate Query into your deployment, your Dockerfile needs to include the Query Server. Consider using a multistage Dockerfile, with the final stage being a compatible x86_64-unknown-linux-gnu image, such as debian:<suite>-slim. Refer to the LiteFS documentation for critical information on this essential system component.

Here is a sample Dockerfile for your Query Server:

FROM debian:12-slim

ADD litefs.yml /etc/litefs.yml
COPY --from=flyio/litefs:0.5 /usr/local/bin/litefs /usr/local/bin/litefs

RUN apt-get update -qq && \
    apt-get install -y --no-install-recommends \
    ca-certificates \
    sqlite3 \
    fuse3 \
    curl

# Download and install Query Server
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/gc-victor/query/releases/latest/download/query-server-installer.sh | sh

EXPOSE 3000

CMD ["litefs", "mount"]
Enter fullscreen mode Exit fullscreen mode

Additionally, to kickstart the server, add this command to the litefs.yml configuration file:

...
exec:
  - cmd: "~/.cargo/bin/query-server"
...
Enter fullscreen mode Exit fullscreen mode

With these components in place, your Query Server will be ready to deploy on Fly, providing a robust and globally accessible solution.

Let's install the toolset to deploy the functions.

We have to install the Query CLI. It is a powerful tool that lets you manage your remote SQLite databases with ease and safety.

Form macOS and Linux (not NixOS, Alpine, or Asahi):

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/gc-victor/query/releases/latest/download/query-installer.sh | sh
Enter fullscreen mode Exit fullscreen mode

The functions will bundle using esbuild. For that, it is required to install esbuild globally:

npm install --global esbuild
Enter fullscreen mode Exit fullscreen mode

Finally, to deploy the functions, run:

query function
Enter fullscreen mode Exit fullscreen mode

With their structured approach and database integration, Query functions offer a robust foundation for building scalable and efficient Function as a Service (FaaS).

💖 💪 🙅 🚩
gc-victor
Víctor García

Posted on December 21, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related