Giter Club home page Giter Club logo

node-run-middleware's Introduction

NodeJS run-middleware

NodeJS module to execute your Express endpoints (middlewares) from your code. This module will let you manually launch all your middleware. It is simulating a client calling your rest APIs, without using a network connection (your server does not even need to listen on a port).

npm npm version Join the chat at https://gitter.im/node-run-middleware/Lobby Build Status

Why?

Many times, your server and your client, need to execute the same functions. For example here is an endpoint to get user details:

app.get('/get-user/:id', (req, res) => {
  mysql.query('select * from users where id=?', [req.params.id], (err, rows) => {
    res.send({
      user: rows[0]
    });
  });
});

Now you want to get the user details from your code. What should you do?

app.runMiddleware('/get-user/20', (_, body) => {
  console.log(`User details: ${body}`);
});

Installation

npm i -S run-middleware
const express = require('express');
const app = express();
const runMiddleware = require('run-middleware');

runMiddleware(app);

Support & Contributions

  • Pull requests, issues, and English proofreading are welcome on Github.
  • Question & support on StackOverflow using run-middlewaretag.

Change request paramaters

As options you can pass the query, body, method and cookies parameters.

app.runMiddleware('/handler', {
  method: 'post',
  query: {
    token: 'tk-12345'
  },
  body: {
    "action": "list",
    "path": "/"
  }
}, (code, data) => {
  console.log(code, data);
  process.exit(0);
});

Auto pass cookies

When you runMiddleware from another location, you don't have to pass all the parameters of the current middleware to the handler.

app.get('/middleware1', (req, res) => {
  req.runMiddleware( /* ... */ );
})

Redirecting

You can check if the middleware executed will redirect the request by checking the code and the headers.location fields.

app.runMiddleware('/this-middleware-will-response-as-redirect', (code, body, headers) => {
  if (code === 301 || code === 302) { // Redirect HTTP codes
    console.log('Redirect to:', headers.location);
  }
});

Changelog

  • v1.0.0 (25 June 2018) -
  • v0.6.1 (9 Sep 2016) - Supports response.redirect
  • v0.6.2 (10 Sep 2016) - Supports passing cookies and other variables to runMiddleware
  • v0.6.3 (11 Sep 2016) - Supports running middleware from others middleware, for automatically passing cookies and headers between middlewares.
  • v0.6.4 (13 Sep 2016) - Better documentation and examples

Examples

See the tests for further examples.

node-run-middleware's People

Contributors

alice-613 avatar aminadav avatar aminag avatar dependabot[bot] avatar dvdvdmt avatar gitter-badger avatar hotlib avatar jneidel avatar nicksulkers avatar therealpecus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

node-run-middleware's Issues

ERROR TypeError: Cannot read property 'remoteAddress' of undefined

Hello. I'm testing this module to be able to have single api called by socket and by http, but I'm getting this error:

ERROR TypeError: Cannot read property 'remoteAddress' of undefined at forwarded (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/forwarded/index.js:31:35) at alladdrs (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/proxy-addr/index.js:57:15) at proxyaddr (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/proxy-addr/index.js:231:15) at IncomingMessage.ip (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/express/lib/request.js:351:10) at getip (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/morgan/index.js:466:14) at logger (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/morgan/index.js:107:26) at Layer.handle [as handle_request] (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/express/lib/router/layer.js:95:5) at trim_prefix (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/express/lib/router/index.js:317:13) at /Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/express/lib/router/index.js:284:7 at Function.process_params (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/express/lib/router/index.js:335:12) at next (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/express/lib/router/index.js:275:10) at app.use (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/run-middleware/index.js:16:5) at Layer.handle [as handle_request] (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/express/lib/router/layer.js:95:5) at trim_prefix (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/express/lib/router/index.js:317:13) at /Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/express/lib/router/index.js:284:7 at Function.process_params (/Users/osoverflow/IdeaProjects/domitai/dokku/node_modules/express/lib/router/index.js:335:12) +6ms 500 '<h1>Cannot read property &#39;remoteAddress&#39; of undefined</h1>\n<h2></h2>\n<pre></pre>\n' { 'X-Powered-By': 'Express', 'x-powered-by': 'Express' }

Buffers / Stream

I am not sure that this module works well when the original middleware uses Express Steram and buffers.
If you need it in your projects, let me know by comment, and I will check it out.

TypeError: Cannot read property 'pipesCount' of undefined

I am trying to use run-middleware within an angular-fullstack application.

My application is using express for managing sessions and passport.js for authentication (stored in Mongodb). When a user logins in, I want to check if that user already has a living session. I want to use run-middleware to programmatically query mongodb for all the live sessions.

'use strict';

import path from 'path';

import passport from 'passport';
import {Strategy as LocalStrategy} from 'passport-local';


import express from 'express';
import session from 'express-session';


import _ from 'lodash';
import Session from '../../api/session/session.model';


var app = express();

require('run-middleware')(app);


function localAuthenticate(User, email, password, done, req) {
  User.findOne({
    email: email.toLowerCase()
  }).exec()
    .then(user => {

      if (!user) {
        return done(null, false, {
          message: 'This email is not registered.'
        });
      }

      // HERE is where I am trying to use the runMiddleware 
      app.runMiddleware('/sessions',{},function(code,data){
        console.log(code) // 200 
        console.log(data) // { user: '20', name: 'Moyshale' }
      });

      user.authenticate(password, function(authError, authenticated) {
        if (authError) {
          return done(authError);
        }
        if (!authenticated) {
          return done(null, false, { message: 'This password is not correct.' });
        } else {
          return done(null, user);
        }
      });
    })
    .catch(err => done(err));
}

export function setup(User, config) {

  passport.use(new LocalStrategy({
    passReqToCallback: true,
    usernameField: 'email',
    passwordField: 'password' // this is the virtual field on the model
  }, function(req, email, password, done) {
    return localAuthenticate(User, email, password, done, req);
  }));
}

The error I am getting is:

if (state.pipesCount === 0)
           ^
TypeError: Cannot read property 'pipesCount' of undefined
    at IncomingMessage.Readable.unpipe (_stream_readable.js:634:12)
    at unpipe (/home/enview/node_modules/unpipe/index.js:47:12)
    at send (/home/enview/node_modules/finalhandler/index.js:184:3)
    at Immediate.<anonymous> (/home/enview/node_modules/finalhandler/index.js:113:5)
    at Immediate.<anonymous> (/home/enview/node_modules/express/lib/router/index.js:618:15)
    at runCallback (timers.js:568:20)
    at tryOnImmediate (timers.js:546:5)
    at processImmediate [as _immediateCallback] (timers.js:525:5)


async/await usage

Just in case anyone's using this and trying to run in modern Node, the callbacks aren't standard so promisify requires some work to get it behaving.

Not perfect but it's a start if you're trying to reuse connect style middleware with direct calls in something like a cron.

    require('run-middleware')(server);

    server.runMiddleware[util.promisify.custom] = (path, options) => {
        return new Promise((resolve, reject) => {
            server.runMiddleware(path, options, function (code,data,headers) {
                let payload = {code: code, data: data, headers: headers};
                resolve(payload);
            });
        });
    };

    const runMiddlewarePromise = util.promisify(server.runMiddleware);

    const runMiddlewareAsync = async (path, options) => {
        try {
            const middlewareRes = await runMiddlewarePromise(path, options);
            return middlewareRes;
        } catch(e) {
            console.error("NOT IMPLEMENTED: ", e);
            return false;
        }
    };

    // ======= Execute with the following ==============
    let resTest = await runMiddlewareAsync('/my/url',{
                    secure: true,
                    connection: {},
                    method:'GET'                    
                });

    console.log("res Test: ", resTest);

Add headers objects

The new version is passing the header object to the runMiddleware function.
See example.js for more details

Choose a better name and description

I am not sure that developers understand, what this module do. I think it needs better name & desription & documentation.

Please suggest here for names, and description.
Thanks

Remove Lodash depenedency

This module do not really need Lodash, it use Lodash only for one or two functions. If you want me to remove this dependency please comment.

node-run-middleware and helmet or cors = errors

If use node-run-middleware and with helmet or cors or other which get/ remove header ( helmet remove header: res.removeHeader("X-Powered-By") or res.getHeader('Vary') I get errors:

(node:23833) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'etag' of undefined
at ServerResponse.getHeader (_http_outgoing.js:490:24)
at ServerResponse.res.get (/var/www/html/selbi.test/node_modules/express/lib/response.js:789:15)
at IncomingMessage.fresh (/var/www/html/selbi.test/node_modules/express/lib/request.js:478:19)
at ServerResponse.send (/var/www/html/selbi.test/node_modules/express/lib/response.js:206:11)
at ServerResponse.json (/var/www/html/selbi.test/node_modules/express/lib/response.js:267:15)
at ServerResponse.send (/var/www/html/selbi.test/node_modules/express/lib/response.js:158:21)

(node:23833) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 3)
TypeError: Cannot read property 'vary' of undefined
at ServerResponse.getHeader (_http_outgoing.js:490:24)
at vary (/var/www/html/selbi.test/node_modules/vary/index.js:140:17)
at applyHeaders (/var/www/html/selbi.test/node_modules/cors/lib/index.js:151:11)
at applyHeaders (/var/www/html/selbi.test/node_modules/cors/lib/index.js:149:11)
at applyHeaders (/var/www/html/selbi.test/node_modules/cors/lib/index.js:149:11)
at cors (/var/www/html/selbi.test/node_modules/cors/lib/index.js:187:7)

Not support `res.write` that called more than once

The current implementation executes the callback as soon as the the first res.send or res.write or res.end

In ExpressJS, it is possible, to execute multi res.write, but this module not support it yet.

If someone need it please comment, and I will implement it.

Small Error in Docs

The readme has:

//We use res.runMiddleware instead of app.runMiddleware. All the cookies & other data (like socket.io session) will be pass to the second middle ware
res.runMidleware(...) 

There's a small typo runMidleware() is missing an l, but also looking at the code it looks like this function is defined on the req object not the res object.

Lack of working res.getHeaders() breaks res.json() and some middleware. Possible fix suggestion.

When trying to use PassPort sessions middleware app.runMiddleware() results in failure due to problems with getting headers. A similar problem was encountered in Issue #39 with a partial workaround.

Error seen:

node:_http_outgoing:721
  const entry = headers[StringPrototypeToLowerCase(name)];
                       ^
TypeError: Cannot read properties of undefined (reading 'set-cookie')
    at ServerResponse.getHeader (node:_http_outgoing:721:24)
    at setcookie (/node_modules/express-session/index.js:661:18)
    at ServerResponse.<anonymous> (/node_modules/express-session/index.js:243:7)
    at ServerResponse.writeHead (/node_modules/on-headers/index.js:35:16)
    at ServerResponse._implicitHeader (node:_http_server:338:8)
    at writetop (/node_modules/express-session/index.js:276:15)
    at ServerResponse.end (/node_modules/express-session/index.js:343:16)
    at allFailed (/node_modules/passport/lib/middleware/authenticate.js:177:11)
    at attempt (/node_modules/passport/lib/middleware/authenticate.js:183:28)
    at strategy.fail (/node_modules/passport/lib/middleware/authenticate.js:305:9)

References for above error:

Adding the following into createRes() seems to fix the issue while restoring the ability for res.getHeader() to work.

Proposed Solution (submitted in PR #57):

res.getHeader = function(name) {
    if ( 'undefined' !== typeof headers[name] ) {
      return headers[name];
    }
    return null; 
  };

Add res.json(...) support - /w work around

Almost all of my controllers return res.json(...).
run-middleware does not appear to correctly support this.

In express/lib/response.js it tries to see if Content-Type is set as a header, eventually through the getHeader(...) call.
getHeader is implemented a little poorly, expecting "this[kOutHeaders]" to equal null, but instead it is undefined.

That means all res.json(...) calls will fail. I haven't looked at your code, but is your response not extending OutgoingMessage ?

As a workaround, after I did runMiddleware(app), I added this little gem:

app.response.getHeader = (name) => { 
    return null; 
};`

No mocha tests

I can add Mocha+ChaiJS tests to this module. If you need it, just let me know by comment.

setting HTTP status during SSR fails

RunMiddleware creates a strimmed down response object that prevents SSR applications from forwarding a HTTP status code. We hit a case with Angular, where setting the correct status code for some pages works in Express, but fails when the same resource is retrieved via runMiddleware.

In general, I don't think supporting a full Response object would slow down or add excessive complexity to RunMiddleware, but at least provide methods and entries for statusCode and statusMessage.

function createRes(callback) {
  var res = {
    _removedHeader: {},
    _statusCode: 200,
    statusMessage: 'OK'
    get statusCode() {
      return this._statusCode
    },
    set statusCode(status) {
      this._statusCode = status
      this.status(status)
    }
  };

  // some code has been left out

  res.status = res.sendStatus = function(number) {
    console.log('[runMiddleware] res.status', number, res);
    code = number;
    return res;
  };

.end() Doesn't work

If you do something like res.status(200).set('Content-Type', 'text/plain').send('Done!').end(); it doesn't work as .send() doesn't return anything inside the middleware

I guess it doesn't matter too much since I assume calling .end() isn't needed

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.