/jServ

jServ is a flexible database server that allows you to adapt it's API and JSON databases to build backends for your project

Primary LanguageGoApache License 2.0Apache-2.0

jServ

A project by alchemicode


A flexible backend server


Build your backend fast and simple Easy document-based database with no query language Adapt the server to your project
jServ is an open source project designed to help backend developers get a server, database, and API up and running as soon as possible.
jServ has a flexible data structure that allows you to customize the database and it's functionality, with or without modifying the code.
jServ's driving force is it's use of multiple markup languages in it's data structure, and custom endpoints functions powered by Python.


Getting Started

To set up jServ, download the latest release, and unzip it into a folder, and run the executable. You will have a config.json file, a keys.jserv file, and an admin.jserv file. There will also be a directory called Collections, with an example.dat given to get started. To add a collection to the program, simply add a .dat file of any name, and the program will read it.

Before you execute the program for the first time, you should check in your config and data files.
The config.json file should look something like this:

{   
    "appname": "New app",
    "debug": true,
    "admin-path": "admin.jserv",
    "key-path": "keys.jserv",
    "ip": "localhost", 
    "port": 4040, 
    "write-interval": 10,
    "Requests": 
    {   
        "GET": true, 
        "POST": true, 
        "PUT": false, 
        "HEAD": true, 
        "DELETE": true, 
        "PATCH": false, 
        "OPTIONS": false 
    }, 
    "Permissions": 
    { 
        "Query":  "user",
        "Add":    "user",
        "Mod":    "user",
        "Delete": "user",
        "Purge":  "user"
    },
    "Aliases":
    {
        "127.0.0.1":"localhost"
    },
    "Services":
    {
        "/" : "index"
    }
}

Change the IP and port to whatever you need. Debug mode will show more detailed console logging. The requests list determines which requests the program will accept.

The permissions list determines which requests can be made with the user keys, whereas admin keys will have access to all of them.

The aliases list will change how certain addresses are displayed within the console.

When you run the program for the first time, an Admin API key will generate in the admin.jserv file, and a User API key will generate in the keys.jserv file. The program will reject any requests that do not have these keys in the "x-api-key" header.

Program Reference

Database

jServ's database relies on the use of HTTP requests to send instructions and data back and forth between the instance and your program. There are built-in request handlers that execute a variety of database operations (See below).

Each request will give a response in the form of a JSON object. It appears as follows (with example values)

{
    "status": "ok",
    "message": "Successfully queried some-database for some-object",
    "data": {
        "some-data": "some-value"
    }
}

The status value will appear as either "ok" or "error", and the message value will display a message either confirming the success, or explaining the error. The data value may not appear, and will only contain data if the request returns it.

Data Structure

(All of these structures can also be found in the jServ core library)

The database follows a document-based structure which internally relies on three classes, Document, Attribute, and Collection.


Document is the class that represents objects in the database. When serialized as a JSON object, it appears as follows (with example values)

{
    "_id": "some-unique-identifier",
    "data": {"some-key": "some-value"}
}

There is no pre-defined schema like in relational databases like MySQL. Each document can have a unique set of data The _id field is the only guaranteed value attached to any document. It is dependent on the user to implement field enforcement in your applications, and to ensure that the data fields are consistent across all objects if that is required.


Attribute is a class that serves the sole purpose of being a proxy between fields passed in the API requests. When serialized as a JSON object, it appears as follows (with example values)

{
    "some-key": "some-value"
}

Some of the requests require a single value to be passed in to the request body in a form resembling an Attribute object. The Attribute class acts as a model within the program to translate that data seamlessly to the Collection and Document classes.


Collection is a grouping of documents within a file. When written as a JSON object, it appears as follows (with example values)

{
    "name": "some-name",
    "list": [
        {
        "id": 0,
        "data": {"some-key": "some-value"}
        }
    ]
}

Internally, the name corresponds to a filename in the Collections folder, which contains the serialized data of list.


Database API Reference

(All of these structures can also be found in the jServ core library)

jServ's database operations are called through HTTP requests. This eliminates the need for a query language, as the properties of every operation can be encapsulated into serialized objects passed into each request.

Operations

__/j/db/query

Queries a list of, or all, collections for documents based on a set of rules. Returns a list of documents.
Possible properties of a query, written in JSON format, are as follows:

{
    //List of collections to be queried
    //If omitted, all collections will be queried
    "collections": [
        "some-collection", 
        "another-collection"
    ],
    //List of attributes a document must have
    "has": [
        "some-attribute",
        "another-attribute"
    ],
    //Attributes that must be equal to a given value
    "equals": {
        "some-attribute": "some-value"
    },
    //Attributes that must not be equal to a given value
    "not-equals": {
        "some-attribute": "some-value"
    },
    //Attributes that must be less than a given value
    "lt": {
        "some-attribute": "some-value"
    },
    //Attributes that must be less than or equal to a given value
    "lte": {
        "some-attribute": "some-value"
    },
    //Attributes that must be greater than or equal to a given value
    "gte": {
        "some-attribute": "some-value"
    },
    //Attributes that must be greater than a given value
    "gt": {
        "some-attribute": "some-value"
    },
    //Attributes that must be between two given values
    "between": {
        "some-attribute": ["lower-value", "upper-value"]
    }
}

This request returns the list of documents queried.

__/j/db/add

Adds documents to, or attributes to specific documents in, a collection.
The format of an Add, written in JSON, is as follows:

{
    //Name of the collection to add to, will fail if omitted
    "collection": "some-collection",
    //List of full documents to add to the collection
    "documents": [
        {
            "_id": "some-new-id",
            "data": {
                "some-attribute": "some-value"
            }
        }
    ],
    //Map of new attributes that will be added to the documents they are listed under. Note that "_id" cannot be added as an attribute
    "values":{
        "some-document-id": {
            "some-new-attribute": "some-new-value"
        }
    }
}

This request returns a list of elements added, and elements skipped.

__/j/db/mod

Modifies attributes of a specific document within a collection.
The format of a Mod, written in JSON, is as follows:

{
    //Collection containing the document. Will fail if this collection does not exist
    "collection": "some-collection",
    //_id of Document to be modified. Will fail if this document does not exist
    "document": "some-document-id",
    //Map of attributes to be changed. Note that the _id can also be changed in this operation.
    "values":{
        "_id": "some-new-id",
        "some-attribute": "some-new-value"
    }
}

This request returns a list of changes made, and changes skipped.

__/j/db/delete

Deletes attributes of a specific document within a collection.
The format of a Delete, written in Json, is very similar to a Mod, as follows:

{
    //Collection containing the document. Will fail if this collection does not exist
    "collection": "some-collection",
    //_id of Document to be modified. Will fail if this document does not exist
    "document": "some-document-id",
    //List of attributes to be deleted. Note that _id cannot be deleted in this operation.
    "values":[
        "some-attribute",
        "another-attribute"
    ]
}

This request returns a list of attributes deleted, and attributes skipped.

__/j/db/purge

Deletes documents from a list of, or all, collections, based on query rules.
See __/j/db/query above, as this request has an identical structure.

This request returns the list of document _ids deleted.


Skips

When performing operations such as Mod or Add, the request body contains rules for finding the targets of the operations. However, these may not always match up with the data, for example, trying to add a document whose _id already exists within that collection. In cases such as these, this part of the operation is skipped, and message is relayed back to the user through the HTTP Response data.



Services

Services are small python scripts that can be assigned to run on specific endpoints.
This feature isn't implemented yet :(

License and Copyright Notice

Copyright (c) 2024, alchemicode. All Rights Reserved. Permission to modify and redistribute is granted under the terms of the Apache 2.0.