Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 57 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ You need NPM to install folder-router in your NodeJS project.
$ npm install --save folder-router
```

You can now use it in your main server file.
You can now use it in your main server file.
The first parameters must be your express instance, the second one must be the location of your routes directory. I highly recommand to use absolute location.
```js
var app = require('express')();
Expand All @@ -24,8 +24,8 @@ app.listen(3000);

## Creating your routes

In your routes directory, you can create as much as file as you want, everything will be read and add to express by folder-router. A route file MUST export a express.Router() instance as below :
In your routes directory, you can create as much as file as you want, everything will be read and add to express by folder-router. A route file MUST export a express.Router() instance as below:

routes/book.js
```js
var Router = require('express').Router();
Expand All @@ -48,9 +48,9 @@ Here is the list of all end points :
- GET http://localhost:3000/book
- GET http://localhost:3000/book/5
- POST http://localhost:3000/book

-------------
Also, you can create a directory "book" and write your routes like so :
Also, you can create a directory "book" and write your routes like so:
routes/book/book.js
```js
var Router = require('express').Router();
Expand All @@ -69,7 +69,7 @@ Router.post('/', function(req, res) {

module.exports = Router;
```
The name of the file has no impact. The end point remains the same because it takes the name of the sub directory
The name of the file has no impact by default. The end point remains the same because it takes the name of the sub directory

---------

Expand All @@ -95,6 +95,51 @@ module.exports = Router;
module.exports.root = '/book'; // here
```

---------

If you want to use name files as part of the route as well, you can use `useFilenameAsRoot` option like so:

```js
var app = require('express')();
var router = require('folder-router');

router(app, {
location: __dirname + '/routes',
useFilenameAsRoot: true
});

app.listen(3000);
```

So now the endpoints will end up like:

- GET http://localhost:3000/book/book
- GET http://localhost:3000/book/book/5
- POST http://localhost:3000/book/book

Take note that index.js files won't be used as part of the route, for example:

routes/book/index.js
```js
var Router = require('express').Router();

Router.get('/', function(req, res) {
res.end('All Books !');
});

Router.get('/:id', function(req, res) {
res.end('Books with id = ', req.params.id);
});

Router.post('/', function(req, res) {
res.end('Adding a new book')
});
```
It will define the following routes:

- GET http://localhost:3000/book
- GET http://localhost:3000/book/5
- POST http://localhost:3000/book

## Tests

Expand All @@ -107,11 +152,11 @@ $ mocha ./test
```

## Contribute
All ways to contribute to folder-router are highly appreciated:
- improving the readme
- writing features
- writing tests
- writing a tutorial
All ways to contribute to folder-router are highly appreciated:
- improving the readme
- writing features
- writing tests
- writing a tutorial
- troubleshooting reported issues

Thank you very much !
100 changes: 65 additions & 35 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,82 @@
var path = require('path');
var fs = require('fs');

function exist(location) {
try {
var stat = fs.statSync(location);
return (stat.isFile() || stat.isDirectory());
} catch (err) {
return (false);
}
function exist (location) {
try {
const stat = fs.statSync(location);
return (stat.isFile() || stat.isDirectory());
} catch (err) {
return false;
}
}

function handleFolder(app, root, folder) {
var files = fs.readdirSync(folder);
function handleFolder (app, config) {
const { location: folder } = config;
const files = fs.readdirSync(folder);

files.forEach(function(file) {
var absolutePathFile = path.join(folder, file);
analyzeFile(app, root, absolutePathFile);
});
files.forEach((file) => {
const absolutePathFile = path.join(folder, file);
analyzeFile(app, Object.assign({}, config, { location: absolutePathFile }));
});
}

function handleFile(app, root, filepath) {
var fileContent = require(filepath);
var middlewareRoot = '';
function getRoute (fileContent, config) {
const { root, location: filepath, useFilenameAsRoot } = config;

if (fileContent.root) {
middlewareRoot = fileContent.root;
} else {
var location = path.dirname(filepath);
middlewareRoot = location.substr(root.length);
if (useFilenameAsRoot) {
const {name, dir} = path.parse(filepath);
if (name === 'index') {
return dir.substr(root.length);
}
app.use(middlewareRoot, require(filepath));
return path.join(dir, name).substr(root.length);
}

if (fileContent.root) {
return fileContent.root;
}

return path
.dirname(filepath)
.substr(root.length);
}

function analyzeFile(app, root, location) {
var stat = fs.statSync(location);
function handleFile (app, config) {
const { location: filepath } = config;
const fileContent = require(filepath);
let middlewareRoot = getRoute(fileContent, config);

if (stat.isFile())
handleFile(app, root, location);
else if (stat.isDirectory())
handleFolder(app, root, location);
app.use(middlewareRoot, require(filepath));
}

module.exports = function(app, location) {
location = location || './routes';
location = path.resolve(location);
function analyzeFile (app, config) {
const { location } = config;
const stat = fs.statSync(location);

if (!exist(location)) {
throw new Error('Cannot find routes folder');
}
analyzeFile(app, location, location);
if (stat.isFile()) {
handleFile(app, config);
} else if (stat.isDirectory()) {
handleFolder(app, config);
}
}

function getConfig (config) {
if (typeof config === 'string') {
config = { location: config };
}
const { location = './routes', useFilenameAsRoot = false } = config;
const root = path.resolve(location);
return {
location: root,
root,
useFilenameAsRoot
};
}

module.exports = (app, options) => {
const config = getConfig(options);

if (!exist(config.location)) {
throw new Error('Cannot find routes folder');
}
analyzeFile(app, config);
};
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{
"name": "folder-router",
"version": "1.0.4",
"description": "A simple router based on folder name ",
"version": "2.0.0",
"description": "A simple router based on folder name",
"main": "lib/index.js",
"scripts": {
"lint": "semistandard --fix --env mocha",
"pretest": "npm run lint",
"test": "mocha ./test"
},
"repository": {
Expand All @@ -21,14 +23,15 @@
"rest"
],
"author": "dorianamouroux",
"license": "ISC",
"license": "MIT",
"bugs": {
"url": "https://github.com/dorianamouroux/folder-router/issues"
},
"homepage": "https://github.com/dorianamouroux/folder-router#readme",
"dependencies": {},
"devDependencies": {
"express": "^4.13.4",
"mocha": "^5.2.0",
"semistandard": "*",
"supertest": "^1.2.0"
}
}
124 changes: 101 additions & 23 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,109 @@
var request = require('supertest');
const path = require('path');
const request = require('supertest');
const express = require('express');
const router = require('../');

var app = require('./server/app').getApp;
const routesPath = path.join(__dirname, 'server', 'routes');

describe('Test all endpoint', function() {
it('should respond 200 on /', function(done) {
request(app)
.get('/')
.expect(200, done); // note that we're passing the done as parameter to the expect
const createApp = (options = routesPath) => {
const app = express();

router(app, options);

return app;
};

let app;

describe('Test all endpoint', () => {
context('when `options` is a string', () => {
before(() => {
app = createApp();
});

it('should respond 200 on /', (done) => {
request(app)
.get('/')
.expect(200, done); // note that we're passing the done as parameter to the expect
});
it('should respond 200 on /contact', (done) => {
request(app)
.get('/contact')
.expect(200, done); // note that we're passing the done as parameter to the expect
});
it('should respond 200 on /book', (done) => {
request(app)
.get('/book')
.expect(200, done); // note that we're passing the done as parameter to the expect
});
it('should respond 200 on /book/4', (done) => {
request(app)
.get('/book/4')
.expect(200, done); // note that we're passing the done as parameter to the expect
});

it('should respond 200 on /books', (done) => {
request(app)
.get('/books')
.expect(200, done); // note that we're passing the done as parameter to the expect
});
it('should respond 200 on /contact', function(done) {
request(app)
.get('/contact')
.expect(200, done); // note that we're passing the done as parameter to the expect
it('should respond 200 on /books/4', (done) => {
request(app)
.get('/books/4')
.expect(200, done); // note that we're passing the done as parameter to the expect
});
it('should respond 200 on /book', function(done) {
request(app)
.get('/book')
.expect(200, done); // note that we're passing the done as parameter to the expect

it('should respond 200 on /user', (done) => {
request(app)
.get('/user')
.expect(200, done); // note that we're passing the done as parameter to the expect
});
});

context('when `useFilenameAsRoot` is true', () => {
before(() => {
app = createApp({
location: routesPath,
useFilenameAsRoot: true
});
});

it('should respond 200 on /', (done) => {
request(app)
.get('/')
.expect(200, done); // note that we're passing the done as parameter to the expect
});
it('should respond 200 on /contact', (done) => {
request(app)
.get('/contact')
.expect(200, done); // note that we're passing the done as parameter to the expect
});
it('should respond 200 on /book/4', function(done) {
request(app)
.get('/book/4')
.expect(200, done); // note that we're passing the done as parameter to the expect
it('should respond 200 on /books/books', (done) => {
request(app)
.get('/books/books')
.expect(200, done); // note that we're passing the done as parameter to the expect
});
it('should respond 200 on /user', function(done) {
request(app)
.get('/user')
.expect(200, done); // note that we're passing the done as parameter to the expect
it('should respond 200 on /books/books/4', (done) => {
request(app)
.get('/books/books/4')
.expect(200, done); // note that we're passing the done as parameter to the expect
});

it('should respond 200 on /books', (done) => {
request(app)
.get('/books')
.expect(200, done); // note that we're passing the done as parameter to the expect
});
it('should respond 200 on /books/4', (done) => {
request(app)
.get('/books/4')
.expect(200, done); // note that we're passing the done as parameter to the expect
});

it('should respond 200 on /user/user', (done) => {
request(app)
.get('/user/user')
.expect(200, done); // note that we're passing the done as parameter to the expect
});
});
});
Loading