pick-n-mix

a set of tools, untils and polyfulls for writing declarative javascript apps


Keywords
error, error-handling, javascript, try-catch
License
Other
Install
npm install pick-n-mix@0.3.1

Documentation

pick-n-mix

a set of tools, untils and polyfulls for writing declarative javascript apps

errors

A extension mechanism for JavaScript errors

The errors.registry functions registers custom Error constructors

1 registry should be passed a String or Array of strings. Representing the names of the errors you want generated.

2 The generated Errors has a signature if

  • message - String. The description of the problem
  • args - mix. Any arguments that were used
  • rootCause - Error. A lower level error are is being wrapped

3 The new Error Object will have some more attributes

  • type - String. The name of this type of Error
  • fileName - String. The file name - where this error was created
  • lineNumber - Number. The line number - where this error was created
  • columnNumber - Number. The column number - where this error was created
  • functionName - String. The function name - where this error was created
  • createdAt - Number. The time the error was create based on hosts time settings.
  • rootCause - Error. Error that trigger this error. undefined if not set
  • args - mix. Any arguments that were used. undefined if not set
  • processId - Number. The Node process ID if create on a server. undefined if created in brower
  • userAgent - String. The user agent. undefined if created in Node
    • This can be set on Node by using err.setUserAgent(req.headers['user-agent'])

Example:

ES6 modules

During your app startup

import registry from 'pick-n-mix/errors'

registry("BadInput");

Any where you wish to use it

import { BadInputError } from 'pick-n-mix/errors'
//...
if( ! input){
  throw new BadInputError("missing input",input)
}
//...

AMD / Node modules

During your startup

var registry = require('pick-n-mix/errors').registry

registry("Authorization");

Any where you wish to use it

var errors = require('pick-n-mix/errors')
var AuthorizationError = errors.AuthorizationError
//...
if( ! ok){
  throw new AuthorizationError("Bad password",user)
}
//...

πŸŽ‰ Pro Tip: You can pass a descriptive string to registry to indicate error subtype

registry(['Range>InvalidArgument','Internal']);

var invalidErr = new InvalidArgumentError("...")

invalidErr instanceof InvalidArgumentError // true
invalidErr instanceof RangeError           // true
invalidErr instanceof Error                // true

var internalErr = new InternalError("...")

internalErr instanceof InternalError // true
internalErr instanceof RangeError    // false
internalErr instanceof Error         // true

utils

deepRequire

deepRequire will require all sub-files in a folder as a nasted Object.

You must supply the path to the folder deepRequire(dirname) Your can also pass an Array of file extensions. Default:["js"] deepRequire(dirname,exts)

Example:

tools/
 β”œβ”€ index.js
 β”œβ”€rest/
 β”‚   β”œβ”€ get.js
 β”‚   └─ post.js
 └─ list/
     └─ points.js

In tools.index.js

// index.js start
const deepRequire = require('pick-n-mix/utils/deepRequire')
module.exports = deepRequire(__dirname);
// index.js end

In you service code

const tools = require('./tools')

tools.rest.get()

promisify

promisify takes an Object with Async functions using callback functions and loops of the first level attributes wrapping them in a Promise

You must supply the object holding the Async functions. It will then wrap all attributes

promisify(obj)

Your can also pass an Array of attributes not to wrap.

promisify(obj,["skip"])

Example:

Setup you worker object with two function attributes "get_pic" and "name"

const user = {
  get_pic:function(next){
    $.ajax({
      url: "/user/pic/meta",
      error: function(xhr,status,error){
        next(error)
      },
      success: function(result){
        next(null,result)
      }
    });
  },
  name: function(){ return "Bob" }
}

Wrap the worker but skip the "name" function

const promisify = require('pick-n-mix/utils/promisify')
const userP = promisify(user,["name"]);

Use your newly wrapped worker

userP.get_pic().then( function(result){
  console.log(result)
}).catch( function(err){
  console.error(err)
})

console.log(userP.name()) // "bob"

graphql Scheam Builder

Overview

Each custom graphql type will have its own file.

The file looks like

module.exports = {
  description:"Error info",
  model:`{
    type:String!, // type of error
    message:String!, // 'error message'
    args:String!,//arguments
    trace:String!// 'stack trace'
  }`
}

This will be outputted

 # Error info
 #* **type** - type of error,
 #* **message** - 'error message',
 #* **args** - arguments,
 #* **trace** - 'stack trace'
 type Error{
     type:String,
      message:String,
      args:String,
      trace:String
     }

πŸ›ˆ Things to know:

  • Each type will also have a Input version generated for convenience.
 # Error info
 #* **type** - type of error,
 #* **message** - 'error message',
 #* **args** - arguments,
 #* **trace** - 'stack trace'
 input InputError{
     type:String,
      message:String,
      args:String,
      trace:String
     }

How to use

Scheam Builder is designed to be use with deepRequire to pull in your types.

An Example schemas:

sample/
 β”œβ”€ index.js
 β”œβ”€ Error.js
 β”œβ”€ partys.js
 └─ accounts/
     └─ user/
         β”œβ”€ index.js
         └─ item.js

Example Source

You will need to specify the "Query" and "Mutation" strings

const Query = `
  # A GraphQL API for my App
   type Query {
     readUser(id:String):user,
     config:Config,
   }`

const Mutation = `
   type Mutation {
     logError(type:String!, message:String!,args:String!,trace:String!):Error
   }
`

Query and Mutation Api function will map to the same object

var root = {
// Query
readUser: (args)=> db.getUser({_id:args.id}),
config: () => fs.readFileAsync(__dirname + "/config.json"),

// Mutation
logError: (args)=>{
  const type      = args.type;
  const message   = args.message;
  const errorArgs = args.args;
  const trace     = args.trace;

  return db.saveError(message,{type,errorArgs},trace)
           .then( x => args ) // return the error back to use
  },
}

Using the above code snippets

const deepRequire = require('pick-n-mix/utils/deepRequire');
const schemas = deepRequire("./My_schemas_dir");

const schemaQL    = require("pick-n-mix/schemaQL");
const schemaTypes = schemaQL(schemas);

const buildSchema = require('graphql').buildSchema;
const schema = buildSchema(schemaTypes
                            + " " + Query  
                            + " " +  Mutation)

// ================== Express Server
// =================================

const graphqlHTTP = require('express-graphql');
const express     = require('express');

const app = express();

// ======================== Graph QL
// =================================

  app.use('/graphql', graphqlHTTP({
    schema: schema,    rootValue: root,    graphiql: true,
  }));