Issue with reassigning ctx.query and type preservation
wjonesusna2012 opened this issue · comments
Describe the bug
Node.js version:
16.15.1
OS version:
Windows 11
Description:
Per the Koa docs, you can reassign to the ctx.query object. Whenever I do so, any typing that I have, is not preserved in future middleware or future calls to ctx.query (i.e. a value of [ 2 ] in the object just becomes '2' or the number 5 becomes the string '5'), although the actual assignment does seem to occur as indicated below by the fact that id becomes 4 after assignment, indicating something has changed.
Actual behavior
INITIAL QUERY OBJECT [Object: null prototype] { id: '2', arr: '5' }
QUERY FROM JOI VALIDATION [Object: null prototype] { id: 2, arr: [ 5 ] }
number
CTX.QUERY AFTER ASSIGNMENT [Object: null prototype] { id: '4', arr: '5' }
QUERY IN 2ND MIDDLEWARE [Object: null prototype] { id: '4', arr: '5' }
string
Expected behavior
This is what I would expect from code example below.
INITIAL QUERY OBJECT [Object: null prototype] { id: '2', arr: '5' }
QUERY FROM JOI VALIDATION [Object: null prototype] { id: 2, arr: [ 5 ] }
number
CTX.QUERY AFTER ASSIGNMENT [Object: null prototype] { id: 4, arr: [ 5 ] }
QUERY IN 2ND MIDDLEWARE [Object: null prototype] { id: 4, arr: [ 5 ] }
number
Code to reproduce
I've included a stack overflow entry and code sandbox that replicates this issue in addition to my project on my Windows 11 computer.
https://stackoverflow.com/questions/75368044/unable-to-reassign-ctx-query-in-a-koa-middleware
const Koa = require("koa");
const app = new Koa();
const Joi = require("joi");
const PORT = 3000;
const validSchema = Joi.object({
name: Joi.string().optional(),
id: Joi.number().required().min(0),
arr: Joi.array().items(Joi.number()).optional().single(),
});
// #1
app.use(async (ctx, next) => {
console.log("INITIAL QUERY OBJECT", ctx.query);
const { error, value } = validSchema.validate(ctx.query);
if (!!error) ctx.throw(400, error);
console.log("QUERY FROM JOI VALIDATION", value);
value.id += 2;
console.log(typeof value.id);
ctx.query = value;
console.log("CTX.QUERY AFTER ASSIGNMENT", ctx.query);
await next();
});
// #2
app.use(async (ctx, next) => {
console.log("QUERY IN 2ND MIDDLEWARE", ctx.query);
console.log(typeof ctx.query.id);
await next();
});
app.use(async (ctx, next) => {
ctx.body = `test koa`;
});
app.listen(PORT);
console.log(`http://localhost:${PORT}`);
ctx.query
uses querystring
to parse query parameters internally.
when you set ctx.query = value
,It is equivalent to ctx.query = querystring.stringify(value)
;
when you get ctx.query
, It will return querystring.parse(value)
。
https://github.com/koajs/koa/blob/master/lib/request.js in 172 line
This isn't a bug but a side effect of how delegation works in Context
.
The return value from accessing ctx.query
is actually coming from context delegating access to ctx.request.query
. As @senfish wrote the result you're seeing is the evaluated queryparser result. I would recommend you instead took the result from Joi and assigned it to something under e.g. ctx.state.validatedQuery
.
I'm closing this ticket as this is not a bug. If you still have questions you can re-open this or a new ticket.