All Projects → thysultan → wam.js

thysultan / wam.js

Licence: MIT License
wam is a koa and next.js inspired middleware framework for node

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to wam.js

interface-doc
The technical specification of the data interface that describes how to integrate the fiskaltrust Middleware into POS systems.
Stars: ✭ 17 (+21.43%)
Mutual labels:  middleware
Guardian
Service Side Swift:Vapor 3 based API Guardian Middleware. 🦁
Stars: ✭ 90 (+542.86%)
Mutual labels:  middleware
laminas-mvc-middleware
Dispatch middleware pipelines in place of controllers in laminas-mvc.
Stars: ✭ 18 (+28.57%)
Mutual labels:  middleware
rbac
RBAC - Simple, concurrent Role Based Access Control(GO)
Stars: ✭ 67 (+378.57%)
Mutual labels:  middleware
fuxedo
An Open Source alternative to Oracle Tuxedo
Stars: ✭ 15 (+7.14%)
Mutual labels:  middleware
koii
A simple middleware for displaying routes in an express application
Stars: ✭ 73 (+421.43%)
Mutual labels:  middleware
express-firebase-middleware
🔥 Express middleware for your Firebase applications
Stars: ✭ 53 (+278.57%)
Mutual labels:  middleware
koa-waterline
Deprecated: A middleware for your hose
Stars: ✭ 14 (+0%)
Mutual labels:  middleware
express-view-cache
Unobtrusive solution to express framework - cache rendered page, without database requests and rendering.
Stars: ✭ 20 (+42.86%)
Mutual labels:  middleware
rack-fluentd-logger
Rack middleware to send traffic logs to Fluentd
Stars: ✭ 21 (+50%)
Mutual labels:  middleware
rmw ecal
ROS2 middleware based on eCAL
Stars: ✭ 30 (+114.29%)
Mutual labels:  middleware
doa
A middleware framework for Deno's http serve🦕. Transplanted from Koa with ❤️
Stars: ✭ 20 (+42.86%)
Mutual labels:  middleware
deepword
Web editor based on Monaco
Stars: ✭ 25 (+78.57%)
Mutual labels:  middleware
mooseware
💀 Skeleton for writing a middleware handler
Stars: ✭ 47 (+235.71%)
Mutual labels:  middleware
ngx-security-starter
A full implementation of the heloufir/security-starter with an Angular 7+ front-end implementation, with a laravel 5.8.* server
Stars: ✭ 37 (+164.29%)
Mutual labels:  middleware
jwt-auth
JSON Web Token Authentication for Laravel and Lumen
Stars: ✭ 46 (+228.57%)
Mutual labels:  middleware
dog
Full repository for the Dog gateway
Stars: ✭ 21 (+50%)
Mutual labels:  middleware
faaskit
A lightweight middleware framework for functions as a service
Stars: ✭ 24 (+71.43%)
Mutual labels:  middleware
redux-simple-auth
A library for implementing authentication and authorization for redux applications
Stars: ✭ 20 (+42.86%)
Mutual labels:  middleware
phpdebugbar
PSR-15 middleware for PHP Debug bar
Stars: ✭ 64 (+357.14%)
Mutual labels:  middleware

wam.js

npm licence dependencies

Wam is a small koa and next.js inspired middleware framework for node the following block of code is a quick run down on what Wam supports out of the box, following that i will try to explain the details of it all.

const Wam = require('wamjs');

const app = new Wam();

// on the fly(as opposed to cached) compression i.e json requests
app.use(app.compress());

// serve static files, cached compression
app.use(app.static('examples/public'));

// component architecture v1 (directory)
app.use(app.components('examples/views', {optDependency: 1}));

// component architecture v2 (custom mappings)
app.use(app.components({'examples/views/index.js': 'index'}, {optDependency: 1}));

// middleware
app.use((context, next) => {});

// route for GET methods on /user/:id
app.use('/user/:id', 'get', (context, next) => { context.params.id === ':id' });

// route for ALL methods on /user/:id
app.use('/user/:id', (context, next) => { context.params.id === ':id' });

// start server
app.listen(3000);

Application

When you execute new Wam() a new application is created. This application object is the main point of entry for communicating with Wam api's. The following is the shape of the object returned by new Wam();

{
	use, listen, callback, create, error, static, 
	compress, router, components, statuses, mimes
}

Use

app.use is used to push a middleware to the stack where context is the object exposing the request and response objects and next is a function that is used to jump to the next middlware in the chain.

app.use(function (context, next) {
	// we will cover in full detail what the context object contains
	// but if you have used Koa before this should be all to familiar
	context.response.body === context.body === this.body;
	context.request.url = context.url === this.url;

	// where req and res represent the default 
	// request and response stream object from node
	this.req === context.req === context.response.req;
	this.res === context.res === context.response.res;

	// if there is another middlware this will execute that
	// if this is the last middlware the response will end
	next();

	// anything after next() call will execute 
	// after all middlwares in the chain
	// have resolved but before the response has been sent

	console.log('hello world');
});

Since routes are just middlwares the app.use function doubles as a route register when the first argument is a String/RegExp

app.use('/user/:name', function (ctx, next) {
	// where the .params property hold the variables
	// found in the url from the defined route
	ctx.params.name;
});

As you may have notices a method has not been specified for the request. When left blank the method resolves to handling all methods of that route but you could also be explicit about it and do the following

app.use('/user/:name', 'ALL' function (ctx, next) {
	// where `ALL` could be `GET` or `POST` or any method
	// or event an array ['get', 'post'] with 
	// just the methods the middlware should handle
});

If you wanted to be very explicit with routes you could also do the following, which is how Wam handles this under the hood.

app.use(app.route('/user/:name', 'ALL', function (ctx, next) {
	// ...
}))

Listen

Creates a server and starts listening for requests on the port 3000

app.listen(3000);

// this is just a short hand of what is internally being handled as
http.createServer(app.callback()).listen(3000);

Static

Creates a middleware that handles requests for static files

// the following will do a couple of things
app.use(app.static('examples/public'));

First it will resolve to the folder and create a tree of all the assets that residing, in the process this will also gzip any compressible assets using file type and file size as an indicator. The results of the above are cached - paths, file stats, and gzip payloads.

When a request is received the middleware will try to determine if the request is for a static asset, if it is and the resource is available, and the body has not been set it will serve the compressed asset as a stream and assign all the necessary headers.

Note that following this flow successfully will result in middlewares after the Static to be bypassed when a static file is request, found and served.

When not in a production enviroment the static files are watched for changes and updated as needed.

Components

Creates a middleware for all the components/files found in the specified directory and passing any dependencies if any the returned function is called like any other middleware when the components route is matched.

// index.js
app.use(app.components('examples/views', {id: 1}));

// examples/views/index.js
module.exports = function ({id}) {
	return function () {
		this.body = id;
	}
}

// when a request is made to `/` the function
// returned in `examples/views/index.js` will handle it.
// the step of calling next is handled internally
// if next is not specified as an argument of the middlware.

You could also be more specific and pass an object of the files - to - route matches to be used, for example...

app.use(app.components({'examples/views': '/'}, {id: 1}));

Compress

Creates a middleware that provides on the fly(non cached) compression for example for json requests. If you wanted to serve static content use Static instead.

app.use(app.compress());

Context

The context object and next function are the two arguments passed to every middlware function. We will start with context and what you can do with it, though if you've used Koa before you are probably familiar with this.

{
	response: {
		// methods
		is:  (types),
		get: (name),
		set: (name, value),
		remove: (name),

		// getters and setters
		type: {(getter|setter)},
		body: {(getter|setter)},
		length: {(getter|setter)},
		message: {(getter|setter)},
		status: {(getter|setter)},
		header: {(getter)},
		lastModified: {(getter|setter)},
		socket: {getter},
		writable: {getter},
		headerSent: {getter},
		etag: {(getter|setter)},
	},

	request: {
		// methods
		is: is(types),
		get: get(name),

	 	// getters and setters
		header: {getter},
		url: {(getter|setter)},
		method: {(getter|setter)},
		path: {(getter|setter)},
		query: {(getter|setter)},
		querystring: {(getter|setter)},
		search: {(getter|setter)},
		origin: {getter},
		href: {getter},
		ext: {getter},
		socket: {getter},
		length: {getter},
		protocol: {getter},
		secure: {getter},
		type: {getter},
		host: {getter},
		ips: {getter},
	},

	// aliased to response 
	remove, set, status, message, body, length, type, 
	lastModified, etag, headerSent, writable

	// aliased to request
	accepts, get, is, querystring, socket, search, method, query, path,
	url, origin, href, protocol, host, hostname, header, secure, ext, ips
}

Next

The next function is a central piece that connects middlewares together, though unlike Koa the next function accepts an optional argument that is used internally but one that you could make use of when needed.

app.use((ctx, next) => {
	// 1. if i pass 0 to next(0)
	// this will immediatly bypass all middelwares 
	// after this middleware and send the response	next(0);
});

app.use((ctx, next) => {
	// 2. if i pass 1 to next(1)
	// this will do the above plus opt out of the built
	// in response handling
	next(1);
});

app.use((ctx) => {
	// 3. if i don't define the next argument
	// next() will automatically run at the end of this function
});

Under The Hood

  1. Wam checks if a stream has a _type property to determine and set the response type if it has one.

  2. stores caches for the .static middlware in the directory provided within a .cache folder. This cache is updated as needed i.e if an asset is removed its gzipped resource is also removed, though this syncing is only in place when not in production mode.

  3. If your filesystem supports the / characters in filenames then you could potentially create a routing solution with just the app.components() middleware.

Intergration

Wam can be used as a general solution with the above listed api's but really shines when coupled with Dio.js and the app.components() api, in part inspired by next.js.

Note that the below will also work when used with any other vdom library making use of something like renderToString/renderToStream meaning you can do the exact following with React, Preact and Inferno minus the renderToCache, and stylesheet.

// views/index.js
module.exports = function ({Component, renderToStream, h, renderToCache}) {
	class Head extends Component {
		render () {
			return h('head',
				h('title', 'Hello World'),
				h('link', {rel: 'stylesheet', href: 'style.css'})
			)
		}
	}

	class Body extends Component {
		render () {
			return h('body', Hello, Button, Button);
		}
	}

	class Button extends Component {
		stylesheet () {
			return `
				{
					color: black;
					border: 1px solid red;
					padding: 10px;
				}
			`
		}
		render () {
			return h('button', 'Click Me');
		}
	}

	class Page extends Component {
		render () {
			return h('html', 
				Head,
				Body
			)
		}
	}
	
	renderToCache([Head]);

	return (ctx) => ctx.body = renderToStream(Page);
}

// index.js
const app = new require('wamjs')();

app.use(app.static('public/'));
app.use(app.components('views/', require('dio.js')));
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].