Is it possible to use application level middleware in express router? - javascript

I've been playing around with setting up a basic atlassian-connect-express (ACE) application, and have modified the starter code provided by the ACE package to be suitable for serverless deployment. One of the problems I faced after doing this was that routing is now divided into stages, e.g. /dev, /prod. I did a bit of research and found that a way to deal with this would be to use an express Router and mount it to the appropriate endpoint for the stage being deployed to. The problem I then faced is that the authentication middleware provided by ACE seems to be application level and then can't be used by each router.
Typically the routes were added to the express app like this:
import ace from 'atlassian-connect-express';
import express from 'express';
import routes from './routes';
const app = express();
const addon = ace(app);
app.use(addon.middleware());
routes(app, addon);
and in ./routes/index.js
export default function routes(app, addon) {
// Redirect root path to /atlassian-connect.json,
// which will be served by atlassian-connect-express.
app.get('/', (req, res) => {
res.redirect('/atlassian-connect.json');
});
// This is an example route used by "generalPages" module (see atlassian-connect.json).
// Verify that the incoming request is authenticated with Atlassian Connect.
app.get('/hello-world', addon.authenticate(), (req, res) => {
// Rendering a template is easy; the render method takes two params:
// name of template and a json object to pass the context in.
res.render('hello-world', {
title: 'Atlassian Connect'
});
});
// Add additional route handlers here...
}
I've changed ./routes/index.js to work as a router object and export that, however this leaves me unable to use the addon.authenticate() middleware
import ace from 'atlassian-connect-express';
import express from 'express';
import routes from './routes';
const app = express();
const addon = ace(app);
app.use('/dev', require('./routes'));
and in ./routes/index.js
const express = require('express');
const router = express.Router();
// Redirect root path to /atlassian-connect.json,
// which will be served by atlassian-connect-express.
router.get('/', (req, res) => {
res.redirect('/atlassian-connect.json');
});
// This is an example route used by "generalPages" module (see atlassian-connect.json).
// Verify that the incoming request is authenticated with Atlassian Connect.
router.get('/hello-world', addon.authenticate(), (req, res) => {
// Rendering a template is easy; the render method takes two params:
// name of template and a json object to pass the context in.
res.render('hello-world', {
title: 'Atlassian Connect'
});
});
module.exports = router;
Obviously having no knowledge of addon, the router cannot use that authentication middleware.
Is it possible to pass that middleware through to the router when attaching it to the application? If not, is there another way I can handle URL prefixes without using a router?

Related

Express.js - prepend sub-route to all defined routes

Let's say I have an Express app defined in a file, say server.js like this:
const app = express();
app.use('/foo', foo);
app.use('/bar', bar);
module.exports = app;
I import this Express app in another file, say index.js:
const app = require('./server');
const port = process.env.PORT || 3000;
const listen = (port) => {
app.listen(port, () => {
console.log(`Backend listening on port ${port}!`);
});
};
listen(port);
Now, the routes that are available for this app are /foo and /bar.
Is there a way to edit configuration in the index.js file so that the routes become /api/foo and /api/bar? Without touching server.js file.
Use case:
I have a Nuxt.js app with a backend that is loaded into the Nuxt app via serverMiddleware property in nuxt.config.js like this:
serverMiddleware: [
...
{ path: '/api', handler: '~/server.js' },
],
This has the effect similar to what I described above: it imports the express app from server.js app and prepends all its routes with /api.
However, often I don't want to develop the frontend part of the Nuxt app, I just want to do changes on the backend. For this purpose I have a helper file like index.js above, which runs backend only. (Frontend often takes long time to compile, that's why I don't want to compile it when I don't need to.)
This creates a problem that all the routes are slightly different - they lack the /api at the beginning. The routes are being used in different tools like Postman etc. and suddenly they wouldn't work.
My current solution is to define index.js file in the same way as server.js file with all routes defined like I want them - instead of app.use('/foo', foo); there's app.use('/api/foo', foo); etc. but this has its own problems, e.g. if I change server.js I have to change index.js. I am looking for something more elegant.
According to the express 4.0 docs https://expressjs.com/en/4x/api.html#app.use you can use an application instance the same as you would a router. In short, just use the export of your server.js as a middleware at the route in which you want to insert it, as opposed to directly calling .listen() on it.
Here is some demo code that worked for me:
const express = require('express');
const app_inner = express();
app_inner.use('/foo', (req,res) => res.send('foo'));
const app_outer = express();
app_outer.use('/foo2', app_inner);
app_outer.listen(9999);
// web browser at localhost:9999/foo2/foo returns 'foo' as expected

Nodejs how can I add another main app.js and use both of them to make my code clean?

Hello I'm using nodejs and express framework and I wrote all my serverside code into my app.js file but it's little bit complicated for me cause cause I have almost 250 line code and I want to implement authentication now so I want to create another app.js to write my code only for auth so other code will not confuse me how can I do that????
UPDATED
as you se above I have 2 post requests from my app.js I asking that how I will get thoso request in my auth.js file cause as I understand exports import for static js field I want to take request and save that information my database and I want to that in my auth.js file
Here are a simplified structure for your project derived from my project at this link.
routes.js:
Create a file named route.js where you define all the routes for your application. In this case the routes will be only the register and the login routes that will be handled by the UserController module.
import { Router } from 'express';
import UserController from './UserController';
const router = Router();
router.post(
'/register',
UserController.register
);
router.post(
'/login',
UserController.login
);
export default router;
UserController.js:
This file/class that handle all the operations for the creation and login of an user
As you can see all the methods has no route url because they are called directly from our route.js file. We are dividing and structuring your application!
export default class UserController {
public static register(req, res) {
// Register operation
}
public static login(req, res) {
// Login operation
}
}
app.js
The entry point and where you are configuring your express application.
import express from 'express';
import routes from './routes';
const app = express();
// configure app ...
// Here we attach our routes url to the express app
app.use('/', routes)
Hope it helps :)
depending on your setup you can divide your files in per example:
app.js
authentication.js
and then either require or import functions from the authentication.js file into app.js like this:
import express from "express";
or this:
const express = require("express");
functions inside the authentication file should be exported like this:
//needs to be imported as this: import {authenticate} from "authenticate";
export function authenticate(){};
//needs to be imported as this: import authenticate from "authenticate";
function authenticate(){};
export default authenticate;
or this:
// needs to be imported as this: const authenticate = require("authenticate");
module.exports = function authenticate(){};
See this guide on enabling ES6 imports as shown above. this has the preference for it can save on memory when importing.

React and Dynamic Routes including Filename and Extension

I am new to React and trying to put a CMS driven application together as kind of a POC. I am majorly stuck on how to get a full URL (including filename and ext) into a dynamic route in a React application. For example if I call this
http://localhost:8080/en/us/fly/index
The dynamic route picks it up. But if I call this
http://localhost:8080/en/us/fly/index.html
I get the following error. Cannot GET /en/us/fly/index.html
It is a requirement that I handle all URLs through my route even if they have a file extension & filename. My routes.jsx is as follows:
import React from 'react';
import {
Switch, Route
} from 'react-router-dom';
// Pages
import Page from "./pages/Page";
class Routes extends React.Component {
render() {
return (
<Switch>
<Route path="/:page" component={Page} />
</Switch>
)
}
}
export default Routes;
and my server.js is as follows:
const path = require('path')
const express = require('express');
const app = express();
const port = process.env.PORT || 8080;
// get an instance of router
const router = express.Router();
// serve static assets normally
router.use(express.static(__dirname + '/dist'))
router.get('*', function (request, response){
response.sendFile(path.resolve(__dirname, 'dist', 'index.html'))
})
// apply the routes to our application
app.use('/', router);
app.listen(port);
console.log('Site available on port ' + port);
How can I get all URLs to pass through my dynamic route? Is this even possible? I need to know if there are limitations in React that prevent this vs how it would work in a traditional ASP.Net MVC application where I can do this kind of dynamic routing.
Any help or advice on this will be very much appreciated as I am very stuck with this and don't fully understand the React world enough to find the solution.
Thanks in advance,
You can use *.* in your route. It matches with file extensions as below
<Route path="*.*" component={YOUR_COMPONENT}/> // matches /hello.jpg and /hello.html
Then you can access the props in your component as
// CMS name: sample.html
this.props.params.splat[0] // For name of prop without extension. It Will give 'sample'
this.props.params.splat[1] // For extension itself. It will give 'html'

Express, diff between route.use() ,route.all(),route.route()

If router.all() just match all methods,could it be instead by router.use()?
and what router.use() diff between router.route()?
router.all: What this means is, it doesn't matter the method of the request.. (post, get, put), if the url matches, execute the function.
ex- router.all("/abc",fn) will be work for all request to /abc
router.use() : router.use() helps you write modular routes and modules.. You basically define a middle ware for routes.
router.use("/pqr", pqrRoutes)
now for all requests that start with /pqr like /pqr/new or /pqr/xyz can be handles inside the pqrRoutes.
router.route(): this is nice way to define the different Method implementations for a single url end point.
lets just say you have two api end points. router.get("/jkl") and router.post("/jkl"), with router.route() you cam sort of combine these different api handlers..
you can say router.route("/jkl").get(fn1).post(fn2)
router.all() matches every http protocol, router.use() is for middleware, and router.route() returns an instance of a single route which you can then use to handle HTTP verbs with optional middleware.
You should check out the documentation for more informations
app.all(), which is not derived from any HTTP method. This method is used for loading middleware functions at a path for all request methods.
app.all('/secret', function (req, res, next) {
console.log('Accessing the secret section ...')
next() // pass control to the next handler
})
Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”.
The following example creates a router as a module, loads a middleware function in it, defines some routes, and mounts the router module on a path in the main app.
var express = require('express')
var router = express.Router()
// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
Bascially we use .use when we use a middleware
express.Router
Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”.
The following example creates a router as a module, loads a middleware function in it, defines some routes, and mounts the router module on a path in the main app.
var express = require('express')
var router = express.Router()
// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
// define the home page route
router.get('/', function (req, res) {
res.send('Birds home page')
})
There can we more than 1 router this instance of router has name router defined below the express defination.
Here is the documentation for router
https://expressjs.com/en/guide/routing.html
Router.use()
Routers behave like middleware and can be .use()d by the app in other routers. In other words, routers allow you to chunk your big app into numerous mini-apps that you can later put together. For small apps, this might be overkill, but as soon as you think, “This app.js file is getting big,” it’s time to think about breaking down your app with routers.
router.route(path)
The router.route(path) method is used to chain HTTP verb methods. For example, in a create, read, update, and
delete (CRUD) server that has POST, GET, PUT, and DELETE endpoints for the /posts/:id URL (e.g., /posts/53fb401
dc96c1caa7b78bbdb), we can use the Router class as follows:
var express = require('express');
var router = express.Router();
router.param('postId', function(request, response, next) {
// Find post by ID
// Save post to request
request.post = {
name: 'Node.js',
url: 'http://your-url/node-js-blog'
};
return next();
});
The Router.route(path) method provides the convenience of chaining methods, which is a more appealing way
to structure, your code than re-typing router for each route.
Alternatively, we can use router.VERB(path, [callback...], callback) to define the routes just as we
would use app.VERB(). Similarly, the router.use() and router.param() methods work the same as app.use() and
app.param().

express - route middle ware how to determine if a response view is already rendered

I have created a custom route middle ware for express js.
Example:
var customRouter = function(req, res, next) {
console.log(res);
next();
};
and in app.js
app.use(app.router); //express default router
app.use(customRouter); //my custom router which comes after express default router
My custom router comes after the express default router. What I'm trying to achieve is that to determine if the default express router have already rendered a response or a view.
How do I determine in my route middleware if a view or a response is already rendered in the express route?
As far as I know, when a middleware sends a response, then next() is not called anymore. So your customRouter is not fired in a case, when default router handles a request.
But anyway, you can always check a response if it was already flushed: res.finished => (boolean)

Categories

Resources