Introduction
anzii is a lightweight, modular, and event-driven Node.js framework for building extensible applications with ease. Perfect for creating APIs, plugins, middleware-based apps, or small web services.
It was designed to be simple, quick to learn and build with. It doesn't matter if you are a designer, developer,or anything in between. If you have a basic understanding of Javascript,you can have your application running in 2 minutes, all with a single line of code.
If you are upgrading: please see UPGRADING.md.
anzii
Features
- Event-driven architecture – handle asynchronous workflows elegantly.
- Plugin-based design – easily extend functionality with modular plugins.
- Routing & middleware – define custom routes and middleware in a clean configuration.
- Clustering support – scale your apps across multiple CPU cores.
- Flexible configuration –
.config.jsoncontrols routing, middleware, logging, and clustering.
Installation
npm install anzii
Quick Guide
import { anzii } from "anzii";
anzii(); // Starts anzii server with default configuration
With Plugins
import { anzii } from "anzii";
import HelloPlugin from "./plugins/Hello.js";
const plugins = {
Hello: HelloPlugin,
};
anzii(plugins);
Configurations
Anzii will look for a .config.json configuration in the root of your project. This configuration file is used to configure your preferences for things such middlewares,routes,static and view directories,etc
Create a .config.json at your project root:
import routes from "./includes/routes";
import * as middlewares from "./includes/globals";
export default {
middleware:
publik: middlewares.public ,
privet: middlewares.pprivate ,
all: middlewares.all ,
}, // Your middlewares configurations
view: true, // Enable rendering web pages
router: routes, // Your api routes
logger: { level: "info" }, // Enable info logging
cluster: { workers: 3, spawn: true }, // Enabble cluster
};
Notes
- middleware – Load global, public, and private middleware functions.
- view – Enable rendering HTML templates or static assets.
- router – Define routes and map them to plugin handlers.
- logger – Control logging levels (info, warn, error, etc.).
- cluster – Scale the server using multiple worker processes.
Routing Examples
In Anzii, every route is an object that contains a couple of properties that determine charateristics of that route:
{
path: '/hello', // Route path with request handler(plugin) name(hello)
method: 'GET', // Use get method for this route
type: 'public', // Make this a publicly available path
},
Every route object represents a handler(plugin) whose task is to handle a request in a request/response lifecycle, more on this shortly.
Anzii plugins
Example Plugin Hello
class Hello {
constructor(pao) {
this.pao = pao; // Every plugin is passed this object
}
init() {
this.listens({
"handle-hello-task": this.handleHelloTask.bind(this), // Event and handling method
}); // Call listens() method (available to every anzii plugin) to set events that this module listens to
} // Define the required init() method
handleHelloTask(data) {
const self = this;
self.callback = data.callback;
const { payload } = data;
const { user } = payload;
const { name, surname } = user; // assume name to be "Ntsako" and surname to be "Mashele"
const message = `Hello ${name} ${surname}, I'm happy to meet you.'`;
return self.callback(null, { message: message });
}
}
export default Hello;
And that's it! The thing is done! Now when you navigate to http://localhost:3000/hello you should see the text Hello Ntsako Mashele, I'm happy to meet you. on your browser.
The data object
Every event-handling method of a plugin receives a data argument which contains data that the event-handling module expects to be able to perform and complete its task. The data argument is sent by an event-emitting module that is in need of a task that the event-handling performs.
In a request/response lifecycle, your request handling module/plugin is sent a data object that your plugin requires to complete its task. The emitted data object contains information needed in a request/response lifecycle. A picture is worth a thousand words, please refer to the request data object below:
{
payload: {
parsed: {
url: '/greeting/Ntsako/Mashele',
handler: 'greeting' //
}, // Request information directly extracted from the request object
user: { name: 'Ntsako', surname: 'Mashele' }, // Parameters or data extracted
handler: 'hello', // Request handling plugin name (sometimes refered to as alias)
request: {
req: [IncomingMessage],
res: [ServerResponse]
} // Request and Response objects for further manipulation (using express framework)
}, // Contains data about the request
callback: [Function: bound taskerHandler] // Method to be called when task is completed
}// Data object
How does it work?
Every anzii plugin you create should include an init() method whose sole purpose is to call this.listen() method. The this.listen() method takes an object that contains a list of events that your plugin should listen to. As an An anzii plugin author, you define a list of events that you want to handle when emitters emit them.
Instead of listening to events, sometimes you create plugins that emit those events,in which case your listeners have to know about your events in order to listen to them to perform whatever task they exist to perform.
The anzii framework is its self made up of plugins building upon its base. These plugins also emit and listen to certain events.
As authors of these plugins/modules, we have defined specific events that we expect interested consumers(listeners) to listen and handle. One of these events is used in the request/response lifecycle and it takes the form handle-pluginname-task. This event is emitted whenever a request is made to a server running anzii.
Any plugin you implement to handle a request should listen to the event of the form handle-pluginname-task where pluginname refers to the name of your plugin.
In the Hello example above,the request is handled by the Hello plugin,so the plugin listens to the handle-hello-task event.
Route Alias
There are cases where you find the use of a handler as part of the route object's pathproperty is undesired. In such a case, you can use a route Alias by adding an alias property in the route object with the name of the handler as the value of the property. See an example below.
Using the Hello example above, the route object with an alias will be written this way:
{
path: '/greeting',
type: 'public',
alias: 'hello'
}
Documentation
Docs coming soon!
we are currently working on our documentation with the help from our first ever collaborater @ntsakosuprise
Questions & Support
For questions and support please use anziijs's Suppport page on Github repo.
Issues
Please make sure to read the Issue Reporting Checklist before opening an issue. Issues not conforming to the guidelines may be closed immediately.
Changelog
Detailed changes for each release are documented in our Changelog.
Release Notes
A summary of release changes can be found in our Release Notes.
Stay In Touch
Contribution
Please make sure to read the Contributing Guide before making a pull request. If you have an anzii plugin, add it with a pull request.
Licence
MIT - see the LICENSE file for details.
copyright (c) 2019-present, iiprodatks. Ntsako (Surprise) Mashele
A Special thanks to Nicholas C. Zakas for the box presentation that help inspire Akii which has inspired anzii.