npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

zenserver

v1.7.9

Published

a lean and mean http router for node.js

Downloads

111

Readme

ZEN-server

Is the main module of ZEN, that there you will find all necessary tools to create web servers with NodeJS. The main difference from others solutions is the not dependency of third modules, very common in NodeJS projects but that ultimately can create problems.

Our engagement is use the fewer dependencies and offer our experiences with NodeJS easily and intuitive.

ZENserver wants to offer all you need to build applications robust and easy to maintain. Also provides connectors databases with MongoDB and Redis and a connector with APPNIMA.

So, the basic structure of files and folders to work with those features are:

.
├── api
├── common
│   └── models
├── environment
├── www
│   └── index.html
├── package.json
├── zen.js
├── zen.yml

To install a new instance of ZENserver only you have to run this command:

  npm install zenserver --save

Another option is modify the package.json including this new dependency:

{

  "name"            : "zen-server-instance",
  "version"         : "1.0.0",
  "dependencies": {
    "coffee-script" : "*",
    "zenserver"     : "*" },
  "scripts"         : {"start": "node zen.js"},
  "engines"         : {"node": "*"}
}

We include coffee-script package too, because we go to do all examples in this language. But if you want to develop in JavaScript, you can.

We believe that CoffeeScript is more maintainable and legible, so if you want to learn more of CoffeeScript you can download this free book https://leanpub.com/coffeescript.

It is easy to configure ZEN because everything you need is in the configuration file zen.yml. We are goint to analyze these options:

# -- General Info --------------------------------------------------------------
  protocol: http # or https
  host    : localhost
  port    : 8888
  timezone: Europe/Amsterdam

In this section you can set your server configuration, the protocol that you use (http or https), host name, port and timezone.

# -- Environment ---------------------------------------------------------------
  environment: development

With this attribute you can create different configuration files to use in different environments (development, preproduction, production...).

In this example we have established environment so when the server is started searches a file in environment/development.yml route to overwrite the previous configuration on /zen.yml.

# -- RESTful services ----------------------------------------------------------
api:
  - index

# -- HTML pages ----------------------------------------------------------------
www:
  - index

The attributes api and www contain the endpoints of your server. The api is for REST services and the www for others results (HTML, images...).

In this example, ZENserver searches the endpoints /api/index.coffee and /www/index.coffee and will load on the router for further proccesing.

# -- Static resources ----------------------------------------------------------
statics:
  - url     : /temp/resources
    folder  : /static
    maxage  : 60 #secods
  - url     : /img
    folder  : /static/img
  - file    : humans.txt
    folder  : /static
    maxage  : 3600
  - file    : robots.txt
    folder  : /static

This attribute gives us a simple way to provide static files on our server. We can offer complete directories with the url attribute or a specific file by file attribute. In both cases we set the path relative to the project directory using the folder attribute. In case we need to have cache resources we have to set the number of seconds using the attribute maxage.

# -- session -------------------------------------------------------------------
session:
  # Cookie Request
  cookie: zencookie
  domain: ""
  path  : "/"
  expire: 3600 #seconds
  # HTTP Header
  authorization: zenauth

With this attribute we can establish and get easily the session variable for a particular customer. This variable we can get with the attribute cookie.

# -- Monitor -------------------------------------------------------------------
monitor:
  password: mypassword
  process : 10000
  request : 1000

With this attribute we can create an audit to control what happens in our server when it is running. This audit creates a file per day in /logs directory with this information:

  • Endpoint requested.
  • Which methods: GET, POST, PUT, DELETE,...
  • Processing time in milliseconds.
  • HTTP code response.
  • Response length.
  • Client (coming soon).

image

Learn how to use ZENmonitor.

# -- firewall ------------------------------------------------------------------
firewall:
  ip: 100 #Number of request per firewall rule
  extensions:
    - php
    - sql

You can control packets transiting using firewall option. You just need to set extensions that your application is not configured to handle and ZENserver will return 403 Forbidden. Also, with ip parameter you can set a number of maximum requests that a host can do before get into list blacklist.json.

# -- CORS Properties -----------------------------------------------------------
headers:
  Access-Control-Allow-Origin: "*"
  Access-Control-Allow-Credentials: true
  Access-Control-Allow-Methods: GET,PUT,POST,DELETE,OPTIONS
  Access-Control-Max-Age: 1
  Access-Control-Allow-Headers:
    - Accept
    - Accept-Version
    - Content-Length
    - Content-MD5
    - Content-Type
    - Date
    - Api-Version
    - Response-Time
    - Authorization
  Access-Control-Expose-Headers:
    - api-version
    - content-length
    - content-md5
    - content-type
    - date
    - request-id
    - response-time

Finally we set the type of response from our endpoints, to limit access to the same with typical parameters for cross-origin control filtering methods, etc ...

1.3 HTTPS servers

You can create a HTTPS server with ZENserver just setting the protocol attribute and certificates files names:

# -- General Info --------------------------------------------------------------
protocol : https
host     : localhost
port     : 8888
timezone : Europe/Amsterdam

# -- Certificates --------------------------------------------------------------
cert: server.crt
key : server.key

This files must be at *certificates folder at the root of the project. Then you can start your app like always but type in browser: https://127.0.0.1:8888.

  $node zen.js zen

The content of zen.js must be:


require('zenserver').start();

The server runs in the port that you established in zen.yml file. You can overwrite values of zen.yml with command line:

  $node [JS file] [YML file] [ENVIRONMENT] [PORT]
  $node zen zen production 1980

In this example we established that run zen.js file with these attributes:

  • config: Is the configuration file, replacing zen.yml that it is the default file (must be passed without extension yml).
  • production: The name of the file of environment for replace the existing environment attribute in the configuration file zen.yml.
  • 1980: The new port, replacing the declared in zen.yml

Note that it is not mandatory to set all parameters but respect the order thereof. With this, in case you want to assign a new port number, you must pass the following arguments.

As you saw, to work with APIs, we need to store the files into /api folder.

  "use strict"
  module.exports = (zen) ->
      zen.get "/hello", (request, response) ->
        response.json hello: "world"

In this case the exported file hello.coffee GET a single endpoint type and whose has path /hello, the callback that runs whenever you access it gives us two parameters:

  • request: It is the native object NodeJS but powered with zenserver. In later sections we will see the extras options that zenserver offers on this item.
  • response: Like the above is the native object, but as we can see with the (nonexistent in NodeJS) json function comes with extra features.

In this endpoint we are only returning a json object "hello": "world" thanks to .json() method of zenserver.

If we want to capture other methods http we could do it in the same file hello.coffee:

"use strict"

module.exports = (zen) ->

  zen.get "/hello", (request, response) ->
    response.json hello: "world"

  zen.post "/hello", (request, response) ->
    response.json method: "POST"

  zen.put "/api", (request, response) ->
    response.json method: "PUT"

  zen.delete "/api", (request, response) ->
    response.json method: "DELETE"

  zen.head "/api", (request, response) ->
    response.json method: "HEAD"

  zen.options "/api", (request, response) ->
    response.json method: "OPTIONS"

For example, we need an endpoint to get when access to an user and a determinated area like this: /user/soyjavi/messages or /user/cataflu/followers, for this we use the conditional URL /user/:id/:context

http://domain.com/user/soyjavi/messages?order_by=date&page=20

We have an object like this:

  {
    "id"      : "soyjavi",
    "context" : "messages",
    "order_by": "date",
    "page"    : 20
  }

In the following example show how to established the cookie and how to do logout:

  zen.get "/login", (request, response) ->
    response.session "10293sjad092a"
    response.json "cookie": true

  zen.get "/logout", (request, response) ->
    response.logout()
    response.json "cookie": false
  values =
      username: "cataflu",
      name    : "Catalina"
  headers =
    domain    : "http://domain.com"
  response.json values, 201, headers

As you can see it's really simple, but to further facilitate the zenserver things HTTPStatus offers predefined. For example if a given endpoint want to return the client does not have permission just have to call response.badRequest () method and will handle zenserver create a 401 response with the message "Bad Request".

ZENserver offers HTTPStatus predefined:

response.badRequest()

Then list all HTTPStatus: 2xx Successful

200: "ok"
201: "created"
202: "accepted"
204: "noContent"

4xx Client Error

400: "badRequest"
401: "unauthorized"
402: "paymentRequired"
403: "forbidden"
404: "notFound"
405: "methodNotAllowed"
406: "notAcceptable"
407: "proxyAuthenticationRequired"
408: "requestTimeout"
409: "conflict"

5xx Server Error

500: "internalServerError"
501: "notImplemented"
502: "badGateway"
503: "serviceUnavailable"
504: "gatewayTimeout"
505: "HTTPVersionNotSupported"
zen.get "/form", (request, response) ->
  response.html """
    <form action="/form" method="post">
      <input type="text" name="name">
      <input type="text" name="username">
      <input type="file" name="media">
      <input type="submit" value="Submit">
    </form>
  """

We use .html() method to render all HTML code; it is similar to .json().

We are goint to create a file base.mustache in /www/mustache directory with this code:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ZENServer</title>
</head>
<body>
    <header>
        <h1>Hello World!</h1>
        More info & code
        <a href="https://github.com/soyjavi/zen-server" target="_blank">GitHUB</a>
    </header>

</body>
</html>

Now we create a new endpoint (index.coffee) that render create template when access to /:

zen.get "/", (request, response) ->
  response.page "base"

With the method .page() we indicate to ZENserver that search a file with name "base" in /www/mustache directory.

If this file not exists, ZENserver search a 404.mustache file to render. And if you dont create it, ZENserver return a <h1> 404 - Not found</h1> HTML.

We will send details to our staff so that renderize, this is known as data binding. To do this we will modify our base.mustache template:

...
  <h1>Hello World! {{title}}</h1>
...

Now, we send through our enpoints the bingin title:

zen.get "/", (request, response) ->
  bindings =
    title   : "ZENserver"
    session: request.session

  response.page "base", bindings
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{title}}</title>
</head>
<body>
    <header>
        <h1>{{title}}</h1>
        More info & code
        <a href="https://github.com/soyjavi/zen-server" target="_blank">GitHUB</a>
    </header>

    {{> partial.example}}
    {{> partial.session}}
</body>
</html>

We have created two references to mustache block {{> partial.example}} and {{> partial.session}}. We are goint to create in the same level of the rest of mustaches with partial.example.mustache name:

partial.example.mustache

<section>
    <h2>partial.example</h2>
    subdomain: <strong>{{user.name}}</strong>
    mobile: <strong>{{mobile}}</strong>
</section>

partial.session.mustache

<section>
    <h2>partial.session</h2>
    Session: <strong>{{session}}</strong>
    <nav>
        <a href="/session/login">Login</a>
        <a href="/session/logout">Logout</a>
    </nav>
</section>

Now, from our endpoint we completed the new binding:

  zen.get "/", (request, response, next) ->
    bindings =
      title : "zenserver"
      user  :
        name: "@soyjavi"
      session: request.session
      mobile : request.mobile
    partials = ["partial.example", "partial.session"]

    response.page "base", bindings, partials
zen.get "/dashboard", (request, response) ->
  if response.session
    response.page "dashboard", bindings, partials
  else
    response.redirect "/login"

Although NodeJS is not the best way to serve static files zenserver provides a simple and efficient solution for this purpose.

Only we shall have to use the response.file method which will analyze the file type you want to serve and provide the best method of transmission. For example if we are trying to serve some sort of multimedia files such as video or audio, zenserver automatically performs a streaming it. Here's an example:

  zen.get "/vídeo/:id", (request, response) ->
    response.file "/assets/vídeo/#{request.parameters.id}.avi"

As you can see it is very simple, since all zenserver responsibility to decide how to transmit the file is delegated. Noted that in the event that the file did not exist zenserver /assets/vídeo/?.id return a HttpStatusCode 404.

The response.file method will make a small caching on the client, by default 60 seconds, in case you want to increase or decrease the caching, we just have to pass in the second parameter:

  url_file = "/assets/image/tapquo.jpg"
  response.file url_file, maxage = 3600

In this case, we have assigned the file /assets/image/tapquo.jpg a cache on the client 1 hour (3600 seconds).