How can i pass express Request and Response objects into graphql-yoga context using the createYoga function? - express

I want to pass the express req and res object to my context because i want to use express-sessions to do session-based-auth because the default requests from the context does not know about sessions. Here is what I have tried
app.use("/graphql", (req, res) => {
return createYoga({
context: ({ params }) => {
return {
req,
params,
res,
prisma,
redis: redisClient,
};
},
graphiql: true,
landingPage: false,
cors: false,
schema,
});
});
But if i try this it seems like the request is not going through.

According to the docs, while running in node.js and express runtime, the context will automatically have the request and response.
Server Context
When creating the server instance, GraphQL Yoga accepts an additional
object from your base server framework or library that will be merged
with the default context. Node.js (standalone, express and Next.js
etc.)
If you are using GraphQL Yoga as a standalone server with createServer
from the http(s) module or exposing it as a middleware as we show in
the express or Next.js integration recipes.
req - Node.js IncomingMessage object
res - Node.js ServerResponse object
The req and res objects are added to the initial context object.
const serverContext = { ...defaultContext, req, res }
Thus, when using #graphql-yoga/node, it is possible to access
context.req and context.res within the GraphQL resolvers or the user
context factory function.
However, we recommend avoiding using context.req and context.res
wherever possible and instead favor context.request, as it is more
future-proof and platform independent (as Node.js HTTP servers adopt
the Fetch Response API).
I did try this out and the context does have the req and res objects.

Related

How to handle JWT authentication with RxDB?

I have a local RxDB database and I want to connect it with CouchDB. Everything seems to works fine except for authentication. I have no idea how to add it differently then inserting credentials in database url:
database.tasks.sync({
remote: `http://${username}:${pass}#127.0.0.1:5984/tododb`,
});
I would like to use JWT auth but can't find how to add a token to sync request. I found only some solutions for PouchDB (pouchdb-authentication plugin) but can't get it working with RxDB.
RxDB is tightly coupled with PouchDB and uses its sync implementation under the hood. To my understanding, the only way to add custom headers to a remote PouchDB instance (which is what is created for you when you pass a url as the remote argument in sync), is to intercept the HTTP request:
var db = new PouchDB('http://example.com/dbname', {
fetch: function (url, opts) {
opts.headers.set('X-Some-Special-Header', 'foo');
return PouchDB.fetch(url, opts);
}
});
PouchDB replication documentation (sync) also states that:
The remoteDB can either be a string or a PouchDB object. If you have a fetch override on a remote database, you will want to use PouchDB objects instead of strings, so that the options are used.
Luckily, RxDB's Rx.Collection.sync does not only accept an server url as the remote argument, but also another RxCollection or a PouchDB-instance.
RxDB even reexport the internally used PouchDB module, so you do not have to install PouchDB as a direct dependency.
import { ..., PouchDB } from 'rxdb';
// ...
const remotePouch = new PouchDB('http://27.0.0.1:5984/tododb', {
fetch: function (url, opts) {
opts.headers.set('Authorization', `Bearer ${getYourJWTToken()}`)
return PouchDB.fetch(url, opts);
}
})
database.tasks.sync({
remote: remotePouch,
});

How to create dynamically multiple graphql endpoints on expressjs - nodejs

I'm creating an API where I want to create dynamically multiple graphql endpoints according to the user's preferences without restarting the server.
In general is something very simple, the user will specify the graphql schema and the resolvers, and after the user will push a button to generate a graphql endpoint which will be under the mydomain/randomString
The only code that I can provide so far is how am I creating a graphql endpoint in my expressjs app, which happens on one of the initial files that run when the nodejs server starts.
const {ApolloServer, gql} = require('apollo-server-express');
const typeDefs = gql(fs.readFileSync('./server/graphql/schema.graphql', {encoding: 'utf-8'}));
const resolvers = require ('./server/graphql/resolvers');
const graphqlServer = new ApolloServer({
typeDefs
,resolvers
,engine: {
apiKey: "aRandomString"
}
,introspection: true
// ,context: ({req}) => ({user: req.user && db.users.get(req.user.sub)})
});
After the user generates the endpoint, he/she will be able to query on that graphql endpoint.

Does Feathers Authentication also require app internal service calls to be authenticated (and how to get around)?

I'm building a FeathersJS service behind an authentication very similar to the messages service that is part of the FeathersJS demo chat app: https://github.com/feathersjs/feathers-chat/
Additionally, I'd like to define an event listener that should store the messages it receives to the app's messages service and call all necessary hooks to notify the client application.
Here's my current approach:
module.exports = function () {
const app = this;
const Model = createModel(app);
const paginate = app.get('paginate');
const options = {
name: 'messages',
Model,
paginate
};
app.use('/messages', createService(options));
const service = app.service('messages');
service.hooks(hooks);
const sender = new MyExternalMessageSender();
sender.on('message', (msg) => {
service.create(msg, {user: {_id: 0}}).then(result => console.log(result));
});
if (service.filter) {
service.filter(filters);
}
};
This sometimes works fine and sometimes it randomly results in an error as soon as MyExternalMessageSender is notified and tries to call the message service's create method.
NotAuthenticated: No auth token
at Error.NotAuthenticated (projects\feathers-chat\node_modules\feathers-errors\lib\index.js:100:17)
at projects\feathers-chat\node_modules\feathers-authentication\lib\hooks\authenticate.js:102:31
How can I store messages the correct way without my application itself needing to use a JWT?
Thanks for your support!
I am not sure what MyExternalMessageSender does but authentication is skipped by default in internal service calls. If it is an internal service call is determined by params.provider being set. So if you pass hook.params from an external call (where provider is normally set to rest or socketio) to subsequent service calls authentication will run (since it thinks it is an external call).
This can be avoided by removing the provider property before passing the original parameters e.g. with Lodash _.omit:
myservice.find(_.omit(params, 'provider'))

InversifyJS: dependency instantiation per HTTP Request

I'm using Inversify.JS in a project with Express. I would like to create a connection to a Neo4J Database, and this process has two objets:
The driver object - Could be shared across the application and created one time only
The session object - Each HTTP request should create a session against the driver, whose lifecyle is the same as the http request lifecycle (as long as the request ends, the connection is destroyed)
Without Insersify.JS, this problem is solved using a simple algorithm:
exports.getSession = function (context) { // 'context' is the http request
if(context.neo4jSession) {
return context.neo4jSession;
}
else {
context.neo4jSession = driver.session();
return context.neo4jSession;
}
};
(example: https://github.com/neo4j-examples/neo4j-movies-template/blob/master/api/neo4j/dbUtils.js#L13-L21)
To create a static dependency for the driver, I can inject a constant:
container.bind<DbDriver>("DbDriver").toConstantValue(new Neo4JDbDriver());
How can I create a dependency instantiated only once per request and retrieve them from the container?
I suspect I must invoke the container on a middleware like this:
this._express.use((request, response, next) => {
// get the container and create an instance of the Neo4JSession for the request lifecycle
next();
});
Thanks in advance.
I see two solutions to your problem.
use inRequestScope() for DbDriver dependency. (available since 4.5.0 version). It will work if you use single composition root for one http request. In other words you call container.get() only once per http request.
create child container, attach it to response.locals._container and register DbDriver as singleton.
let appContainer = new Container()
appContainer.bind(SomeDependencySymbol).to(SomeDependencyImpl);
function injectContainerMiddleware(request, response, next) {
let requestContainer = appContainer.createChildContainer();
requestContainer.bind<DbDriver>("DbDriver").toConstantValue(new Neo4JDbDriver());
response.locals._container = requestContainer;
next();
}
express.use(injectContainerMiddleware); //insert injectContainerMiddleware before any other request handler functions
In this example you can retrieve DbDriver from response.locals._container in any request handler/middleware function registered after injectContainerMiddleware and you will get the same instance of DbDriver
This will work, but I'm not sure how performant it is. Additionally I guess that you may need to somehow dispose requestContainer (unbind all dependencies and remove reference to parent container) after http request is done.

How to call an express.js handler from another handler

I'm building an isomorphic React application which is using express.js on the server. The client app makes a number of AJAX requests to other express handler which currently entails them making multiple HTTP requests to itself.
As an optimisation I'd like to intercept requests I know the server handles and call them directly (thus avoiding the cost of leaving the application bounds). I've got as far as accessing the apps router to know which routes it handlers however I'm struggling to find the best way to start a new request. So my question is:
How do I get express to handle an HTTP request that comes from a programatic source rather than the network?
I would suggest create a common service and require it in both the handlers. What I do is break the business logic in the service and create controllers which handles the request and call specific services in this way u can use multiple services in same controller eg.
router.js
var clientController = require('../controllers/client-controller.js');
module.exports = function(router) {
router.get('/clients', clientController.getAll);
};
client-controller.js
var clientService = require('../services/client-service.js');
function getAll(req, res) {
clientService.getAll().then(function(data) {
res.json(data);
}, function(err) {
res.json(err);
});
}
module.exports.getAll = getAll;
client-service.js
function getAll() {
// implementation
}
module.exports.getAll = getAll;
u can also use something like http://visionmedia.github.io/superagent/ to make http calls from controllers and make use of them.