How to use Express middleware after Apollo-Server v2 middleware? - node.js

I'm having this weird requirement(because I got nothing on the internet on how to use it. So, I guess it's only me) while using Express and Apollo Server.
I want to use an Express middleware after using the Apollo Server middleware but I can't.
Example:
const { ApolloServer } = require('apollo-server-express');
const express = require('express')
const app = express();
const server = new ApolloServer({typedefs, resolvers})
app.use(...); // Middleware-1
app.use(...); // Middleware-2
app.use(server.getMiddleware()); // Apollo server middleware
app.use(...); // Middleware-3
app.listen({ port: 4000 }, () =>
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
);
In the above code, the Middleware-3 is never being called. I've searched a lot about that but I got nothing.
Is there any way to invoke Middleware-3 after Apollo Server Middleware?
Thank you.
Edit:1
I forgot to mention that I don't want to modify the response from the ApolloServer. I already have some Express middlewares which I don't want to refactor/modify/write completely new ones to be able to use along with Apollo. So, is there any hacky way to follow the app.use() order even after ApolloServer middleware?

You can try to assign
res.end2 = res.end
res.end = ()=>{}
in any middleware called before ApolloMidleware and then call res.end2 to the send response

Apollo Server calls res.end after sending the execution results of your GraphQL request. This finalizes the response, so no other middleware will be called afterward.
If you need to format the response, you can utilize the formatResponse or formatErrors options, but you cannot use Express middleware.

Related

Node.js / express / passport / saml - How to inspect the content of outgoing HTTP request to SAML Identity Provider?

I am a newbie in node.js, but I have a sample application written for node.js that shows the way of integration with specific Identity Provider (SAML). Using this sample app I am trying to inspect what is sent in the HTTP requests made from the node.js backend to the remote IdP. Logging the request headers and body by writing to the console.log would be enough for me. Monitoring the network traffic with some tool like Fiddler is not an option for me, because I cannot run it locally, I need to have the app exposed and I have it deployed to Heroku.
I've tried morgan, but it only intercepts the INCOMING requests. I've also tried global-request-logger, but for some reason it does not inject itself into the express framework and passport. Seems like passport is not using the standard modules for HTTP requests?
The question is: what I need to use to be able to log the content of the HTTP requests made by passport during the .authenticate() call? Is there any flag that I am able to set in passport to enable HTTP logging? Or should I rather do it in express? Or maybe some other package would provide the functionality I need?
EDIT:
My original question was marked as possible duplicate of how to log OUTGOING https requests from node within webstorm
But actually I have already seen that topic and I've tried to setup a hook to http module, it was done this way:
'use strict';
// Setup express.js application:
var express = require('express');
var app = express();
// Patch "http" module with outgoing request logging:
var http = require('http');
const originalRequest = http.request;
http.request = function wrapMethodRequest(req) {
console.log('EXTERNAL OUTGOING REQUEST LOGGING:');
console.log(req.host, req.body);
return originalRequest.apply(this, arguments);
}
This approach was not working. As already said in the original question, it seems that passport does not use standard http module? Or did I something wrong with the code above?
As already mentioned in the original question, I was also trying to handle it via global-request-logger package (which as explained in the possible duplicated post, uses the same technique). The code for that was:
'use strict';
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var passport = require('passport');
var SamlStrategy = require('passport-saml').Strategy;
app.use(bodyParser.urlencoded({ extended: false }));
var globalLog = require('global-request-logger');
globalLog.initialize();
globalLog.on('success', (req, res) => {
console.log('HTTP(S) CALLOUT SUCCESS');
console.log('REQUEST: ', req);
console.log('RESPONSE: ', res);
});
globalLog.on('error', (req, res) => {
console.log('HTTP(S) CALLOUT ERROR');
console.log('REQUEST: ', req);
console.log('RESPONSE: ', res);
});
...

Cannot GET / error using express

I'm new to nodeJS, I'm trying to follow this tutorial.
My code:
// server/index.js
import express from 'express';
import { graphqlExpress, graphiqlExpress } from 'graphql-server-express';
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import bodyParser from 'body-parser';
import { createServer } from 'http';
import { Schema } from './data/schema';
import { Mocks } from './data/mocks';
const GRAPHQL_PORT = 8000;
const app = express();
const executableSchema = makeExecutableSchema({
typeDefs: Schema,
});
addMockFunctionsToSchema({
schema: executableSchema,
mocks: Mocks,
preserveResolvers: true,
});
// `context` must be an object and can't be undefined when using connectors
app.use('/graphql', bodyParser.json(), graphqlExpress({
schema: executableSchema,
context: {}, // at least(!) an empty object
}));
app.use('/graphiql', graphiqlExpress({
endpointURL: '/graphql',
}));
const graphQLServer = createServer(app);
graphQLServer.listen(GRAPHQL_PORT, () => console.log(`GraphQL Server is now running on http://localhost:${GRAPHQL_PORT}/graphql`));
reports an error Cannot GET /
I've read that maybe the createServer function is deprecated, but I'm not sure how to fix it.
When you use express, you have to be explicitly define the routes used by your application. For example, if you define a route with app.get('/hello', handler) then any GET requests to localhost/hello will get routed to that handler. It can then execute whatever logic and return a response, be that a JSON object, a webpage, etc.
Express will only handle the routes you've defined in this way. So if you've only defined a route for requests that GET /hello, it will not know how to GET /foo, or GET your root path /. If you wanted to implement a way to POST or PUT to /hello, that would need to be a different route as well.
You can use app.use in a similar way to implement middleware in your application. While middleware typically takes your request, manipulates it and pass it on, it can also be used to break up your routing logic.
In the case of GraphQL, requests are typically made using the POST method, but the specification does allow for both POST and GET requests. To do this, we would have to define handlers for both app.get('/graphql') and app.post('/graphql'). The graphqlExpress middleware you're importing and using conveniently does that for you.
So with your set up, you've created some routes that allow you to POST to and GET from localhost:8000/graphql. You've also enabled GraphiQL on localhost:8000/graphiql. If you don't see any errors in the console when you start your server, you should be able to navigate to the GraphiQL page at localhost:8000/graphiql and play around with your schema.
But these are the only routes you've set up on your server. If you attempt to navigate anywhere else, like the root at localhost:8000/, express won't know how to handle that request and you will see the error you reported.
Use app.listen(port, function(){console.log('server started')}); instead of createServer(app).

Manually injecting express app via `http.createServer` proxy

I am currently authoring a component for a users sites which adds a number of resources to their server. For my part, I am wanting to use express, but the user could be using express themselves or some other web framework.
Because I want this to just work out of the box, I was attempting to setup my express pipeline via proxying http.createServer. Injecting the pipeline this way seems to work reasonably well in cases where I handle the request, but it fails in cases where I let it fall through and execute the users callback (specifically, it says that the response headers have been sent already).
Here is the sample I am working on. Any ideas?
var http = require('http');
var express = require('express');
var setupProxy = function setupProxy() {
var app = buildApp();
var oldCreateServer = http.createServer;
http.createServer = function(callback) {
return oldCreateServer(function(req, res) {n
app.apply(this, arguments);
if (!res.finished) {
callback.apply(this, arguments);
}
});
};
};
var buildApp = function buildApp() {
var app = express();
app.use('/test', function(req, res) {
res.send('Hello World');
});
return app;
};
I suspect your express handling creates a default 404 response when it doesn't match any of your routes. So, that would be the cause of the headers already sent issue when you are not handling it, but trying to pass it on.
So, I think you need your own 404 handler that writes nothing to the request (e.g. does nothing), but keeps Express from handling it.
Or, another possibility would be to call the user's server callback from your express 404 handler and not elsewhere.

Using express middleware in koa

I have existing code which implements an express middleware. How can I use this middleware in a Koa application?
When I try to call app.use(expressMiddleware) in order to use the middleware in my Koa app, Koa complains that a generator function is required:
AssertionError: app.use() requires a generator function
So I guess that some kind of adapter or trick is needed here... ideas?
Also, you can try koa-connect: https://github.com/vkurchatkin/koa-connect
It looks quite straightforward:
var koa = require('koa');
var c2k = require('koa-connect');
var app = koa();
function middleware (req, res, next) {
console.log('connect');
next();
}
app.use(c2k(middleware));
app.use(function * () {
this.body = 'koa';
});
app.listen(3000);
koa is incompatible with express middleware. (see this blog post for a detailed explaination, especially the part 'Better written middleware').
You could rewrite you middleware for koa. The koa wiki has a special guide for writing middleware.
The req and res that you would receive in an express middleware are not directly available in koa middleware. But you have access to the koa request and the koa response objects via this.request and this.response.
I have create koa2-connect on npm for koa2. https://github.com/cyrilluce/koa2-connect
npm i koa2-connect -S
// usage same as koa-connect
Because koa-connect's author haven't publish next version( npm i koa-connect#next didn't work ), and it is not compatible with webpack-dev-middleware and webpack-hot-middleware.

Mount Koajs app on top of Express

From koajs.com:
app.callback()
Return a callback function suitable for the http.createServer() method to handle a request. You may also use this callback function to mount your koa app in a Connect/Express app.
Now I have an Express app that already starts its own http server. How can I mount a koa app on top of this existing server, so that it shares the same port?
Would I include the koa app as an Express middlware? Do I still use app.callback() for that?
expressapp.use(koaapp.callback()) is fine. but remember, koaapp.callback() does not have a next, so there's no passing errors to the express app or skipping the koaapp once you use it.
it's better to keep them completely separate since their APIs are incompatible
var koaapp = koa()
var expressapp = express()
http.createServer(req, res) {
if (true) koaapp(req, res);
else expressapp(req, res);
})
Since you need a server instance in order to mount a middleware on a specific /prefix, it would be something like
var http = require('http');
var expressApp = require('express');
var koaApp = require('koa');
// ...
expressApp.use('/prefix', http.createServer(koaApp.callback()));

Resources