Here is how my app.js looks like...
I want to know how do I separate this single file into multiple files for better code quality. How do we do that?
My idea is to have the below files...
server.js -> for server related properties
serve.js -> this becomes the main file in the package.json
apis -> this shall be the file with apis, I shd be able to separate apis depending upon the modules too...
What is the preferred convention in NodeJS? I am sure that we do not want to write all apis in one single file.
const express = require('express') // import express module
const app = express() // initiate express app
app.use(express.json()) // not sure what this is but without it POST cant read the JSON parameters from the body
const host = 'localhost' // host
const port = process.env.PORT || 1338 // pick port
const routePrefix = '/' + 'api' + '/' // this is the route prefix used from where the APIs will be accesssed
const routes = { // define routes
root: routePrefix + 'root',
test: routePrefix + 'test',
items: routePrefix + 'items',
item: routePrefix + 'items/:id'
}
// print details
function printDetails(currentRoute, requestMethod, requestParams,
requestQuetyString) {
console.log(currentRoute, requestMethod, requestParams, requestQuetyString);
}
// get root
app.get(routes.root, (req, res) => {
printDetails(routes.root, req.method, req.params, req.query)
res.send(routes.root)
})
// get test route
app.get(routes.test, (req, res) => {
printDetails(routes.test, req.method, req.params, req.query)
res.send(routes.test)
})
// for the web server
app.use(express.static('../public')) // this is where static files reside and need to be served to for the clientside app
// start the API server and Web server
app.listen(port, () => {
console.log(`
\nExpress Server started on port ${port}..
APIs can be accessed at http://${host}:${port}${routePrefix}
Web Server started on port http://${host}:${port}
`)
})
I have tried it on my own and the respective files look like this. However, I am unable to run this.
server.js
const express = require('express') // import express module
const app = express() // initiate express app
app.use(express.json()) // not sure what this is but without it POST cant read the JSON parameters from the body
//const api = require('./apis')
//const app = api.app
const host = 'localhost' // host
const port = process.env.PORT || 1338 // pick port
const routePrefix = '/' + 'api' + '/' // this is the route prefix used from where the APIs will be accesssed
const routes = { // define routes
root: routePrefix + 'root',
test: routePrefix + 'test',
items: routePrefix + 'items',
item: routePrefix + 'items/:id'
}
// for the web server
app.use(express.static('../public')) // this is where static files reside and need to be served to for the clientside app
module.exports = {
app: app,
host: host,
port: port,
routePrefix: routePrefix,
routes: routes
}
serve.js
const server = require('./server') // import server module
//const app = server.app
// start the API server and Web server
server.app.listen(server.port, () => {
console.log(`
\nExpress Server started on port ${server.port}..
APIs can be accessed at http://${server.host}:${server.port}${server.routePrefix}
Web Server started on port http://${server.host}:${server.port}
`)
})
api.js
'use strict'
const server = require('./server') // import sever module
const app = server.app
// get test route
app.get(server.routes.test, (req, res) => {
printDetails(server.routes.test, req.method, req.params, req.query)
res.send(server.routes.test)
})
module.exports = {
}
The problem I am facing is how do I use module.exports and what do I need to export from what module. My requirement is when I run "node serve.js", I should be able to run the APIs and they should be available for the client. How do I achieve this?
I think that the following structure is much more maintainable and easier to understand (also this is the more commonly used structure in new web apps in node):
├───client <-- Your web client application directory
│ └───assets
├───common <-- Common (shared) files between client and server
└───server <-- Your SugoiJS server directory
├───config <-- Build config (environment, webpack)
│ └───webpack
└───src <-- Your server app source code
├───app <-- Bootstrap module, Server initialize and listener files, 'authorization' class(optional)
│ └───classes
├───config <-- Server configuration (services, paths, etc.)
└───modules <-- All of you application modules
└───index <-- Single module
├───controllers <-- Modules' controllers
├───models <-- Modules' models(optional)
└───services <-- Modules' services
This is taken from SugoiJS framework.
https://wiki.sugoijs.com/get-started
Then basically all the routes you are writing will be controllers :)
There are many ways to split up JS code into files, the simplest way (that is still quite efficient) is to require modules. Here's a full guide, and here's a minimal demo:
// lib.js
module.exports = {
x: 10,
y: () => 20
}
// index.js
const lib = require('./lib');
console.log(lib.x); // 10
console.log(lib.y()); // 20
To keep the code clear, simple and efficient, requiring a module should not have any side effects (ie deleting a file, or making requests): for example, define a Class inside a module, and export it.
There are other ways to split up code between files, such as import/export.
Related
I'm just starting with oidc-provider and I can't get express to recognize routes once I include oidc-provider.
In the simple setup below, I get a "unrecognized route on '/'. The well known url for setup does work, and the auth endpoint looks like it does as well.
const express = require('express');
const Provider = require('oidc-provider').Provider;
const app = express();
const configuration = {
// ... see /docs for available configuration
clients: [{
client_id: 'foo',
client_secret: 'bar',
redirect_uris: ['http://192.168.128.128:3000/oidc/cb'],
// ... other client properties
}],
};
const oidc = new Provider('http://localhost:3000', configuration);
app.use('/oidc', oidc.callback());
app.get('/', function(req, res) {
res.send('hello world');
});
oidc.listen(3000, () => {
console.log('oidc-provider listening on port 3000, check http://localhost:3000/.well-known/openid-configuration');
});
I don't understand the whole "mount" notion though I suspect it has something to do with my route problem. Why is this happening? What is the solution?
This is because you are doing:
oidc.listen(...)
And by doing that, you are ignoring all the routes added to app.
What you should do instead is to make the express app to listen, instead of the oidc provider:
app.listen(...)
🙂
I'm developing an SSR Nuxt.js app with an integrated REST API server.
To do this, I've added my /api endpoint inside Nuxt server.js code as following
const express = require('express')
const consola = require('consola')
const { Nuxt, Builder } = require('nuxt')
const app = express()
// Import and Set Nuxt.js options
const config = require('../nuxt.config.js')
config.dev = process.env.NODE_ENV !== 'production'
// MY REST API ENDPOINT (It's the right approach?)
const routesApi = require('./api/routes')
app.use('/api', routesApi)
async function start() {
// Init Nuxt.js
const nuxt = new Nuxt(config)
const { host, port } = nuxt.options.server
await nuxt.ready()
// Build only in dev mode
if (config.dev) {
const builder = new Builder(nuxt)
await builder.build()
}
// Give nuxt middleware to express
app.use(nuxt.render)
// Listen the server
app.listen(port, host)
consola.ready({
message: `Server listening on http://${host}:${port}`,
badge: true
})
}
start()
I didn't found examples related to this approach.
I need some help to understand if it's the right way.
Thank you for your support.
You would probably like to read following article: https://blog.lichter.io/posts/nuxt-with-an-api/
It has common takes to solve "API with Nuxt" case.
Your solution is already enough for small integrated API, I guess, that way you avoid setting up proxy against CORS issues. :) You could add some sugar with serverMiddleware:
// nuxt.config.js
export default {
...
serverMiddleware: [
'/api': '~/api/index.js'
],
...
}
// api/index.js
export default function (req, res, next) {
... // Well, here comes nothing
next()
}
But big API scales nice on separate server, it's also a separation of concerns to consider. Nuxt serves better as universal app rendering middleware, but API can be written even in another language, backend. For defying problems with CORS, you'll need to place /api on same domain, as you intended, thus it's more easier with Nuxt proxy-module.
I've been using Express for a while but suddenly I'm unsure about something pretty basic --
I'm trying to add custom middleware to a KeystoneJS application -- specifically I'm adding a JWT token endpoint to a TinyMCE custom field
The custom field is
export let Wysiwyg = {
type: 'Wysiwyg',
implementation: Text.implementation,
views: {
Controller: Text.views.Controller,
Field: importView('./views/Field'),
Filter: Text.views.Filter,
},
adapters: Text.adapters,
prepareMiddleware,
};
and prepareMiddleware is
function prepareMiddleware() {
const tinymcePath = dirname(require.resolve('tinymce'));
const app = express();
app.use(cors());
app.use('/tinymce-assets', express.static(tinymcePath));
app.post('/jwt', function (req, res) {
// NOTE: Before you proceed with the TOKEN, verify your users' session or access.
const payload = {
sub: '123', // Unique user id string
name: 'John Doe', // Full name of user
// Optional custom user root path
// 'https://claims.tiny.cloud/drive/root': '/johndoe',
exp: Math.floor(Date.now() / 1000) + (60 * 60) // 60 minutes expiration
};
try {
const token = jwt.sign(payload, privateKey, { algorithm: 'RS256'});
res.set('content-type', 'application/json');
res.status(200);
res.send(JSON.stringify({
token: token
}));
} catch (e) {
res.status(500);
res.send(e.message);
}
});
return app;
}
This is all called from a KeystoneJS app that has its own ExpressJS server running. What exactly is the call to express() above doing? The ExpressJS API docs say
**express()**
Creates an Express application. The express() function is a top-level function exported by the express module.
var express = require('express')
var app = express()
I always understood this to be creating a new HTTP server. Surely you don't want to do that twice in a single app unless you're serving on different ports (which I'm not trying to do)?
Similarly, the KeystoneJS docs say
If you need to provide your own custom middleware for your system you
can create a custom App and include it in your exported apps.
class CustomApp {
prepareMiddleware({ keystone, dev, distDir }) {
const middleware = express();
// ...
return middleware;
}
}
Here, again, they're calling express().
What exactly happens when you callexpress()? It starts a new Express app, according to the docs, but I always thought this was equivalent to starting a new server. Surely, I thought, you can't start two servers on the same port.
Thanks for helping clear up my confusion -- I'm obviously not seeing the forest for the trees.
express() basically just creates a stack of middleware functions. It's not a server on its own.
Because it's just a stack of middleware, an Express app can be 'mounted' into another app. An example is shown here (edited for brevity):
var sub2 = express();
sub2.get("/", (req, res) => { res.json({}); });
var app = express();
app.use("/foo", sub2);
Defining and use()ing a new Express instance is really no different from loading any other middleware stack, such as express.Router().
As for binding to ports, usually, you'll only call the listen() helper function on the upper-most Express app instance. All this does is set up a basic HTTP server (so you don't have to) and registers your Express instance as the callback. It's little different from doing http.createServer(options, myUpperMostExpressApp);.
I'm attempting to setup a NodeJS application that is using the Next framework to utilize client and server side rendering. I'm trying to get the client and server side rendering to prepend a path to the routes/URLs it generates. The server side render seems to be working by setting up the express server GET function to listen for requests made on route and then passing that along to node by stripping out the prepended route value. However when it comes the rendering on the client the prepended value is missing even when the as="{somestring}" is added to the .js pages for elements like Link so when the external Next javascript files are referenced in the render it's missing the prepended value.
The purpose for the routing is to allow us to run multiple micro-services on one domain each hosted on different instances in AWS and being routed using Target Groups and an ALB.
Essentially what I want to do is replace / with /{somestring} and I need this to be included not only in the server side rendering but in the client side rendering.
URL Example:
www.example.com -> www.example.com/somestring
HTML Render:
www.example.com/_next/960d7341-7e35-4ea7-baf6-c2e7d457f0db/page/_app.js -> www.example.com/somestring/_next/960d7341-7e35-4ea7-baf6-c2e7d457f0db/page/_app.js
Edit/Update
I've tried to use app.setAssetPrefix and while it renders the requests for the assets correctly and the pages load the assets themselves are 404ing.
Here is my server.js file:
const express = require('express');
const next = require('next');
const port = process.env.PORT || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app
.prepare()
.then(() => {
// Port
const server = express();
app.setAssetPrefix('test1');
// ======
// Routes
// ======
server.get('/test1/:id', (req, res) => {
const actualPage = `/${req.params.id}`;
const queryParams = { id: req.params.id };
app.render(req, res, actualPage, queryParams);
});
server.get('/test1', (req, res) => {
app.render(req, res, '/');
});
server.get('*', (req, res) => {
handle(req, res);
});
// =============
// End of Routes
// =============
server.listen(port, err => {
if (err) throw err;
console.log(`>Listening on PORT: ${port}`);
});
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});
You need custom routing. Parse the incoming url and replace it with what you want.
Here is is an example to make /a resolve to /b, and /b to /a
https://github.com/zeit/next.js#custom-server-and-routing
I would like to develop an Express website that can run either stand-alone or as part of a larger server while allowing a degree of configuration.
For example, say I have a large main server in server.js and I write another server app.js that defines a route /* to provide a small service. I want to be able to either:
run app.js standalone, which will provide its routes through localhost:port/
define a route within server.js that maps to this server, for example so that /app/* will allow app.js to handle requests.
Reading through Smashing Node, I see that if I define an Express server and its routes in app.js, I can use: server.use('/app', require('app.js') to gain use of its routes. The problem with this approach is that I do not see how to pass any configuration options to app.js.
You could write your app.js module as a callable function:
var express = require("express");
var app; // <-- note the global
var initialize = function(conf) {
if (app) {
return app;
}
conf = conf || {};
app = express();
// here goes the configutation code, for example:
if (conf.static) {
app.use(express.static(conf.static));
}
return app;
};
if (require.main === module) {
// if standalone, fire it
initialize({ static: __dirname + "/public" });
}
// and export
module.exports = exports = initialize;
and then in other file:
var app = require("app.js")({ static: __dirname + "/public" });
Note that it is a singleton, so further calls to the module function will return the same server:
app == require("app.js")();
I'm sure you can tweak it to your needs.