This is a repository for public discussions. Any help or questions will have their issues transferred here. Join the discussion.
Want to contribute? Find issues with help-wanted
For more discussions, join the Slack group:
KoaJS Discussions
This is a repository for public discussions. Any help or questions will have their issues transferred here. Join the discussion.
Want to contribute? Find issues with help-wanted
For more discussions, join the Slack group:
With GitHub's new organization administration, I want to try moving all koa middleware/plugins to the org. The goals are:
I'm not sure how this will work. I remember last time, you had to be an owner of the organization for you to transfer a repository to an organization.
The steps will be something like:
If anything, just transfer the repository to me and I'll add it to the organization. Comment here so I remember to add it to the organization! Let me know if anyone wants to transfer any repositories.
First one i'd like to transfer is koa-convert :)
NOTE: IF YOU'RE IN THIS ORGANIZATION, PLEASE SETUP 2-FACTOR AUTHENTICATION!
When using a Koa app as an express middleware, with a path prefix, the ctx.originalUrl
will not be valid and will not contain the path prefix:
const expressApp = express()
const koaApp = new Koa()
const koaRouter = new Router()
koaRouter.get('/test', async (ctx, next) => {
console.log(ctx.originalUrl) // will not contain "/api"
ctx.body = { foo: "bar" }
})
koaApp.use(koaRouter.routes())
expressApp.use('/api', koaApp.callback())
This is due to the fact that, behind the scene, the express router will manipulate req.url
when the request is being processed by router middleware.
I would suggest that Koa does something similar to what express does when it is itself used as a middleware, meaning preserve the original originalUrl
:
https://github.com/expressjs/express/blob/f3fa758af9664526ee18c58764590e48f559e6ae/lib/router/index.js#L172
My suggestion is to change the following line of lib/application.js
:
context.originalUrl = request.originalUrl = req.url;
// to
context.originalUrl = request.originalUrl = req.originalUrl || req.url;
Now one can argue that this would be a breaking change, especially because any route defined in koa will need to reflect the prefix again. In my example above, the routes in the router would have to be defined as koaRouter.get("/api/test", ...)
. That is true, but we also need to consider that the current implementation already breaks the request URL
related getters.
use history-fallback-api ?
I want to play music that received from my server.
it works properly without error when I test it in the local, but EPIPE errors occur when I test it in the server.
const mp3 = fs.createReadStream(`../music-uploader/${low_mp3}`);
ctx.response.set("content-type", "audio/mp3");
ctx.response.set("Accept-Ranges", 'bytes');
ctx.body = mp3;
It is my code and I don't know how to fix it.
Error: write EPIPE
at _errnoException (util.js:1022:11)
at WriteWrap.afterWrite (net.js:867:14)
why it happens???
I wanted to inherit Koa in TypeScript to add a few properties and methods to Context
because adding by using prototype
does not support the auto-complete for the editor. But an error occurred when calling super
.
Here's my code:
import * as Koa from "koa";
class App extends Koa {
constructor() {
super();
this.use(compose([error]));
}
}
const app = new App();
Here's the error:
TypeError: Class constructor Application cannot be invoked without 'new'
I tried just import Application
from Koa, but the same error occurred.
The request url parameter + is turned into a space.
for example http://localhost:8080?key=a+c
the server received key is a c
;
This is since the middle of last year - transferring large files on slow connections, I get an error:
Error: You cannot pipe after data has been emitted from the response.
Any chance this gets replaced? always need to monkey patch. Quite annoying.
Error: You cannot pipe after data has been emitted from the response.
at Request.pipe (C:\blog\app-ui\node_modules\request\request.js:1478:26)
at respond (C:\blog\node_modules\koa\lib\application.js:240:43)
at handleResponse (C:\blog\node_modules\koa\lib\application.js:149:34)
Solution:
Do not use Koa ctx.body = stream
. Return the stream directly.
Code here: koajs/koa#944 (comment)
I just wanted to let everybody know that I've switched Github account from fl0w to miwnwski. This was due to me "loosing" the 2FA phone number (long story) the account is connected to and me not saving recovery codes (that's on me).
I still have access to it via an obscure iPhone app (using an API Key) that only allows me to comment on tickets.
If anyone have any questions regarding security or the validity of this account just ask them here.
Dear Koa devs,
Super happy with Koa. We've been using it for over a year.
I'm facing an issue where I want to do an 'internal subrequest'. What this means is that a real HTTP request comes in, and I want to write a middleware that creates a brand new (fake) HTTP request and return the result.
This middleware will then take the result and do some post-processing before returning it.
Is there a standard way to solve this problem with Koa? I want to avoid doing a 'real' HTTP request on the local server, because it seems like a lot of overhead. I don't really want to invoke the TCP/HTTP stack, although my prototype does use that approach.
Any pointers here are welcome!
Stacktrace:
TypeError: Cannot read property 'hasHeader' of undefined
File "/home/ubuntu/turnout/turnoutapi/node_modules/koa/lib/response.js", line 436, col 28, in Object.has
return typeof this.res.hasHeader === 'function'
File "/home/ubuntu/turnout/turnoutapi/node_modules/koa/lib/response.js", line 204, col 14, in Object.get length [as length]
if (this.has('Content-Length')) {
File "/home/ubuntu/turnout/turnoutapi/node_modules/koa-logger/index.js", line 77, col 33, in logger
const length = ctx.response.length
File "async /home/ubuntu/turnout/turnoutapi/src/error.service.js", line 10, col 9, in null.<anonymous>
File "async /home/ubuntu/turnout/turnoutapi/src/index.js", line 49, col 9, in null.<anonymous>
Version:
"koa": "^2.11.0",
Affects:
Doesn't seem to break anything, but gets logged a bunch in my error logging (Sentry)
console.log(ctx.query)
if (!ctx.query.sort) {
ctx.query.sort = '-createdAt'
}
console.log(ctx.query)
Will yield {}
and {}
but if I pass anything in qs I correctly get {foo:'bar'}
and {foo:'bar', sort: '-createdAt'}
eg: app -> index.html, h5.html
index.html:
if(isMobile){
window.location.href = './h5.html'
}else{
window.location.href = './pc.html'
}
error URL: isMobile(http://localhost/app => http://localhost/h5.html)
right URL: http://localhost/app/ => http://localhost/app/h5.html
Update: on Linux server it happens too.
I'm trying to figure out how to use koa-static (in SPA) properly.
First I just had put it in front of the other middleware, hoping that when it finds a file it would immediately return serving it:
const Koa = require('koa')
, app = new Koa()
, static = require('koa-static')
app.use(static('css'))
app.use(static('img'))
app.use(static('js'))
app.use(my-other-middleware)
...
app.listen(32123)
But my-other-middleware
rewrites the response (e.g. any css file has the same contents - of the main page). So I try to put an alternate route like this:
my-other-middleware = async (ctx, next) => {
switch (ctx.url.substr(0, 4)) {
case '/css':
case '/js/':
case '/img':
return
// or return next()
// or next(); return — nothing helps
}
...
}
So, for the "static" directories the response shouldn't get rewritten. But then I get 404 'Not Found' for any file which actually exist — e.g.
http://localhost:32123/css/a.css
http://localhost:32123/js/main.js
...
I don't even know how to debug it. Am I doing something wrong, or maybe it's just some incompatibility in my software stack? Bear with a noob question please.
Thank you.
this is not really issue of this module but for completeness
const http = require('uws').http
const Koa = require('koa')
const conditional = require('koa-conditional-get')
const app = new Koa()
app.use(conditional())
app.use(ctx => {
ctx.body = 'Hello World!'
})
http.createServer(app.callback()).listen(8000)
using this module with uws http server results in:
Warning: req.headers usage past request handler is not supported!
this is because this.get (or this.headers in fresh
module) being called in upstream triggers it
one would have to "solve" this like
const fresh = ctx.fresh
return next().then(() => {
if (fresh) {
ctx.status = 304;
ctx.body = null;
}
});
which I don't think is really a solution since one has to allocate memory before it is sure it will get used
I suspect there is bunch of other libraries that will have the same "issue"
reported that over to uws
https://github.com/uWebSockets/uWebSockets/issues/590
Hi, i want to run a resultful api in Postman,
but i get an error Invalid CSRF token
.
How can i exclude my api router from csrf ?
i try to use:
headers: {
X-CSRF-Token: [csrf-value],
_csrf: [csrf-value]
}
or
/api/add?csrf=gnwLgVst-Hf-liZtMY3BQwEik9x-Sn4k1-58
but it dosn't work
I made a micro web app so I can record my voice anywhere I want. At first I thought it was working perfectly but only to realize the long recordings were trimmed at the end. So I opened up my project again and tried to understand what was going on.
I noticed the trimmed recordings had a maximum size of 128K. But the POST data (which is sent in plain format btw) was transmitted by full length. After few experimentation I determined the problem was the piping :
const fileStream = fs.createWriteStream('path/to/file.wav');
ctx.req.pipe(fileStream);
If I change to
const fileData = '';
ctx.req.on('data', function (data) {
fileData += data;
});
ctx.req.on('end', function () {
fs.writeFileSync('path/to/file.wav', fileData);
});
It works. But I'd like to understand why the former doesn't wait all the data to be piped in. What do you think ?
Also because I don't like how the latter save all this raw data in the form of a string in a variable before filling up the file container.
Thanks in advance.
I notice there is not a page describing who is using the framework? Any idea of some "big companies" using it? Thanks
I was just checking out my nodejs service with Brotli compression enabled with default config and Brotli enabled.
Download size decreased from 77kb to 47kb with Brotli, but total request time raised from 209ms (waiting: 200ms + download: 9ms) to 1306ms (waiting 1300ms + download: 6ms) in Chrome DevTools.
I read that latency might increase, but not at such a high level.
Tested with Chrome Dev85, NodeJS 12.18.1 + Koa 2.13 + Koa-Compress 4.0.1.
I am working with JSON data.
I've noticed that when I use this library, the "Content Download" time in Chrome dev tools is increased by 200+ ms. I see the same thing in Firefox for the "Receiving" time. I've created a small test script to isolate this issue from anything else:
const Koa = require('koa');
const app = new Koa();
app.keys = ['key1'];
app.use(require('koa-compress')({
flush: require('zlib').Z_SYNC_FLUSH
}));
let data = [];
for(let i = 0; i < 50000; i++) {
data.push('hello');
}
app.use(async (ctx, next) => {
ctx.body = data;
});
app.listen(3000);
console.log('Listening on port 3000.');
This is using Koa v2, koa-compress v2.0, Node v7.2.1 along with the harmony flag.
With compression on, the page loads between 200-230 ms. Transferred amount is 637B.
With compression off, the page loads between 8-30 ms. Transferred amount is 390.63KB.
It looks like compression is working fine, but why is it adding 200 ms?
I'm running these tests inside a local Ubuntu vagrant environment.
The problem is that query serialized back to string in setter, so I cannot write middleware that will convert some parameters to number, and I have to do it only in handler, which is inconvenient :(
cast @dead-horse
I need to be able to modify it, for coercion of validated data.
The docs currently state that Koa supports "common" functions as well as the new async/await. While this works with happy path code, it falls apart with error handling. Here's an example where my error doesn't get caught:
const Koa = require('koa');
const app = new Koa();
app.use(({response}, next) => {
try {
return next();
} catch (ex) {
console.log('Gotcha', ex.stack);
response.body = ex.stack;
}
});
app.use((ctx, next) => {
console.log('About to throw');
throw new Error('Catch me if you can.');
});
Updating the error handler middleware to be async/await fixes the issue:
const Koa = require('koa');
const app = new Koa();
app.use(async ({response}, next) => {
try {
return await next();
} catch (ex) {
console.log('Gotcha', ex.stack);
response.body = ex.stack;
}
});
app.use((ctx, next) => {
console.log('About to throw');
throw new Error('Catch me if you can.');
});
This makes sense, but might throw newcomers (see what I did there). If there is no easy solution to this problem, then might I suggest that you advise all middleware to be async? The koa-composer is wrapping all middleware with a Promise already (which is likely the reason why the "sync" error is not caught). Just a personal opinion, but I think it might simplify all things if you advise all middleware to be async/await (easier for newcomers, fewer issues, easier docs, etc).
EDIT: if middleware does not use async/await, then it should return a promise. Failure to do so breaks an app. I think koa could easily warn users if the middleware fails to do one of the above.
Our prod deployment of a koa server is exiting several times a day with little info logged. There is logging on a number of node process events including beforeExit, exit, close, uncaughtExceptionMonitor and unhandledRejection but only exit is triggered. None of our code calls exit() explicitly and looking through npm packages we use it doesn't look like any of them would be calling it either.
The exit happens during a request to a specific API PUT endpoint where the body payload is relatively large compared to other calls, but not huge (around 15-30KB). It's not happening consistently on every request, as a server restart and re-attempt with the same data can work in most cases.
Based on log timestamps the exit happens immediately when the request is made. Any exception around these calls would be handled and logged but it looks like no exception is thrown. This issue has happened when our codebase used the co-request library to manage http requests as well as after migrating to axios.
My understanding is that node will exit when there are no pending async operations, which could indicate koa is stopping for some reason?
This is my app.js
file:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var usersRouter = require('./routes/usersRouter');
var imagesRouter = require('./routes/imagesRouter');
const uploadRouter = require('./routes/uploadRouter');
const Images = require('./models/images');
//const uploadRouter = require('./routes/uploadRouter');
//const favoriteRouter = require('./routes/favoriteRouter')
var config = require('./config');
const mongoose = require('mongoose');
//mongoose.set('useCreateIndex', true);
mongoose.Promise = require('bluebird');
var passport = require('passport');
var authenticate = require('./authenticate');
// Connection URL
const url = config.mongoUrl;
const connect = mongoose.connect(url, {
//useMongoClient: true,
/* other options */
useNewUrlParser: true ,
useUnifiedTopology: true
});
connect.then((db) => {
console.log("Connected correctly to server");
}, (err) => { console.log(err); });
var app = express();
// Secure traffic only
app.all('*', (req, res, next) => {
if (req.secure) {
return next();
}
else {
res.redirect(307, 'https://' + req.hostname + ':' + app.get('secPort') + req.url);
}
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
app.use('/', index);
app.use('/users', usersRouter);
app.use(express.static(path.join(__dirname, 'public')));
app.use('/images',imagesRouter);
app.use('/imageUpload',uploadRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
And this is my `cors.js` file:
const express = require('express');
const cors = require('cors');
const app = express();
const whitelist = ['http://localhost:3000', 'https://localhost:3443', 'http://localhost:4200'];
var corsOptionsDelegate = (req, callback) => {
var corsOptions;
console.log(req.header('Origin'));
if(whitelist.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true };
}
else {
corsOptions = { origin: false };
}
callback(null, corsOptions);
};
exports.cors = cors();
exports.corsWithOptions = cors(corsOptionsDelegate);
And also my imageRouter.js
:
const express = require('express');
const bodyParser = require('body-parser');
const Images = require('../models/images');
var authenticate = require('../authenticate');
const imagesRouter = express.Router();
const cors = require('./cors');
imagesRouter.use(bodyParser.json());
/*
imagesRouter.options('*', cors.cors, (req, res) => {
res.sendStatus(200);
//res.header('Access-Control-Allow-Origin', "*");
//res.header('Access-Control-Allow-Methods', 'POST');
//res.header("Access-Control-Allow-Headers", "accept, content-type");
//res.header("Access-Control-Max-Age", "1728000");
} );
*/
imagesRouter.route('/')
.options(cors.corsWithOptions, (req, res) => { res.sendStatus(200); })
.get(cors.cors, (req,res,next) => {
Images.find({})
.then((images) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(images);
}, (err) => next(err))
.catch((err) => next(err));
})
module.exports = imagesRouter;
But I get:
Access to XMLHttpRequest at 'https://localhost:3443/images' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
zone-evergreen.js:2828 GET https://localhost:3443/images net::ERR_FAILED
scheduleTask @ zone-evergreen.js:2828
scheduleTask @ zone-evergreen.js:386
onScheduleTask @ zone-evergreen.js:273
scheduleTask @ zone-evergreen.js:379
scheduleTask @ zone-evergreen.js:211
scheduleMacroTask @ zone-evergreen.js:234
scheduleMacroTaskWithCurrentZone @ zone-evergreen.js:1118
(anonymous) @ zone-evergreen.js:2861
proto.<computed> @ zone-evergreen.js:1433
(anonymous) @ http.js:2615
_trySubscribe @ Observable.js:42
subscribe @ Observable.js:28
call @ tap.js:16
subscribe @ Observable.js:23
subscribeToResult @ subscribeToResult.js:9
_innerSub @ mergeMap.js:59
_tryNext @ mergeMap.js:53
_next @ mergeMap.js:36
next @ Subscriber.js:49
(anonymous) @ subscribeToArray.js:3
_trySubscribe @ Observable.js:42
subscribe @ Observable.js:28
call @ mergeMap.js:21
subscribe @ Observable.js:23
call @ filter.js:13
subscribe @ Observable.js:23
call @ map.js:16
subscribe @ Observable.js:23
call @ catchError.js:16
subscribe @ Observable.js:23
ngOnInit @ header.component.ts:41
callHook @ core.js:3937
callHooks @ core.js:3901
executeInitAndCheckHooks @ core.js:3842
refreshView @ core.js:11795
refreshComponent @ core.js:13217
refreshChildComponents @ core.js:11508
refreshView @ core.js:11829
renderComponentOrTemplate @ core.js:11903
tickRootContext @ core.js:13379
detectChangesInRootView @ core.js:13413
detectChanges @ core.js:15093
tick @ core.js:42683
_loadComponent @ core.js:42733
bootstrap @ core.js:42659
(anonymous) @ core.js:42251
_moduleDoBootstrap @ core.js:42247
(anonymous) @ core.js:42202
invoke @ zone-evergreen.js:365
onInvoke @ core.js:41257
invoke @ zone-evergreen.js:364
run @ zone-evergreen.js:124
(anonymous) @ zone-evergreen.js:851
invokeTask @ zone-evergreen.js:400
onInvokeTask @ core.js:41235
invokeTask @ zone-evergreen.js:399
runTask @ zone-evergreen.js:168
drainMicroTaskQueue @ zone-evergreen.js:570
Promise.then (async)
scheduleMicroTask @ zone-evergreen.js:553
scheduleTask @ zone-evergreen.js:389
scheduleTask @ zone-evergreen.js:211
scheduleMicroTask @ zone-evergreen.js:231
scheduleResolveOrReject @ zone-evergreen.js:841
then @ zone-evergreen.js:967
bootstrapModule @ core.js:42232
./src/main.ts @ main.ts:11
__webpack_require__ @ bootstrap:79
0 @ main.ts:12
__webpack_require__ @ bootstrap:79
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.js:1
Show 28 more frames
home:1 Access to XMLHttpRequest at 'https://localhost:3443/images' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
zone-evergreen.js:2828 GET https://localhost:3443/images net::ERR_FAILED
I've tried to wrap listen()
in a try...catch
but it doesn't actually catch the error. I don't want to print a stack-trace, I want to print a helpful error message. How can I catch this error? I've searched but can't find any other discussions about this problem.
Thanks a bunch for this project!
Backlink: fraction/oasis#129
"koa": "^2.12.0",
"koa-compress": "^4.0.1",
"koa-router": "^8.0.8",
"koa-static": "^5.0.0",
Hi there!
I like koa and its paradigms, but as a used-to-express user I was severely wondering how it's possible that there is no app.get()
or app.post()
. I then realized that I need koa-router for that.
Unfortunately the website / readme doesn't mention koa-router or other important middlewares like koa-body at all. Even grepping for "router" did not yield a single match.
Would be quite helpful for newbies to link to the most popular middlewares in a prominent place 😉
We are using koa-mount to mount a server based on who is logged in. We want to only allow the user that is logged in to see their servers. How can we achieve this? Can we use something like koa-session?
Middleware like koa-mount has a need to identify Koa application objects, and behave differently if found ( example ).
What would be the standard/recommended way to achieve this? Perhaps by using an exported Symbol in a sub package?
test1
router.use('/test', require('./test').routes(), require('./test').allowedMethods());
/test -->ok
/test2-->404
test2:
router.use(['/test','test2'], require('./test').routes(), require('./test').allowedMethods());
/test -->404
/test2-->404
test3
router.use('/test', require('./test').routes(), require('./test').allowedMethods());
router.use('/test2', require('./test').routes(), require('./test').allowedMethods());
/test->404
/test2-->404
test.js:
var router = require('koa-router')();
router.get('/', async function (ctx, next) {
ctx.body='ok'
})
module.exports = router;
how to make both the /test and /test2 can be accesss
I am trying to create a post RestApi in node with koa and postgresql. I have a unique email validation and want to check if email exists the it should display message user already exists with this email. My query is working but that ctx.body not working. This api is creating new user every time. It should display msg "User already exists with this email" when email exists in db. Why my ctx.body not working?
router.post('/createNewUser', async (ctx) => {
var name = ctx.request.body.name;
var email = ctx.request.body.email;
var password = ctx.request.body.password;
if (
!name ||
!email ||
!password
) {
ctx.response.status = 400;
ctx.body = {
status: 'error',
message: 'Please fill all the fields'
}
} else {
await ctx.app.pool.query("SELECT * FROM users WHERE email = $1",
[`${email}`],
(err, result) => {
if(result.rows.length > 0){
ctx.body = {
exceptions: "",
status: 200,
error: false,
message: "user already exists with this email",
};
}
});
await ctx.app.pool.query(`INSERT INTO USERS (name,email,password) VALUES ('${name}','${email}','${bcrypt.hashSync(password, 10)}')`);
const {rows} = await ctx.app.pool.query("SELECT * FROM users ORDER BY id DESC LIMIT 1");
ctx.body = {
exceptions: "",
status: 200,
error: false,
message: "User registered Successfully",
data: rows[0],
};
}
});
I'm coding API server to be used in mp3 app.
I've used koa-send
, koa-static
, and just setting mp3 file to response-body.
But, no matter what API the app uses, the app stops. When I sent the length of the MP3 file separately because the app did not seem to accept the length of the MP3 file, it worked on iOS but not on Android.
If I post the same MP3 file on S3 and send request to that URL, it worked well, so I can't understand what the problem is.
Also, if I play music on Safari using my API, it comes out as a live broadcast. (using other sites, it comes in the form of mp3)
If it's a problem that you don't know how long it's playing, why is it the same file, but not on other sites, and not on my API?
Other storage site:
My API:
I found a weird problem. We have a server-rendered service. When we were stress testing, it was normal for 100 qps, but when we set http Connection:keep-alive. There was a significant memory leak after 4 minutes and 1GB of memory in 8 minutes. We have been looking for a long time because this phenomenon disappeared after removing the koa compress middleware. I read the koa compress source, but it seems that there is nothing unusual. Can you explain it to me?thank you very much.
but i cant update examples: upload,just use koa-multer,someone else has this example?
This library doesn't work with the examples given.
Something as simple as
const serve = require('koa-static');
async function images(ctx, next) {
await next();
serve('public/images/preview/');
}
app.use(images)
And try to visit localhost:3000/1.png Not found. Please improve the documentation.
Related issues from the graveyard: koajs/koa#71, koajs/koa#74
I kind of expected to be able to mount a koa app in an express app.
You currently can only do the following:
expressApp.use('/some-path', koaApp.callback());
But this then fully takes over /some-path
. There is no way to call next
in the koaApp
and yield back to the expressApp
.
Do you think this is a feature that we could and should support?
In this example is calling await mw.call (this, ctx, next) still necessary? Can I call await mw (ctx, next)
directly?
I have a few questions: why use it, what problems it solves, and what advantages it has to compare to other
i use coffeescript rewrite this example.
koa= require 'koa'
route= require 'koa-route'
cors = require 'koa-cors'
app= module.exports= koa()
stream= require 'stream'
class Subscription extends stream.Readable
constructor: (@options)->
super
@value = 0
_read: ->
@push(String(@value++))
class SSE extends stream.Transform
_transform: (data, enc, next)->
@push 'data: ' + data.toString('utf8') + '\n\n'
next()
app.use cors()
app.use route.get '/sse', ->
# otherwise node will automatically close this connection in 2 minutes
@req.setTimeout Number.MAX_VALUE
@type= 'text/event-stream; charset=utf-8'
@set 'Cache-Control', 'no-cache'
@set 'Connection', 'keep-alive'
body= @body= new SSE
stream= new Subscription 'some event'
stream.pipe body
yield return
if not module.parent then app.listen 3000
run coffee file.coffee
then listening on port 3000
curl http://localhost:3000/sse
Original output is printed every 1ms, how could i set it every 1s.
I suspect I'll met a disagreement but I have to say it.
Request / Response aliases are very confusing. And I'm not a Koa newcomer.
Why this.body
is this.response.body
while this.headers
are this.request.headers
?
this.request.body
is used often as well as this.response.headers
. Oh, wait, the latter is this.set(...)
! Did I tell you it's confusing?
I know, it's optional and I may use full path (as I do). But, the thing is, the library
authors are following the "convention" and create first shortcut-ful then even shortcut-only APIs. Like this.path
without a proper copy in this.request.path
.
I feel like way too many things are in the single namespace right now.
Koa is mature and established. Why I bother?
Because async-await is in the Node 7.0 and I expect more people will start to adopt this framework soon. Maybe Koa 2 could take an opportunity to clean this up.
Memorizing these tables is not a friendly option
Request aliases
The following accessors and alias Request equivalents:
ctx.header
ctx.headers
ctx.method
ctx.method=
ctx.url
ctx.url=
ctx.originalUrl
ctx.origin
ctx.href
ctx.path
ctx.path=
ctx.query
ctx.query=
ctx.querystring
ctx.querystring=
ctx.host
ctx.hostname
ctx.fresh
ctx.stale
ctx.socket
ctx.protocol
ctx.secure
ctx.ip
ctx.ips
ctx.subdomains
ctx.is()
ctx.accepts()
ctx.acceptsEncodings()
ctx.acceptsCharsets()
ctx.acceptsLanguages()
ctx.get()
Response aliases
The following accessors and alias Response equivalents:
ctx.body
ctx.body=
ctx.status
ctx.status=
ctx.message
ctx.message=
ctx.length=
ctx.length
ctx.type=
ctx.type
ctx.headerSent
ctx.redirect()
ctx.attachment()
ctx.set()
ctx.append()
ctx.remove()
ctx.lastModified=
ctx.etag=
I guess this.request.foobar
felt too long to write and you probably didn't want to get this.req
confused with native Node Request
which is commonly called req
. But still this is not worth the encomplication IMO.
I am writing the middleware for API endpoints in my app that respond to webhooks from other applications, and am relatively new to Koa, so am not completely familiar with its patterns.
I would like to structure my middleware as follows:
exports.updateReceived = async (ctx, next) => {
// Respond to server issuing the webhook
ctx.res.body = "ok";
ctx.res.statusCode = 200;
// Grab what we need from the request
const { headers, state, request } = ctx;
const { body } = request;
// Do some async work
const { example } = await doSomeAsyncWork(ctx);
// Prepare a database query
const query = { aValue: anId };
// Run the DB query
const result = await Thing.findOne(query);
// Add data to the request
state.thing = result;
// Move on...
return next();
};
However, this does not appear to be working, as an error in any of my async methods can cause the route to error out.
My goal is for this endpoint to always respond "yep, ok" (immediately), meaning it is simply up to the application to handle any error states.
I have researched this fairly well, and have come across this pattern:
app.use(async ctx => {
db.fetch() // Assuming a Promise is returned
.then(() => { ... })
.catch(err => {
log(err)
})
// status 200 will be returned regardless of if db.fetch() resolves or rejects.
ctx.status = 200
})
However, this does not meet my needs as the middleware makes no use of next
, so it is not really a useful pattern, so far as I can tell.
Could someone tell me what I am overlooking? I wrote this question on StackOverflow several days ago, but getting nowhere.
I'm coding API server to be used in mp3 app.
I've used koa-send
, koa-static
, and just setting mp3 file to response-body.
But, no matter what API the app uses, the app stops. When I sent the length of the MP3 file separately because the app did not seem to accept the length of the MP3 file, it worked on iOS but not on Android.
If I post the same MP3 file on S3 and send request to that URL, it worked well, so I can't understand what the problem is.
Also, if I play music on Safari using my API, it comes out as a live broadcast. (using other sites, it comes in the form of mp3)
If it's a problem that you don't know how long it's playing, why is it the same file, but not on other sites, and not on my API?
Other storage site:
My API:
If there is a good koa module you think belongs in this organization, post a comment here and we can coordinate
I am trying out Koa for a simple app. I have used koa-static as a middlewear to serve the /public directory.
Middlewear works fine.
To run the app, I push the application to a local docker container. When running the app I found out that it caches the static files completely. Even if i completely remove entire directories it still serves those js/html files. Even a server restart doesn't seem to clear cache. Is it because koa-static may be keeping a separate set of files for cache delivery? Later I tried adding koa-no-cache to middlewear. But still doesn't seem to work.
I am not sure whether this is koa-static issue or something to do with Docker.
The repository description reads:
Expressive middleware for node.js using ES2017 async functions
The first human-readable line of the readme reads:
Expressive HTTP middleware framework for node.js to make web applications and APIs more enjoyable to write.
Essentially the package is a class wrapper around koa-compose
, allowing the composition and execution of a middleware stack on request from an HTTP server.
But why only HTTP? Is this pattern not applicable to many request+response services?
Middleware offers a functional solution to working with requests+responses services, giving developers a tool to reuse common context manipulation & comparison and assert the cleanliness of context (by early stack termination), making it an ideal container for business logic. The current nature of Koa makes it inapplicable to other request+response services common to a stack that might contain Koa and benefit from standardized request+response and common logic for other services.
Admittedly, there are several other middleware composition alternatives available, including koa-compose
, that could just as easily be wrapped in a class and attached to an emitter. Sure, this is true, but the active nature of the Koa ecosystem makes it an ideal platform to offer standardized middleware support for request+response environments. The value of being able to offer some level of standardization to various environments with a functional component that is so flexible is very appealing to me, and I would hope to developers at large.
As I see it, Koa could easily become service-agnostic while maintaining it's existing functionality as an HTTP server utility in several ways. Some less awesome than others.
The easiest & cleanest option, in my opinion, is to enable a constructor configuration supporting the following or similar properties:
new Koa({
provider: (callback, args) => { // Callback being the output of this.callback() from listen()
const server = http.createServer(callback); // Allows one to connect Koa to the emitter
return server.listen(...args); // Args provided to the listen() method as usual
},
onRequest: (args) => { // Agnostic context assembly, provided all args from callback
return {
// Service-specific context assembly
// Implement createContext by default
// 404 defaults, etc... previously handled in createContext
// Perhaps an internal/immutable context could be created here and shared with the response?
};
},
onResponse: (ctx) => { // One last method to call when the stack is finished executing
// for HTTP, this would essentially be the respond() method in lib/application.js
}
})
This solution assumes that the call to createContext
in the callback
method is replaced with a reference to onRequest
, which would return the initial context object. It also assumes that the handleRequest
method pass the context to onResponse after stack execution (which is where the statusCode would be assumed, errors handled, and on-finished
implemented for HTTP).
Default parameters could be assigned to this configuration with spread assignment, allowing the class to work out of the box with HTTP support from an external package. Perhaps the class wrapper could/should be abstracted to another package, i.e. koa-app
.
I would even consider removing onRequest and onResponse altogether and providing the parameters given to the callback to the middleware, allowing middleware to assemble the request and become responsible for the response.
At any rate, I just wanted to share my thoughts on the matter and see what the community feedback is. If this is a direction that the community is open to exploring, I would be happy to submit a PR.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.