Comparing version 1.0.0-alpha.19 to 1.0.0-alpha.20
@@ -1,24 +0,50 @@ | ||
# Documentation | ||
# Advanced | ||
> Note: An in-depth *tutorial* coming soon | ||
Some of the concepts that you won't find day-to-day but that might be useful when debugging or creating your own libraries. | ||
To include server, `require` it as a normal Node package: | ||
## Creating middleware | ||
While *plugins are not yet available* you can create middleware just fine and it should be able to cover most developer needs. | ||
## Join routes | ||
If you have two routers and want to make it into one for any reason, you can do so through a helper function we created. | ||
```js | ||
const server = require('server'); | ||
let { get, post, join } = server.router; | ||
let routes = join( | ||
get('/', home.index), | ||
get('/users', users.index), | ||
// ... | ||
); | ||
server({}, acceptsOnlyASingleRoute(routes)); | ||
``` | ||
## Main function | ||
`server` is a function with this signature: | ||
## Experimental | ||
> To enable these, you'll have to add an `EXPERIMENTAL=1` to your environment variables. No need to say that this is not stable and not part of the stable API. | ||
There's an experimental way of dealing with those: | ||
```js | ||
server(options, middleware1, middleware2, ...); | ||
server({}, [ | ||
get('/').send('Hello 世界'), | ||
get('/about.html').file('public/about.html'), | ||
get('/non-existing').status(404).send('Error 404!') | ||
]); | ||
``` | ||
- [Options](options.md) [optional]: an object with the options. [Read more...](options.md). | ||
- [Middleware](middleware.md) [optional]: the middleware that handles requests [Read more...](middleware.md). | ||
They are the same methods as in [Express Methods](http://expressjs.com/en/api.html#res.methods) and accept the same parameters (adding `file`, which is an alias of `sendFile`, and removing `get` and `set` as it conflicts with `Router.get` and `Router.set`). The ones that *do not send* a response can be concatenated, while the ones that send a response will be ignored. So the second *send* will be ignored: | ||
However, it also has the handy property: | ||
- `server.router`: Read the section [Router](router.md) to see how it works. This is **not** the default router from express. | ||
```js | ||
server({}, [ | ||
get('/').status(200).send('Hi there').send('I am ignored') | ||
]); | ||
``` |
@@ -1,2 +0,2 @@ | ||
## Middleware | ||
# Middleware | ||
@@ -6,4 +6,4 @@ One of the most powerful things from express and thus from `server` is the Middleware. We build on this by an evolved concept while giving a wrapper for retro-compatibility: | ||
```js | ||
let setname = s => s.req.user = 'Francisco'; | ||
let sendname = s => s.res.send(s.req.user); | ||
const setname = ctx => ctx.req.user = 'Francisco'; | ||
const sendname = ctx => ctx.res.send(ctx.req.user); | ||
server(setname, get('/', sendname)); | ||
@@ -10,0 +10,0 @@ ``` |
@@ -52,3 +52,3 @@ # Documentation | ||
// Some of the routers available | ||
// Import some of the routers available | ||
const { get, post, put, del } = server.router; | ||
@@ -55,0 +55,0 @@ |
# Router | ||
In the end of the day, routes are just a specific kind of middleware. There are many ways of including them, however we recommend these two: | ||
A router is a function that creates *route(s)*, which in turns tell the server how to handle each request. They are a specific kind of middleware that wraps your logic and acts as a gateway to it: | ||
```js | ||
// Plain middleware for ANY request (NOT a router) | ||
const all = ctx => { /* ... */ }; | ||
// Create a GET route for the users page | ||
const users = get('/users', ctx => { /* ... */ }) | ||
``` | ||
## Simple router | ||
The `ctx` variable is [explained in the middleware documentation](https://serverjs.io/documentation/middleware/#context). One important difference between the routes and middleware is that [**all routes are final**](routes-are-final). This means that **each request will use one route at most**. | ||
All of the routers reside within the `server.router` and follow this structure: | ||
```js | ||
const server = require('server'); | ||
const { NAME } = server.router; | ||
const doSomething = NAME(ID, fn1, [fn2], [fn3]); | ||
server(doSomething); | ||
``` | ||
## REST | ||
The [basic REST routers](http://stackoverflow.com/q/671118/938236) are present: `get`, `post`, `put`, `del`. Delete is called `del` since 'delete' is a reserved word in Javascript. This is the recommended way of importing the routers with destructuring: | ||
```js | ||
const server = require('server'); | ||
const { get, post, put, del } = server.router; | ||
``` | ||
> TODO: create a tutorial as I couldn't find any decent one for this: | ||
They all [accept a path in a similar way to Express.js](http://expressjs.com/en/4x/api.html#router) as ID, which will be parametrized: | ||
```js | ||
const server = require('server'); | ||
const { get } = server.router; | ||
// Homepage | ||
get('/', ctx => { /* ... */ }); | ||
// A specific page | ||
get('/users', ctx => { /* ... */ }); | ||
// Any page such as /contact, /users, /125, etc | ||
get('/:page', ctx => { /* ... */ }); | ||
``` | ||
### Simple router | ||
To define a simple router, you could do: | ||
@@ -25,3 +74,3 @@ | ||
## Complex router | ||
### Complex router | ||
@@ -33,5 +82,5 @@ If you are going to have many routes, we recommend splitting it into a separated file, either in the root of the project as `routes.js` or in a different place: | ||
const server = require('server'); | ||
let routes = require('./routes'); | ||
const routes = require('./routes'); | ||
server(3000, routes); | ||
server(routes); | ||
``` | ||
@@ -41,4 +90,4 @@ | ||
// routes.js | ||
let { get, post } = require('server').router; | ||
let ctrl = require('auto-load')('controllers'); | ||
const { get, post } = require('server').router; | ||
const ctrl = require('auto-load')('controllers'); | ||
@@ -57,27 +106,21 @@ // You can simply export an array of routes | ||
## Error | ||
## Express router | ||
> Explain about the router error: `const { error } = server.router;` and how it handles the errors thrown: `throw new Error()` || `ctx.throw('test:a')?` | ||
You can also use the express router: | ||
```js | ||
const server = require('server'); | ||
let router = server.express.Router(); | ||
router.get('/', home.index); | ||
router.get('/users', users.index); | ||
// ... | ||
## Websockets | ||
server({}, router); | ||
``` | ||
> *Not yet available, coming in version 1.1* | ||
However, we recommend using server's router whenever possible: | ||
```js | ||
const server = require('server'); | ||
let { get, post } = server.router; | ||
let { get, socket } = server.router; | ||
server({}, [ | ||
get('/', home.index), | ||
get('/users', users.index) | ||
get('/', (req, res) => res.sendFile(__dirname + '/public/index.html')), | ||
socket('message', (data, socket, io) => { | ||
io.emit(data); | ||
}) | ||
]); | ||
@@ -87,59 +130,10 @@ ``` | ||
## Retrocompatibility | ||
## Join routes | ||
> Explain about the wrapper for all the middleware out there | ||
If you have two routers and want to make it into one for any reason, you can do so through a helper function we created. | ||
```js | ||
let { get, post, join } = server.router; | ||
## Routes are final | ||
let routes = join( | ||
get('/', home.index), | ||
get('/users', users.index), | ||
// ... | ||
); | ||
server({}, acceptsOnlyASingleRoute(routes)); | ||
``` | ||
## Experimental | ||
> To enable these, you'll have to add an `EXPERIMENTAL=1` to your environment variables. No need to say that this is not stable and not part of the stable API. | ||
There's an experimental way of dealing with those: | ||
```js | ||
server({}, [ | ||
get('/').send('Hello 世界'), | ||
get('/about.html').file('public/about.html'), | ||
get('/non-existing').status(404).send('Error 404!') | ||
]); | ||
``` | ||
They are the same methods as in [Express Methods](http://expressjs.com/en/api.html#res.methods) and accept the same parameters (adding `file`, which is an alias of `sendFile`, and removing `get` and `set` as it conflicts with `Router.get` and `Router.set`). The ones that *do not send* a response can be concatenated, while the ones that send a response will be ignored. So the second *send* will be ignored: | ||
```js | ||
server({}, [ | ||
get('/').status(200).send('Hi there').send('I am ignored') | ||
]); | ||
``` | ||
## Websockets | ||
> *Not yet available, coming in version 1.1* | ||
```js | ||
const server = require('server'); | ||
let { get, socket } = server.router; | ||
server({}, [ | ||
get('/', (req, res) => res.sendFile(__dirname + '/public/index.html')), | ||
socket('message', (data, socket, io) => { | ||
io.emit(data); | ||
}) | ||
]); | ||
``` | ||
> Explain how a route is matched only once |
@@ -1,2 +0,2 @@ | ||
# Documentation | ||
# server() | ||
@@ -3,0 +3,0 @@ > Note: An in-depth *tutorial* coming soon |
@@ -1,3 +0,2 @@ | ||
module.exports.noheader = block => { | ||
return block.replace(/<h1[^>]*>[^<]*<\/h1>/, ''); | ||
} | ||
// Should be okay | ||
module.exports.noheader = block => block.replace(/<h1.*>.+?<\/h1>/g, ''); |
@@ -10,1 +10,7 @@ # WEBSITE | ||
[**documentation folder**](documentation) | ||
Which can also be accessed through the website: | ||
[**documentation in the website**](https://serverjs.io/documentation) | ||
> Note: I've contacted Github about how ridiculous it is to have to name the *web* as *docs* and suggested that they allow the name... *web*. They answered quickly and said it was in their tasklog, so kudos :+1:. |
@@ -0,1 +1,3 @@ | ||
// THESE ARE JUST IDEAS; THEY MIGHT OR MIGHT NOT WORK | ||
// Include the server in your file | ||
@@ -6,12 +8,13 @@ let server = require('server'); | ||
// This compares simple implementations; not expected to be the typical ones | ||
// Initialize the server on port 3000 | ||
server({ port: 3000 }, | ||
server( | ||
// default | ||
get('/', (req, res) => res.send('hello 世界')), | ||
get('/', (req, res) => res.json({ hello: '世界' })), | ||
get('/', (req, res) => res.file('./public/index.html')), | ||
get('/', (req, res) => res.status(400).render('index.pug', {})), | ||
// +direct +simple +express +koa -WET | ||
get('/', ctx => ctx.res.send('hello 世界')), | ||
get('/', ctx => ctx.res.json({ hello: '世界' })), | ||
get('/', ctx => ctx.res.file('./public/index.html')), | ||
get('/', ctx => ctx.res.status(400).render('index.pug', {})), | ||
// +clean +standard +direct +chainable -complex(inside) | ||
// +clean +standard +direct +chainable -complex(inside) -confusing | ||
get('/').send('hello 世界'), | ||
@@ -18,0 +21,0 @@ get('/').json({ hello: '世界' }), |
{ | ||
"name": "server", | ||
"version": "1.0.0-alpha.19", | ||
"version": "1.0.0-alpha.20", | ||
"description": "A modern and powerful server for Node.js", | ||
@@ -31,3 +31,3 @@ "main": "server.js", | ||
"human-error": "^0.2.0", | ||
"loadware": "^1.0.0", | ||
"loadware": "^2.0.0", | ||
"method-override": "^2.3.7", | ||
@@ -34,0 +34,0 @@ "path-to-regexp-wrap": "0.0.4", |
@@ -28,3 +28,3 @@ // Modules - All of the modules that are loaded by default | ||
plugin.middle = [ | ||
plugin.before = [ | ||
@@ -31,0 +31,0 @@ // Public folder |
# **Server** for Node.js | ||
<blockquote class="error">This is alpha software; use at your own risk</blockquote> | ||
Simple and powerful server that just works so **you can focus on your awesome project**: | ||
@@ -4,0 +6,0 @@ |
@@ -52,3 +52,7 @@ // server for Node.js (https://serverjs.io/) | ||
// PLUGIN middleware | ||
middle = join(plugins.map(p => p.middleware || p.middle), middle); | ||
middle = join( | ||
plugins.map(p => p.beforeware || p.before), | ||
middle, | ||
plugins.map(p => p.afterware || p.after) | ||
); | ||
@@ -55,0 +59,0 @@ // Main thing here |
@@ -0,1 +1,2 @@ | ||
// Perform the routing required | ||
const join = require('../join'); | ||
@@ -5,21 +6,28 @@ const params = require('path-to-regexp-wrap')(); | ||
// Generic request handler | ||
// TODO: optimize? by extracting params(path) outside | ||
const generic = (method, ...middle) => ctx => { | ||
const generic = (method, ...middle) => { | ||
// A route should be solved only once | ||
if (ctx.req.solved) return; | ||
// Only for the correct methods | ||
if (method !== ctx.req.method) return; | ||
// Only do this if the correct path | ||
// Extracted or otherwise it'd shift once per call; also more performant | ||
const path = typeof middle[0] === 'string' ? middle.shift() : '*'; | ||
ctx.req.params = params(path)(ctx.req.url); | ||
if (!ctx.req.params) return; | ||
const match = params(path); | ||
middle = join(middle); | ||
// Perform this promise chain | ||
return join(middle)(ctx).then(ctx => { | ||
ctx.req.solved = true; | ||
return ctx; | ||
}); | ||
return ctx => { | ||
// A route should be solved only once per request | ||
if (ctx.req.solved) return; | ||
// Only for the correct method | ||
if (method !== ctx.req.method) return; | ||
// Only do this if the correct path | ||
ctx.req.params = match(ctx.req.url); | ||
if (!ctx.req.params) return; | ||
// Perform this promise chain | ||
return middle(ctx).then(ctx => { | ||
ctx.req.solved = true; | ||
return ctx; | ||
}); | ||
}; | ||
}; | ||
@@ -26,0 +34,0 @@ |
@@ -19,3 +19,3 @@ let request = require('request'); | ||
}; | ||
return poster(middle, data, { middle: false }); | ||
return poster(middle, data, { middle: false }).catch(console.log); | ||
}); | ||
@@ -25,2 +25,3 @@ | ||
let middle = ctx => { | ||
expect(ctx.req.body).toBeDefined(); | ||
expect(ctx.req.body.hello).toBe('世界'); | ||
@@ -33,3 +34,3 @@ expect(ctx.req.headers['content-type']).toBe('application/x-www-form-urlencoded'); | ||
it('bodyParser can be cancelled', () => { | ||
it.only('bodyParser can be cancelled', () => { | ||
let middle = ctx => { | ||
@@ -36,0 +37,0 @@ expect(ctx.req.body).toEqual({}); |
let request = require('request'); | ||
let server = require('../server'); | ||
let { get, post, put, del } = server.router; | ||
let { get, post, put, del, error } = server.router; | ||
@@ -18,3 +18,3 @@ let port = 3000; | ||
opts = Object.assign({}, { port: port }, opts); | ||
return server(opts, middle); | ||
return server(opts, middle, error('*', ctx => console.log('Error:', ctx.error))); | ||
}; | ||
@@ -27,3 +27,3 @@ | ||
let options = Object.assign({}, { | ||
url: 'http://localhost:' + port + '/', | ||
url: 'http://localhost:' + ctx.options.port + '/', | ||
gzip: true | ||
@@ -30,0 +30,0 @@ }, opts); |
@@ -1,4 +0,4 @@ | ||
let request = require('request'); | ||
const request = require('request-promise-native'); | ||
let server = require('../server'); | ||
let { get, post, put, del } = server.router; | ||
let { get, post, put, del, error } = server.router; | ||
let { handler, getter, poster } = require('./helpers'); | ||
@@ -22,2 +22,22 @@ | ||
it('loads as an array', done => { | ||
getter([ctx => ctx.res.send('Hello 世界')]).then(res => { | ||
expect(res.body).toBe('Hello 世界'); | ||
done(); | ||
}); | ||
}); | ||
// A bug shifted the router's middleware on each request so now we test for | ||
// multiple request to make sure the middleware remains the same | ||
it('does not modify the router', done => { | ||
launch([get('/w', ctx => ctx.res.send('w'))].concat(routes)).then(ctx => { | ||
const url = 'http://localhost:' + ctx.options.port + '/'; | ||
request(url).then(() => request(url)).then(() => request(url)).then(body => { | ||
ctx.close(); | ||
expect(body).toBe('Hello 世界') | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it('can perform a simple post', () => { | ||
@@ -24,0 +44,0 @@ let reply = ctx => ctx.res.send('Hello ' + ctx.req.body.a); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
92
1611
86
869379
+ Addedloadware@2.0.0(transitive)
- Removedloadware@1.0.0(transitive)
Updatedloadware@^2.0.0