Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

nodecaf

Package Overview
Dependencies
Maintainers
1
Versions
80
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nodecaf - npm Package Compare versions

Comparing version 0.10.0-rc4 to 0.10.0-rc5

45

lib/logger.js

@@ -29,3 +29,6 @@ const util = require('util');

function parseErr(err){
function parseErr({ err }){
if(!err)
return {};
if(!(err instanceof Error))

@@ -46,3 +49,5 @@ err = new Error(err);

function parseReq(req){
function parseReq({ req }){
if(!req)
return {};
return {

@@ -59,5 +64,6 @@ req: null,

function parseRes(res){
function parseRes({ res }){
if(!res)
return {};
let req = res.req;
return {

@@ -71,20 +77,16 @@ res: null,

msg: 'Sent ' + res.statusCode + ' response to ' + req.method + ' ' + req.url
}
};
}
function parseWs(ws){
function parseWs({ ws }){
if(!ws)
return {};
let client = ws._socket ? ws._socket.address().address : ws.addr;
return {
ws: null,
type: 'websocket',
client
}
return { ws: null, type: 'websocket', client };
}
function getEntry(level, ...args){
let time = new Date();
let data = typeof args[0] == 'object' ? args.shift() : {};
let msg = util.format(...args);
let type = data.type || 'event';
// TODO HOST NAME?

@@ -94,19 +96,10 @@ /* istanbul ignore next */

if(data.err)
Object.assign(data, parseErr(data.err));
if(data.res)
Object.assign(data, parseRes(data.res));
if(data.ws)
Object.assign(data, parseWs(data.ws));
if(data.req)
Object.assign(data, parseReq(data.req));
Object.assign(data, parseErr(data), parseRes(data), parseWs(data),
parseReq(data));
msg = msg || data.msg;
return { level, type, ...data, msg, pid, time };
return { level, type, ...data, msg, pid, time: new Date() };
}
function log(level, ...args){
// TODO parse app
let entry = getEntry(level, ...args);

@@ -113,0 +106,0 @@ entry.app = this._app._name;

@@ -5,8 +5,8 @@ const

http = require('http'),
https = require('https'),
assert = require('assert'),
https = require('https'),
Confort = require('confort'),
{ METHODS } = require('http'),
compression = require('compression'),
cookieParser = require('cookie-parser'),
Confort = require('confort'),
{ METHODS } = require('http');
cookieParser = require('cookie-parser');

@@ -17,2 +17,8 @@ const Logger = require('./logger');

const SHORT_TYPES = {
form: 'multipart/form-data',
urlencoded: 'application/x-www-form-urlencoded',
json: 'application/json'
};
const noop = function(){};

@@ -31,22 +37,40 @@ noop.noop = true;

module.exports = class Nodecaf {
function validateOpts(opts){
assert(typeof opts == 'object',
new TypeError('Options argument must be an object'));
constructor(opts = {}){
this._api = opts.api || noop;
this._startup = opts.startup || noop;
this._shutdown = opts.shutdown || noop;
assert(typeof opts == 'object',
new TypeError('Options argument must be an object'));
assert(typeof this._api == 'function',
new TypeError('API builder must be a function'));
this._api = opts.api || noop;
this._startup = opts.startup || noop;
this._shutdown = opts.shutdown || noop;
assert(typeof this._startup == 'function',
new TypeError('Startup handler must be a function'));
assert(typeof this._api == 'function',
new TypeError('API builder must be a function'));
assert(typeof this._shutdown == 'function',
new TypeError('Shutdown handler must be a function'));
}
assert(typeof this._startup == 'function',
new TypeError('Startup handler must be a function'));
function getRouterProxy(router){
assert(typeof this._shutdown == 'function',
new TypeError('Shutdown handler must be a function'));
// Generate HTTP verb shortcut route methods
let proxy = METHODS.reduce( (o, m) =>
({ ...o, [m.toLowerCase()]: router.addRoute.bind(router, m.toLowerCase()) }), {});
// Needed because it's not possible to call a function called 'delete'
proxy.del = router.addRoute.bind(router, 'delete');
proxy.all = (...chain) =>
METHODS.forEach(m => router.addRoute(m.toLowerCase(), '/:path*', ...chain));
return proxy;
}
module.exports = class Nodecaf {
constructor(opts = {}){
validateOpts.apply(this, [ opts ]);
// TODO sha1 of host+time+name to identify app

@@ -62,10 +86,4 @@

this._alwaysRebuildAPI = opts.alwaysRebuildAPI || false;
// Generate HTTP verb shortcut route methods
this._routeProxy = METHODS.reduce( (o, m) =>
({ ...o, [m.toLowerCase()]: this._router.addRoute.bind(this._router, m.toLowerCase()) }), {});
// Needed because it's not possible to call a function called 'delete'
this._routeProxy.del = this._router.addRoute.bind(this._router, 'delete');
this._serverOpts = opts.server || {};
this._routeProxy = getRouterProxy(this._router);
this._routeProxy.ws = this._wsRouter.set.bind(this._wsRouter);

@@ -102,2 +120,11 @@

accept(types){
types = [].concat(types).map(t => SHORT_TYPES[t] || t);
return ({ body, req, res, next }) => {
if(typeof body !== 'undefined' && !types.includes(req.contentType))
return res.status(415).end();
next();
}
}
async start(){

@@ -127,4 +154,4 @@ if(this.running)

this._server = this._ssl
? https.createServer(this._ssl, handler)
: http.createServer(handler);
? https.createServer({ ...this._serverOpts, ...this._ssl }, handler)
: http.createServer(this._serverOpts, handler);

@@ -174,33 +201,1 @@ this._wsRouter.start();

}
/* CHANGES SO FAR
- log class -> type
- Log name -> app
- Removed Express
- Nice Exceptions
- Logger Auto-parse err, app, res, req (TODO)
- UpTime entrypoint (TODO)
- Health entrypoint (TODO)
- Removed 'port' attr
- Change main class to 'Nodecaf'
- 4xx errors won't spit default body anymore
- expose() to app.global
- PID 1 omitted from log entries
- Added res.type()
- Added res.text()
- Entire assertions usage
- error() -> res.error()
- res log entry now has method
- form-data file interface
- removed accept() and filters (TMP)
- removed user error handler (TMP)
- app.api() to new App(api, ...)
- startup and shutdown
- moved cookieSecret to conf
- constructor argument to OPTS spec
- remove programmatic name and version
- Added WS cookies
- option to disable log completely
- log entry for error on parsing body
*/

@@ -9,15 +9,22 @@ const querystring = require('querystring');

function parseContentType(req){
try{
var ct = contentType.parse(req.headers['content-type']);
}
catch(err){
ct = FALLBACK_CONTENT_TYPE;
}
ct.textCharset = ct.parameters.charset || 'utf-8';
ct.originalCharset = ct.parameters.charset;
req.contentType = ct.type;
return ct;
}
module.exports = {
async parseBody(req){
try{
var ct = contentType.parse(req.headers['content-type']);
}
catch(err){
ct = FALLBACK_CONTENT_TYPE;
}
let ct = parseContentType(req);
let textCharset = ct.parameters.charset || 'utf-8';
let originalCharset = ct.parameters.charset;
try{

@@ -33,9 +40,9 @@

if(ct.type.slice(-4) == 'json')
return JSON.parse(req.rawBody.toString(textCharset));
return JSON.parse(req.rawBody.toString(ct.textCharset));
if(ct.type == 'application/x-www-form-urlencoded')
return querystring.parse(req.rawBody.toString(textCharset));
return querystring.parse(req.rawBody.toString(ct.textCharset));
if(originalCharset || ct.type.slice(4) == 'text')
return req.rawBody.toString(textCharset);
if(ct.originalCharset || ct.type.slice(4) == 'text')
return req.rawBody.toString(ct.textCharset);

@@ -42,0 +49,0 @@ return req.rawBody;

@@ -0,1 +1,2 @@

const assert = require('assert');
const querystring = require('querystring');

@@ -11,2 +12,39 @@ const { pathToRegexp } = require('path-to-regexp');

function findDynamicRouteMatch(req, pool = []){
for(let route of pool){
let match = route.regexp.exec(req.path);
if(match){
route.params.forEach( (p, i) => req.params[p.name] = match[i + 1]);
return route.handler;
}
}
}
const normalizePath = p => (p.slice(-1) == '/' ? p.slice(0, -1) : p) || '/';
function buildStack(chain){
let nextHandler = null;
return chain.reverse().map(h => {
assert(typeof h == 'function',
new TypeError('Invalid route option \'' + typeof h + '\''));
h = normalizeHandler(h.bind(this.app));
h.next = nextHandler;
return nextHandler = h;
}).reverse();
}
function routeRequest(router, req){
let url = new URL(req.url, 'http://0.0.0.0');
req.path = normalizePath(url.pathname);
router.app.log.debug({ req });
req.params = {};
req.flash = {};
req.query = querystring.parse(url.search.slice(1));
let route = req.method + ' ' + req.path;
return router.static[route] ||
findDynamicRouteMatch(req, router.dynamic[req.method]);
}
module.exports = class Router {

@@ -25,39 +63,27 @@

addRoute(method, path, ...opts){
addRoute(method, path, ...chain){
let stack = [];
let m = method.toUpperCase();
let route = m + ' ' + path;
if(!this.app._alwaysRebuildAPI && route in this.routes)
throw new Error('Route for \'' + route + '\' is already defined');
let dup = !this.app._alwaysRebuildAPI && route in this.routes;
assert(!dup, new Error('Route for \'' + route + '\' is already defined'));
for(let o of opts)
if(typeof o == 'function'){
let h = normalizeHandler(o.bind(this.app));
stack.length > 0 && (stack[stack.length - 1].next = h);
stack.push(h);
}
else
throw new TypeError('Invalid route option \'' + typeof o + '\'');
assert(chain.length > 0, new Error('Route is empty at \'' + path + '\''));
let stack = buildStack.apply(this, [ chain ]);
if(stack.length == 0)
throw new Error('Route is empty at \'' + path + '\'');
stack.slice(-1)[0].tail = true;
if(path.indexOf(':') >= 0){
let params = [];
this.routes[route] = true;
this.dynamic[m] = this.dynamic[m] || [];
this.dynamic[m].push({
regexp: pathToRegexp(path, params, PRG_OPTS),
handler: stack[0],
params
});
}
else
this.static[route] = stack[0];
if(!/[:?+*]/.test(path))
return this.static[route] = stack[0];
this.routes[route] = true;
let params = [];
this.dynamic[m] = this.dynamic[m] || [];
this.dynamic[m].push({
regexp: pathToRegexp(path, params, PRG_OPTS),
handler: stack[0],
params
});
}

@@ -67,37 +93,12 @@

try{
let url = new URL(req.url, 'http://0.0.0.0');
let reqPath = (url.pathname.slice(-1) == '/'
? url.pathname.slice(0, -1) : url.pathname) || '/';
res.req = req;
//this.app.log.debug({ req });
res.on('finish', () => this.app.log.debug({ res }));
let route = req.method + ' ' + reqPath;
Object.assign(res, resMethods);
req.params = {};
req.flash = {};
req.query = querystring.parse(url.search.slice(1));
let handler = routeRequest(this, req);
let handler = false;
if(req.method == 'OPTIONS')
return handleCORS(this.app, req, res);
if(route in this.static)
handler = this.static[route];
else if(req.method in this.dynamic)
for(let route of this.dynamic[req.method]){
let match = route.regexp.exec(reqPath);
if(match){
route.params.forEach( (p, i) => req.params[p.name] = match[i + 1]);
handler = route.handler;
break;
}
}
if(!handler)

@@ -104,0 +105,0 @@ return res.status(404).end();

{
"name": "nodecaf",
"version": "0.10.0-rc4",
"version": "0.10.0-rc5",
"description": "Nodecaf is a framework on top of Express for building RESTful services in a quick and convenient manner.",

@@ -41,3 +41,3 @@ "main": "lib/main.js",

"cookie": "^0.4.1",
"cookie-parser": "^1.4.4",
"cookie-parser": "^1.4.5",
"cookie-signature": "^1.1.0",

@@ -48,3 +48,3 @@ "cors": "^2.8.5",

"stdout-stream": "^1.4.1",
"ws": "^7.2.1"
"ws": "^7.3.1"
},

@@ -51,0 +51,0 @@ "devDependencies": {

@@ -5,5 +5,5 @@ # [Nodecaf](https://gitlab.com/GCSBOSS/nodecaf)

Nodecaf is an Express framework for developing REST APIs in a quick and
convenient manner.
Nodecaf is a light framework for developing RESTful Apps in a quick and convenient manner.
Using Nodecaf you'll get:
- Familiar middleware style routes declaration
- Useful [handler arguments](#handlers-args).

@@ -15,3 +15,3 @@ - Built-in [settings file support](#settings-file) with layering.

responses.
- Built-in [assertions for most common REST scenarios](#rest-assertions).
- Built-in [assertions for readable RESTful error handling](#rest-assertions).
- Function to [expose global objects](#expose-globals) to all routes (eg.:

@@ -27,6 +27,2 @@ database connections).

> If you are unfamiliar with Express, checkout
> [their routing docs](https://expressjs.com/en/starter/basic-routing.html)
> so that you can better grasp Nodecaf features and whatnot.
## Get Started

@@ -41,33 +37,21 @@

```js
const { AppServer } = require('nodecaf');
const Nodecaf = require('nodecaf');
const api = require('./api');
module.exports = function init(){
let app = new AppServer();
module.exports = () => new Nodecaf({
// Expose things to all routes putting them in the 'shared' object.
let shared = {};
app.expose(shared);
// Load your routes and API definitions.
api,
// You can intercept all error that escape the route handlers.
app.onRuoteError = function(input, err, send){
// Any error that is not handled here will just become a harmless 500.
};
// Perform your server initialization logic.
app.beforeStart = async function(){
async startup({ conf, log, global }){
};
},
// Perform your server finalization logic.
app.afterStop = async function(){
async shutdown({ conf, log, global }){
};
}
// Load your routes and API definitions.
app.api(api);
// Don't forget to return your app.
return app;
}
});
```

@@ -78,8 +62,11 @@

```js
module.exports = function({ post, get, del, head, patch, put }){
module.exports = function({ post, get, del, head, patch, put, all }){
// Use express routes and a list of functions (async or regular no matter).
// Define routes and a list of middleware functions (async or regular no matter).
get('/foo/:f/bar/:b', Foo.read, Bar.read);
post('/foo/:f/bar', Foo.read, Bar.write);
// ...
// ALL middleware will run on any method and any path
all(Foo.read, Bar.write);
};

@@ -117,4 +104,4 @@ ```

## Manual
On top of all the cool features Express offers, check out how to use all
the awesome goodies Nodecaf introduces.
Formerly based on Express, Nodecaf preserves the same interface for defining routes
through middleware chains. Check out how to use all the awesome goodies Nodecaf introduces.

@@ -128,3 +115,3 @@ ### Handler Args

```js
function({ req, res, next, query, params, body, flash, conf, log, error, headers }){
function({ req, res, next, query, params, body, flash, conf, log, headers }){
// Do your stuff.

@@ -136,9 +123,9 @@ }

- `req`, `res`, `next`: The good old parameters used regularly in Express.
- `req`, `res`, `next`: The good old parameters used regularly in middleware-like frameworks.
- `query`, `parameters`, `body`, `headers`: Shortcuts to the homonymous properties of `req`.
They contain respectively the query string, the URL parameters, and the request
body data.
- `flash`: Is a shortcut to Express `req.locals`. Keys inserted in this a object
are preserved for the lifetime of a request and can be accessed in all handlers
of a route chain.
- `flash`: Is an object where you can store arbitrary values. Keys inserted in this
object are preserved for the lifetime of a request and can be accessed in all
handlers of a route chain.
- `conf`: This object contains the entire

@@ -150,4 +137,2 @@ [application configuration data](#settings-file).

as handler args for all routes.
- `error`: A function to [output REST errors](#error-handling) and abort the
handler chain execution.

@@ -164,3 +149,3 @@ ### Settings File

Suported config formats: **TOML**, **YAML**, **JSON**
Suported config formats: **TOML**, **YAML**, **JSON**, **CSON**

@@ -184,6 +169,3 @@ > Check out how to [generate a project with configuration file already plugged in](#init-project)

```js
module.exports = function init(){
let conf = { key: 'value' };
let app = new AppServer(conf);
}
module.exports = () => new Nodecaf({ conf: { key: 'value' } });
```

@@ -194,5 +176,3 @@

```js
module.exports = function init(){
let app = new AppServer(__dirname + '/default.toml');
}
module.exports = () => new Nodecaf({ conf: __dirname + '/default.toml' });
```

@@ -227,3 +207,3 @@

log.info('hi');
log.warn({lang: 'fr'}, 'au revoir');
log.warn({ lang: 'fr' }, 'au revoir');
log.fatal({ err: new Error() }, 'The error code is %d', 1234);

@@ -243,3 +223,3 @@ }

| Class | Level | Event |
| Type | Level | Event |
|-------|-------|-------|

@@ -260,3 +240,3 @@ | error after headers sent | warn | An error happened inside a route after the headers were already sent |

Additionally, you can filter log entries by level and class with the following
Additionally, you can filter log entries by level and type with the following
settings:

@@ -267,5 +247,10 @@

level = 'warn' # Only produce log entries with level 'warn' or higher ('error' & 'fatal')
class = 'my-class' # Only produce log entries with class matching exactly 'my-class'
type = 'my-type' # Only produce log entries with type matching exactly 'my-type'
```
You can disable logging entirely for a given app by setting it to `false` in the config
```toml
log = false
```
### Async Handlers

@@ -302,3 +287,4 @@

To support the callback error pattern, use the `error` handler arg.
To support the callback error pattern, use the `res.error()` function arg. This
function will stop the middleware chain from being executed any further.

@@ -308,6 +294,6 @@ ```js

post('/my/thing', function({ error, res }){
post('/my/thing', function({ res }){
fs.readFile('./my/file', 'utf8', function(err, contents){
if(err)
return error(err, 'Optional message to replace the original');
return res.error(err);
res.end(contents);

@@ -318,14 +304,5 @@ });

To use other HTTP status codes you can send a string in the first parameter of
`error`. The supported error names are the following:
To use other HTTP status codes you can send an integer in the first parameter of
`res.error()`.
| Error name | Status Code |
|------------|-------------|
| `NotFound` | **404** |
| `Unauthorized` | **401** |
| `ServerFault` | **500** |
| `InvalidActionForState` | **405** |
| `InvalidCredentials` | **400** |
| `InvalidContent` | **400** |
```js

@@ -337,3 +314,3 @@ post('/my/thing', function({ error }){

catch(e){
error('NotFound', 'Optional message for the JSON response');
error(404, 'Optional message for the response');
}

@@ -343,21 +320,2 @@ });

You can always deal with uncaught exceptions in all routes through a default
global error handler. In your `lib/main.js` add an `onRuoteError` function
property to the `app`.
```js
app.onRuoteError = function(input, err, send){
if(err instanceof MyDBError)
send('ServerFalut', 'Sorry! Database is sleeping.');
else if(err instanceof ValidationError)
send('InvalidContent', err.data);
}
```
- The `send` function will instruct Nodecaf to output the given error.
- The `input` arg contain all handler args for the request.
- If you do nothing for a specific type of `Error` the normal 500 behavior will
take place.
### REST Assertions

@@ -370,7 +328,5 @@

```js
let { exist } = require('nodecaf').assertions;
get('/my/thing/:id', function({ params, db }){
get('/my/thing/:id', function({ params, db, res }){
let thing = await db.getById(params.id);
exist(thing, 'thing not found');
res.notFound(!thing, 'thing not found');

@@ -381,29 +337,16 @@ doStuff();

If the record is not found, the `exist` call will stop the route execution right
If the record is not found, the `res.notfound()` call will stop the route execution right
away and generate a [RESTful `NotFound` error](#error-handling).
Along with `exist`, the following assertions with similar behavior are provided:
Along with `notFound`, the following assertions with similar behavior are provided:
| Method | Error to be output |
|--------|--------------------|
| `exist` | `NotFound` |
| `valid` | `InvalidContent` |
| `authorized` | `Unauthorized` |
| `authn` | `InvalidCredentials` |
| `able` | `InvalidActionForState` |
| Method | Status Code |
|--------|-------------|
| `badRequest` | 400 |
| `unauthorized` | 401 |
| `forbidden` | 403 |
| `notFound` | 404 |
| `conflict` | 409 |
| `gone` | 410 |
To use it with callback style functions, pass the `error` handler arg as the
third parameter.
```js
let { exist } = require('nodecaf').assertions;
post('/my/file/:id', function({ error, res, params }){
fs.readFile('./my/file/' + params.id, 'utf8', function(err, contents){
exist(!err, 'File not found', error);
res.end(contents);
});
});
```
### Expose Globals

@@ -416,5 +359,7 @@

```js
app.expose({
db: myDbConnection,
libX: new LibXInstance()
module.exports = () => new Nodecaf({
startup({ global }){
global.db = myDbConnection;
global.libX = new LibXInstance();
}
});

@@ -580,9 +525,8 @@ ```

|----------|------|-------------|---------|
| `app.name` | String | Name to be displayed in logs and documentation | `'Untitled'` |
| `app.version` | String | Verison to be displayed in logs and documentation | Version in Package JSON |
| `app.conf.delay` | Integer | Milliseconds to wait before actually starting the app | `0` |
| `app.conf.port` | Integer | Port for the web server to listen (also exposed as user conf) | `80` or `443` |
| `app.shouldParseBody` | Boolean | Wether supported request body types should be parsed | `true` |
| `app.conf.formFileDir` | Path | Where to store files uploaded as form-data | OS default temp dir |
| `app.alwaysRebuildAPI` | Boolean | Wether the API should be rebuilt dynamically for every start or setup operation | `false` |
| `app.cookieSecret` | String | A secure random string to be used for signing cookies | none |
| `app.conf.cookie.secret` | String | A secure random string to be used for signing cookies | none |
| `opts.shouldParseBody` | Boolean | Wether supported request body types should be parsed | `true` |
| `opts.server` | Object | An options object to be passed directly to the http(s) [`createServer()`](https://nodejs.org/api/http.html#http_http_createserver_options_requestlistener) | `{}` |
| `opts.alwaysRebuildAPI` | Boolean | Wether the API should be rebuilt dynamically for every start or setup operation | `false` |

@@ -240,2 +240,17 @@ const assert = require('assert');

it('Should execute \'all\' handler on any path/method', async () => {
let app = new Nodecaf({
api({ all }){
all(({ res, params }) => {
res.badRequest(!params.path);
res.end();
});
}
});
await app.start();
(await base.get('foo/bar')).assert.status.is(200);
(await base.post('bah/baz')).assert.status.is(200);
await app.stop();
});
it('Should pass all present parameters to handler', async () => {

@@ -623,57 +638,2 @@ let app = new Nodecaf({

it.skip('Should execute intermediary error handler', async () => {
let app = new Nodecaf();
let count = 0;
app.onRouteError = function(input, err){
assert.strictEqual(err.message, 'resterr');
count++;
};
app.api(function({ post }){
post('/known', () => {
throw new Error('resterr');
});
post('/unknown', ({ error }) => {
error('NotFound', 'resterr');
});
});
await app.start();
let { status } = await base.post('known');
assert.strictEqual(status, 500);
let { status: s2 } = await base.post('unknown');
assert.strictEqual(s2, 404);
assert.strictEqual(count, 2);
await app.stop();
});
it.skip('Should allow tapping into the thrown error', async () => {
let app = new Nodecaf();
app.onRouteError = function(input, err, error){
error('Unauthorized', 'resterr');
};
app.api(function({ post }){
post('/unknown', () => {
throw new Error('resterr');
});
});
await app.start();
let { status } = await base.post('unknown');
assert.strictEqual(status, 401);
await app.stop();
});
it.skip('Should expose handler args object to user error handler', async () => {
let app = new Nodecaf();
app.onRouteError = function(input){
assert.strictEqual(typeof input.req, 'object');
};
app.api(function({ post }){
post('/unknown', () => {
throw new Error('resterr');
});
});
await app.start();
await base.post('unknown');
await app.stop();
});
});

@@ -735,21 +695,2 @@

it.skip('Should execute user error handler even if headers were already sent', async () => {
let app = new Nodecaf();
app.api(function({ post }){
post('/bar', ({ res }) => {
res.end();
throw new Error();
});
});
let gotHere = false;
app.onRouteError = function(){
gotHere = true;
};
await app.start();
app.express.set('env', 'test');
await base.post('bar');
await app.stop();
assert(gotHere);
});
it('Should not hang up connections when they have a query string', function(done){

@@ -945,4 +886,55 @@ let count = 0;

await app.stop();
})
});
it('Should reject unwanted content-types for the given route', async () => {
let app = new Nodecaf({
api({ post }){
let acc = this.accept([ 'urlencoded', 'text/html' ]);
post('/foo', acc, ({ res }) => res.end());
}
});
await app.start();
let { assert } = await base.post(
'foo',
{ 'Content-Type': 'application/json' },
'{"foo":"bar"}'
);
assert.status.is(415);
await app.stop();
});
it('Should accept wanted content-types for the given route', async () => {
let app = new Nodecaf({
api({ post }){
let acc = this.accept('text/html');
post('/foo', acc, ({ res }) => res.end());
}
});
await app.start();
let { status } = await base.post(
'foo',
{ 'Content-Type': 'text/html' },
'{"foo":"bar"}'
);
assert.strictEqual(status, 200);
await app.stop();
});
it('Should accept requests without a body payload', async () => {
let app = new Nodecaf({
api({ post }){
let acc = this.accept('text/html');
post('/foo', acc, ({ res }) => res.end());
}
});
await app.start();
let { status } = await base.post(
'foo',
{ 'no-auto': true },
'{"foo":"bar"}'
);
assert.strictEqual(status, 200);
await app.stop();
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc