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

dragonrend

v0.20.5

Published

Node.js Web Framework

Downloads

17

Readme

Build Status version GitHub license

Dragonrend

Dragonrend is productive and fast Node.js framework for building web applications.

All these advantages are achieved due to the fact that there is nothing superfluous. You have only what it is needed for creating Backend apps - no more no less. Then you get easy to read code and performance close to bare Node.

Installation

$ npm install dragonrend

Usage

The framework supports two options for writing code: classic and new way. А new way allows you to create programs due to the extracted functions. This method helps to split the code into blocks that are easier to read. And in the following examples both design options will be shown.

const { dragonrend } = require('dragonrend')

const app = dragonrend()

app.get('/', ctx => ctx.response.json({ message: 'Hi There' }))

app.start(8080).then(() => console.log('Server has been started'))
const { dragonrend } = require('dragonrend')

const { GET, START } = dragonrend()

GET('/', ctx => ctx.response.json({ message: 'Hi There' }))

START(8080, () => console.log('Server has been started'))

API

Context

All middleware functions and handlers get the context object. Context contains the request and response objects by default.

dragonrend(options)

This is builder function, which returns Dragonrend instance.

const { dragonrend } = require('dragonrend')

const app = dragonrend({
  server: false, // your server instance, default: false
  https: false, // object with `key` and `cert` like `https.createServer`, default: false
  http2: false, // true or false, default: false
  noDelay: true, // disable Nagle algorithm, default: false
  errorHandler(e, ctx) { // this is default error handler
    console.log(e)
    ctx.response.status(500).text('Internal Server Error')
  },
  routing: { // default: {}
    prefix: '/api', // default: ''
    notFoundHandler(ctx) { // this is default not found handler
      ctx.response.status(404).text('Not Found')
    }
  },
  autoIncluding: { // default: false
    rootDir: 'dir', // default: process.cwd() (Node.js process directory)
    autoIncludeRoutes: true, // this is default value
    routesDir: 'routes', // this is default value
    autoIncludeMiddleware: true, // this is default value
    middlewareDir: 'middleware', // this is default value
    autoIncludeContentTypeParsers: true, // this is default value
    contentTypeParsersDir: 'parsers' // this is default value
  }
})

Dragonrend Instance

Dragonrend inherits Router.

context(object: Object)

Stores the values you can get from ctx.

// add value
app.context({
  someValue: 'mock'
})

app.get('/path', ctx => {
  const { someValue } = ctx // <- and use it
})
const { CONTEXT, GET } = app

CONTEXT({
  someValue: 'mock'
})

GET('/path', ctx => {
  const { someValue } = ctx // <- and use it
})

addContentTypeParser(contentType: String, fn: Function)

Method add parser of requests body by content type.

app.addContentTypeParser('text/plain', body => {
  return body.toUpperCase()
})
const { PARSER } = app

PARSER('text/plain', body => body.toUpperCase())

Feature: Parsers can be added to the application automatically. Read more in the section "Auto Including".

middleware(...fns: Function)

Adds handler which will called before Router's handler.

// async/await or return promise
app.middleware(async ctx => {
  // do something
})

app.middleware(
  ctx => {},
  ctx => {}
)
const { MIDDLEWARE } = app

MIDDLEWARE(async ctx => {
  // do something
})

MIDDLEWARE(
  ctx => {},
  ctx => {}
)

To break/stop middleware chain you should return false.

const { MIDDLEWARE } = app

MIDDLEWARE(ctx => {
  return false
})

MIDDLEWARE(async ctx => {
  return false
})

MIDDLEWARE(ctx => {
  return Promise.resolve(false)
})

Feature: Middleware-functions can be added to the application automatically. Read more in the section "Auto Including".

setErrorHandler(fn: Function)

fn should have (error, ctx) signature. error is an error occurred, ctx is context.

Sets error handler. By default Dragonrend returns status 500 and body {"error":"Internal Server Error"}.

app.setErrorHandler((error, ctx) => {
  ctx.response.status(500).json({ error: error.message })
})
const { CATCH_ERROR } = app

CATCH_ERROR((error, ctx) => {
  ctx.response.status(500).json({ error: error.message })
})

start(portOrOptions: Number|Object)

Method gets port number or options object like Net server.listen(). Method returns Promise, also it is possible to use callback.

app.start(8080).then(() => console.log('Started'))
// or
app.start({
  host: 'localhost',
  port: 80,
  exclusive: true
}).then(() => console.log('Started'))
const { START } = app

START(8080, () => console.log('Started'))

stop()

Method stops server and returns Promise, also it is possible to use callback.

dragonrend.stop().then(() => console.log('Stopped'))
const { STOP } = app

STOP(() => console.log('Stopped'))

Routing

Routing is performed using Impetuous.

routing(options: Object)

Gets the object with a prefix and not found handler, which appends to all routes of that instance of Router. Returns prepared Router instance.

const router = routing({
  prefix: '/api',
  notFoundHandler() {
    ctx.response.status(404).text('Not Found')
  }
})

NotFound handler

Also NotFound-handler can be set via method or function.

const router = routing()

router.setNotFoundHandler(ctx => {
  ctx.response.status(404).text('Not Found')
})
const { NOT_FOUND } = routing()

NOT_FOUND(ctx => ctx.response.status(404).text('Not Found'))

Classic Express-like routing

Router instance has get, put, patch, post, delete, head, options methods with the same arguments (path: String, ...fn: Function).

const { routing } = require('dragonrend')

const router = routing()

router.get('/path/:param', async ctx => {})

router.post('/path', ({ request, response }) => {})

module.exports = router

GET PUT PATCH POST DELETE HEAD OPTIONS (path: String, ...fn: Function)

These functions add request handlers.

For example, a file with routes may look like this:

const { routing } = require('dragonrend')

const { GET, POST } = module.exports = routing()

GET('/path/:param', async (ctx) => {})

POST('/path', ({ request, response }) => {})

merge(...routers: Router)

Combines one or more instances of Router.

const router1 = routing({ prefix: '/base' })
const router2 = routing()
const router3 = routing({ prefix: '/api' })

router1.merge(router2, router3)
const router1 = routing({ prefix: '/base' })
const router2 = routing()
const router3 = routing({ prefix: '/api' })

const { MERGE } = router1

MERGE(router2, router3)

Instance of Router should be added to Dragonrend

Dragonrend inherits Router, therefore it has method merge.

const app = dragonrend()
const router = routing()
// add some handlers to router
app.merge(router)
// start server...
const { MERGE } = dragonrend()
const router = routing()

MERGE(router)

Feature: Routers can be added to the application automatically. Read more in the section "Auto Including".

Request

Request objects is added to context by default.

Fields of Request instance:

| Field | Description | |---|---| | headers | object, which contains all headers of request | | url | url from request | | method | request's method | | body | parsed request's body | | raw | native Node.js's http Request |

app.middleware(async ctx => {
  const { headers, url, method, raw, query } = ctx.request
  const query = await ctx.request.query() // lazy parsed query
  const body = await ctx.request.body() // lazy parsed body
}

Response

Response objects is added to context by default.

| Method | Description | |---|---| | header(key: String, value: String) | Adds header key-value pair to Response | | status(statusCode: Number) | Sets custom status code to Response, default value is 200 | | json(data: Object) | Sends response with application/json body | | text(data: String) | Sends response with text/plain body | | html(data: String) | Sends response with text/html body | | send(data: String|Buffer, contentType: String) | Sends response with custom body | | raw | Native Node.js' http Response |

app.middleware({ response } => {
  response
    .header('x-total-count', '0')
    .status(201)
    //
    .json({ message: 'Hi There' })
    // or
    .text('Hi There')
    // or
    .html('<p>Hi There</p>')
    // or
    .send(imageBuffer, 'image/jpeg')
})

Return Response

It is possible to return response in middleware function by using returnable wrapper-function.

const { returnable } = require('dragonrend')

app.middleware(returnable(ctx => {
  return {
    status: 201 // default: 200,
    headers: { 'content-type': 'text/plain' } // default: {},
    body: 'body' // default: ''
  }
}))

Response helper-functions

These functions set the content type and in the case of JSON stringify it.

Functions have three call options.

| Option | Description | | --- | --- | | json(body) | one parameter is the request body | | json(status, body) | two parameters are status and body in this order | | json(status, headers, body) | three parameters are status, headers and body in this order |

const { dragonrend, returnable, json, html, text } = require('dragonrend')

const { GET } = dragonrend()

GET('/json', returnable(ctx => json({ message: 'Hi There' })))

GET('/html', returnable(ctx => html(201, '<p>Hi There</p>')))

GET('/text', returnable(ctx => text(201, { 'header': 'value' }, 'Hi There')))

Auto Including

Dragonrend supports auto including of Middleware-functions, Routers and Content Type Parsers. You should follow some rules for this functionality to work.

This feature is disabled by default. You can enable it:

const app = dragonrend({
  autoIncluding: true
})
// or with options
const app = dragonrend({
  autoIncluding: {
    // options
  }
})
  • Files must be in specific directories at the root of project.
    • Middleware-functions in middleware directory.
    • Routers Instances in routes directory.
    • Content Type Parsers in parsers directory.
  • The root directory is the directory that contains the file that is launched very first, i.e. directory of the Node.js process. If you start project with npm script (like npm run start) and all JS files are in src directory and main file is src/index.js, then root is ../src and Auto Including will not work. In this case, it can be customized.
// There are default values of options
const app = dragonrend({
  autoIncluding: {
    routesDir: 'routes',
    autoIncludeMiddleware: true,
    middlewareDir: 'middleware',
    autoIncludeContentTypeParsers: true,
    contentTypeParsersDir: 'parsers',
    rootDir: process.cwd()
  }
})

If you use src directory for example as root of application, then you should set that args:

const app = dragonrend({
  autoIncluding: {
    rootDir: __dirname
  }
})

Parsers

Modules should export an object like that:

module.exports = {
  contentType: 'text/plain',
  parse(body) {
    // do something
    return body
  }
}

Middleware

Modules should export a function.

module.exports = ctx => {
  // do something
}

Router

Router module should export Router instance.

const router = routing()

module.exports = router
const { GET } = module.exports = routing()

Example

You can find an example of using the framework by link. This is a simple Blog implementation with Articles API and JWT-authentication.

Also there is a Profile microservice of a simple social network Artaeum.

Author

Egor Repnikov - GitHub

License

This project is licensed under the MIT License - see the LICENSE file for details