0.5.22 • Published 17 days ago

atma-server v0.5.22

Weekly downloads
10
License
MIT
Repository
github
Last release
17 days ago

Atma Node.js Server Module

Build Status NPM version

Overview

Can be used as a Connect Middleware

This module uses:

To setup a bootstrap project use Atma.Toolkit - $ atma gen server

HttpApplication

var atma = require('atma-server');
atma
	.server
	.Application({
		base:__dirname,
		configs: '/server/config/**.yml'
	})
	.done(function(app){
		// configuration and resources are loaded
		app
			.processor({
				// pipeline is executed on every request
				before: [
					function(req, res, next){ next() },
				]
				// this pipeline is executed only if the application finds any endpoint
				// (server, handler, page, subapp)
				middleware: [
					// refer to connectjs middleware documentation
					function(req, res, next){ next() },
					require('body-parser').json(),
				],
				// otherwise, if response was not completed by any middleware or any endpoint before
				// continue with this middleware pipeline.
				after: [
					function(req, res, next){ next() },
					atma.server.middleware.static
				]
			})

			// start server, portnumber is taken from the configuration
			.listen();

		// or start the server manually:
		var server = require('http')
			.createServer(app.process)
			.listen(app.config.$get('port'));

		if (app.config.debug)
			app.autoreload(server);
	});

Configuration

appcfg module is used to load the configurations and the routings. Default path is the /server/config/**.yml.

The default configuration can be viewed here - link

Resources

scripts / styles for the NodeJS application itself and for the web pages. They are defined in:

  • config.env.both.scripts<Object|Array>

    	`config/env/both.yml`   - shared resources
  • config.env.server.scripts<Object|Array>

    	`config/env/server.yml` - resources for the nodejs application, e.g. server side components paths.
  • config.env.client.scripts<Object|Array>, config.env.client.styles<Object|Array>

    	`config/env/client.yml` - resources, that should be loaded on the client.
    
    	In the DEV Mode all client-side scripts/styles/components are served to browsers without concatenation.
    	For the production compile resources with `atma custom node_modules/atma-server/tools/compile`
  • Define scripts and styles for a particular page in page routing.

Routing

  • subapps config/app.yml

    	```yml
    	subapps:
    		// all `rest/*` requests are piped to the Api Application
    		// `Api.js` should export the `atma.server.Application` instance
    		'rest': '/../Api.js'
    	```
  • handlers config/handlers.yml

    	```yml
    	handler:
    		location: /server/http/handler/{0}.js
    		#< default
    	handlers:
    		# route - resource that exports a HttpHandler
    		'/foo': 'baz'
    			# path is '/server/http/handler/baz.js'
    			# method is '*'
    
    		'$post /qux': 'qux/postHandler'
    			# path is '/server/http/handler/quz/postHander.js'
    			# method is 'POST'
    	```
  • services config/services.yml

    	```yml
    	service:
    		location: /server/http/service/{0}.js
    		#< default
    	services:
    		# route - resource that exports a HttpService @see HttpService
    		'/user': 'User'
    			# path is '/server/http/service/User.js'
    			# method is '*'
    			# futher routing is handled by the service, like '/user/:id'
    	```
  • pages config/pages.yml

    	```yml
    	page:
    		# see default config to see the default page paths
    
    	pages:
    		# route - Page Definition
    
    		/:
    			id: index #optional, or is generated from the route
    
    			template: quz #optional, or is equal to `id`
    				# path is `/server/http/page/quz/quz.mask
    			master: simple #optional, or is `default`
    				# path is `/server/http/master/simple.mask`
    
    			# optional
    			secure:
    				# optional, default - any logged in user
    				role: 'admin'
    
    			scripts:
    				# scripts for the page
    			styles:
    				# styles for the page
    
    			# any other data, which then is accessable via javascript or mask
    			# `ctx.page.data.title`
    			title: String
    
    			# rewrite the page request to some other route
    			rewrite: String
    
    			# redirect the page request to some other route
    			redirect: String
    	```

Endpoints

There are 4 types of endpoints in route lookup order

Sub Application

We support application nesting, that means you can bind another server application instance for the route e.g. /api/ and all /api/** requests are piped to the app. Each application instance has its own settings and configurations. This allows to create highly modular and composit web-applications.

Handler

To declare a Handler is as simple as to define a Class/Constructor with Deferred(Promise) Interface and process function in prototypes, like this

// server/http/handler/hello.js
module.exports = Class({
	Base: Class.Deferred,
	process: function(req, res){
		this.resolve(
			data String | Object | Buffer,
			?statusCode Number,
			?mimeType String,
			?headers Object
		);
		this.reject(error)
	}
});

To bind for a route(server/config/handlers.yml):

handler:
	location: '/server/http/handler/{0}.js'
	# <- default
handlers:
	'/say/hello': Hello
	'(\.less(\.map)?$)': LessHandler
	'(\.es6(\.map)?$)': TraceurHandler

Usually, this are the low level handlers, like 'less' preprocessor. But the interface (Deferred + process(req, res)) is same also for HttpService and HttpPage

HttpEndpoint

Class and decorators oriented HttpService

import { HttpEndpoint, deco } from 'atma-server'

@deco.route('/foo')
@deco.isAuthorized()
export default class MyEndpoint extends HttpEndpoint {

    @deco.isInRole('admin')
    async '$get /:id' (
        @deco.fromUri('id', Number) id: number
    ) {
        return service.fetch(id)
    }
}

Decorators can be applied to the class or methods

  • HttpEndpoint.isAuthorized()
  • HttpEndpoint.isInRole(...roles: string[])
  • HttpEndpoint.hasClaim(...roles: string[])
  • HttpEndpoint.origin(origin: string = "*")
  • HttpEndpoint.middleware(fn: (req, res?, params?) => Promise<any> | any | void)
  • HttpEndpoint.createDecorator(methods: ICreateDecorator)
  • HttpEndpoint.fromUri(name, Type?)
  • HttpEndpoint.fromBody(Type)

Decorators are also accessable via deco export, e.g.: deco.isAuthorized()

interface ICreateDecorator {
    forCtor (Ctor: Function, meta: IHttpEndpointMeta): Function | void;
    forMethod (Proto: any, method: IHttpEndpointMethod): IHttpEndpointMethod | void
}

HttpService

Service routes

For the route docs refer to RutaJS

Sample:

module.exports = atma.server.HttpService({
	'$get /': Function | Endpoint
	'$post /': ...
	'$get /:name(foo|bar|qux)': ...
	'$put /user': ...
})

Service endpoints

Function
atma.server.HttpService(/*endpoints*/ {
	// route:handler
	'route': function(req, res, params){
		this.resolve(/*@see Handler*/);
		this.reject(...);
	},

	'route': {
		process: function(){ ... }
	}
})
Meta - help & validation
  • help - list all endpoints of a service with there meta information. http://127.0.0.1/rest/user?help
  • validation - when sending data with post/put, httpservice will validate it before processing

    	```javascript
    	atma.server.HttpService({
    		'/route': {
    			meta: {
    				description: 'Lorem...',
    
    				/* For request validating and the documentation */
    				arguments: {
    					// required, not empty string
    					foo: 'string',
    					// required, validate with regexp
    					age: /^\d+$/,
    
    					// optional, of type 'number'
    					'?baz': 'number',
    
    					// unexpect
    					'-quz': null,
    
    					// validate subobject
    					jokers: {
    						left: 'number',
    						right: 'number'
    					},
    
    					// validate arrays
    					collection: [ {_id: 'string', username: 'string'} ]
    				},
    				// allow only properties which are listed in `arguments` object
    				strict: false,
    
    				/* Documentation purpose only*/
    				response: {
    					baz: 'string',
    					...
    				}
    			},
    			process: function(req, res, params) { ... }
    		}
    	})
    	```
    	- *Headers* Set default headers for the service
    	```javascript
    	atma.server.HttpService({
    		'/route': {
    			meta: {
    				headers: {
    					'Access-Control-Allow-Origin': '*',
    					'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept'
    				}
    			},
    			process: function(req, res, params) { ... }
    		}
    	});
    	```
Barricades (Middlewares)
atma.server.HttpService({
	// route - Barricade (Middleware pattern)
	'/route': [
		function(req, res, params, next){
			// error example
			if (req.body.name == null){
				next('Name argument expected');
				return;
			}

			// continue
			req.name = req.body.name;
			next();

			// stop processing
			this.resolve(...);
			this.reject(...);
		},
		function(req, res, params, next){
			...
		},
		...
	],

	// same with `help`
	'/other/route': {
		meta: { ... }
		process: [
			fooFunction,
			bazFunction,
			...
		]
	}
})
Service and the application routing example
// server/http/service/time.js
module.exports = atma.server.HttpService({
	'/': function(req, res){
		this.resolve('This is a time service');
	},
	'/:transport(console|file|client)': function(req, res, params){
		var time = new Date().toString(),
			that = this;
		switch(params.transport){
			case 'console':
				console.log(' > time', time);
				this.resolve('Pushed to console');
				return;
			case 'file':
				io
					.File
					.writeAsync('someFile.txt')
					.pipe(this, 'fail')
					.done(() => {
						this.resolve('Saved to file');
					});
				return;
			case 'client':
				this.resolve(time);
				return;
		}
	}
})
# server/config/services.yml

service:
	location: /server/http/service/{0}.js'
	# <- default

services:
	'/time': time

HttpPage

HttpPage consists of 3 parts

  • Controller
  • Master View Template
  • View Template

You would rare redefine the default controller, as each Page should consist of a component composition, so that the logic could be moved to each component. We wont explain what a component is, as you should refer to MaskJS and MaskJS.Node Some things we remind:

  • Context

    	```javascript
    	{ req: <Request>, res: <Response>, page: <HttpPage (current instance)> }
    	```
  • Render-mode

    	```javascript
    	mode: 'server' | 'client' | 'both' // @default is 'both'
    	modeModel: 'server' // if `server` is defined, the model wont be serialized
    	```
  • Cache Each components output could be cached and the conditions could be defined. - byProperty: For each unique value from model or ct

Example

mask.registerHandler(':requestedUrl', Compo({
	mode: 'server:all'
	modelMode: 'server:all'
	cache: {
		byProperty: 'ctx.req.url'
	},

	onRenderStart: function(model, ctx){
		this.nodes = jmask('h4').text(ctx.req.url);
	}
}))

Going back to the HttpPage, lets start from a master view template

Master View

Refer to the layout component

Example:

// server/http/master/default.mask
layout:master #default {
	:document {

		head {
			meta http-equiv="Content-Type" content="text/html;charset=utf-8";
			meta name="viewport" content="maximum-scale=1.5, minimum-scale=.8, initial-scale=1, user-scalable=1";
			title > "Atma.js"

			atma:styles;
		}
		body {

			@placeholder #body;

			atma:scripts;
		}
	}
}

Page View

// server/http/page/hello.mask
layout:view master=default {
	@content #body {
		'Hello World'
	}
}

The routing is also made via the configuration files

# server/config/pages.yml

pages:
	'/hello':
		id: hello

Preprocessors

E.g., to use ES6 or Less files, please install server plugins

# atma.toolkit, is only a helper util to intall plugins (further on is not required)
$ npm i atma -g
$ atma plugin install atma-loader-traceur
$ atma plugin install atma-loader-less

:copyright: 2014-2015; MIT; The Atma.js Project

0.5.22

17 days ago

0.5.21

3 months ago

0.5.20

1 year ago

0.5.18

1 year ago

0.5.19

1 year ago

0.5.17

2 years ago

0.5.16

2 years ago

0.5.14

2 years ago

0.5.15

2 years ago

0.5.13

2 years ago

0.5.10

2 years ago

0.5.11

2 years ago

0.5.12

2 years ago

0.5.8

2 years ago

0.5.9

2 years ago

0.5.5

3 years ago

0.5.4

3 years ago

0.4.89

3 years ago

0.5.3

3 years ago

0.5.1

3 years ago

0.4.88

3 years ago

0.4.87

3 years ago

0.4.86

3 years ago

0.4.85

3 years ago

0.4.84

3 years ago

0.4.83

3 years ago

0.4.82

4 years ago

0.4.81

4 years ago

0.4.79

4 years ago

0.4.78

4 years ago

0.4.77

4 years ago

0.4.76

4 years ago

0.4.75

4 years ago

0.4.74

4 years ago

0.4.73

4 years ago

0.4.72

4 years ago

0.4.71

4 years ago

0.4.70

4 years ago

0.4.69

4 years ago

0.4.68

4 years ago

0.4.66

4 years ago

0.4.65

4 years ago

0.4.64

4 years ago

0.4.63

4 years ago

0.4.62

4 years ago

0.4.60

4 years ago

0.4.61

4 years ago

0.4.59

4 years ago

0.4.57

4 years ago

0.4.55

4 years ago

0.4.54

4 years ago

0.4.53

4 years ago

0.4.51

4 years ago

0.4.52

4 years ago

0.4.48

4 years ago

0.4.50

4 years ago

0.4.47

4 years ago

0.4.46

4 years ago

0.4.45

4 years ago

0.4.44

4 years ago

0.4.43

4 years ago

0.4.42

4 years ago

0.4.41

4 years ago

0.4.39

4 years ago

0.4.38

4 years ago

0.4.36

4 years ago

0.4.33

4 years ago

0.4.32

4 years ago

0.4.31

4 years ago

0.4.30

4 years ago

0.4.28

5 years ago

0.4.27

5 years ago

0.4.26

5 years ago

0.4.25

5 years ago

0.4.24

5 years ago

0.4.23

5 years ago

0.4.22

5 years ago

0.4.21

5 years ago

0.4.20

5 years ago

0.4.19

5 years ago

0.4.18

5 years ago

0.4.17

5 years ago

0.4.16

5 years ago

0.4.15

5 years ago

0.4.14

5 years ago

0.4.13

5 years ago

0.4.12

5 years ago

0.4.10

5 years ago

0.4.9

6 years ago

0.4.8

6 years ago

0.4.7

6 years ago

0.4.5

6 years ago

0.4.3

6 years ago

0.4.1

6 years ago

0.2.42

6 years ago

0.2.41

6 years ago

0.2.40

6 years ago

0.2.39

7 years ago

0.2.38

8 years ago

0.2.36

8 years ago

0.1.36

8 years ago

0.1.35

8 years ago

0.1.34

8 years ago

0.1.33

9 years ago

0.1.32

9 years ago

0.1.31

9 years ago

0.1.29

9 years ago

0.1.28

9 years ago

0.1.27

9 years ago

0.1.25

9 years ago

0.1.24

9 years ago

0.1.23

9 years ago

0.1.22

9 years ago

0.1.21

9 years ago

0.1.20

9 years ago

0.1.19

10 years ago

0.1.18

10 years ago

0.1.17

10 years ago

0.1.16

10 years ago

0.1.15

10 years ago

0.1.14

10 years ago

0.1.13

10 years ago

0.1.12

10 years ago

0.1.11

10 years ago

0.1.10

10 years ago

0.1.9

10 years ago

0.1.8

10 years ago

0.1.7

10 years ago

0.1.5

10 years ago

0.1.4

10 years ago

0.1.2

10 years ago

0.1.0

10 years ago

0.0.99

10 years ago

0.0.98

10 years ago

0.0.97

10 years ago

0.0.96

10 years ago

0.0.95

10 years ago

0.0.94

10 years ago

0.0.92

10 years ago

0.0.91

10 years ago

0.0.90

10 years ago

0.0.89

10 years ago

0.0.88

10 years ago

0.0.87

10 years ago

0.0.86

10 years ago

0.0.81

10 years ago

0.0.80

10 years ago

0.0.79

10 years ago

0.0.78

10 years ago

0.0.77

10 years ago

0.0.76

10 years ago

0.0.75

10 years ago

0.0.73

10 years ago

0.0.72

10 years ago

0.0.70

10 years ago

0.0.69

10 years ago

0.0.68

10 years ago

0.0.67

10 years ago

0.0.66

10 years ago

0.0.65

10 years ago

0.0.64

10 years ago

0.0.63

11 years ago

0.0.62

11 years ago

0.0.61

11 years ago

0.0.60

11 years ago

0.0.59

11 years ago

0.0.58

11 years ago

0.0.57

11 years ago

0.0.56

11 years ago

0.0.55

11 years ago

0.0.54

11 years ago

0.0.53

11 years ago

0.0.52

11 years ago

0.0.51

11 years ago