4.7 KiB
Migrating from Khoa v2.x to v3.x
Breaking Changes
Node.js Version Requirement
Khoa v3 requires Node.js v18.0.0 or higher.
Removal of v1.x Middleware Support
As announced in Khoa v2.x, support for the old middleware signature (generator functions) has been removed in v3.
If you were still using generator middleware with khoa-convert, you'll need to update all middleware to use async functions or functions that return promises.
// Old way (using khoa-convert with generator middleware)
const convert = require('khoa-convert');
app.use(convert(function* (next) {
const data = yield fetchData();
yield next;
this.body = data;
}));
// New way (using async/await)
app.use(async (ctx, next) => {
const data = await fetchData();
await next();
ctx.body = data;
});
HTTP Errors Update
Khoa v3 updates http-errors to v2.0.0, which changes the signature of ctx.throw():
// Old format in Khoa v2.x
ctx.throw(status, message, properties)
// New format in Khoa v3.x
ctx.throw(status, error, properties)
See the http-errors documentation for more details.
Redirect Changes
The res.redirect('back') method has been removed. Instead, use the new ctx.back() method:
// Old way in Khoa v2.x
ctx.response.redirect('back')
// New way in Khoa v3.x
ctx.back()
QueryString Replacement
Node's querystring module has been replaced with URLSearchParams. This should be mostly transparent to users, but might cause subtle differences in query string parsing.
// Old way (Khoa v2.x using querystring)
const qs = require('querystring');
app.use(async (ctx, next) => {
const query = qs.parse(ctx.querystring);
// query['user[]'] = ['john', 'jane']
// query['items[0]'] = 'book'
await next();
});
// New way (Khoa v3.x using URLSearchParams)
app.use(async (ctx, next) => {
const query = new URLSearchParams(ctx.querystring);
// query.getAll('user') => ['john', 'jane']
// query.get('items') => 'book'
await next();
});
New Features
AsyncLocalStorage Support
Khoa v3 adds support for AsyncLocalStorage, which allows you to access the current context from anywhere in your application:
// Enable AsyncLocalStorage
const app = new Khoa({ asyncLocalStorage: true })
app.use(async (ctx, next) => {
callSomeFunction()
await next()
})
function callSomeFunction() {
// Access the current context
const ctx = app.currentContext
// Do something with ctx
}
You can also pass your own AsyncLocalStorage instance:
const { AsyncLocalStorage } = require('async_hooks')
const asyncLocalStorage = new AsyncLocalStorage()
const app = new Khoa({ asyncLocalStorage })
app.use(async (ctx, next) => {
callSomeFunction()
await next()
})
function callSomeFunction() {
// Access the current context
const ctx = asyncLocalStorage.getStore()
// Do something with ctx
}
Web WHATWG Support
Khoa v3 adds support for Web WHATWG standards, including:
- Support for
Blobobjects as response bodies - Support for
ReadableStreamobjects as response bodies - Support for
Responseobjects as response bodies
app.use(async ctx => {
// Using a Blob
ctx.body = new Blob(['Hello World'], { type: 'text/plain' })
// Using a ReadableStream
ctx.body = new ReadableStream({
start(controller) {
controller.enqueue('Hello World')
controller.close()
}
})
// Using a Response object
ctx.body = new Response('Hello World', {
headers: { 'Content-Type': 'text/plain' }
})
})
Upgrading Guide
-
Update your Node.js version to v18.0.0 or higher
-
Update all generator middleware to use async functions:
// Old way (generator middleware) app.use(function* (next) { const start = Date.now() yield next const ms = Date.now() - start console.log(`${this.method} ${this.url} - ${ms}ms`) }) // New way (async middleware) app.use(async (ctx, next) => { const start = Date.now() await next() const ms = Date.now() - start console.log(`${ctx.method} ${ctx.url} - ${ms}ms`) }) -
Update any calls to
ctx.throw()to use the new signature:// Old way (Khoa v2.x) ctx.throw(404, 'User not found', { user: 'john' }); // New way (Khoa v3.x) const error = new Error('User not found'); ctx.throw(404, error, { user: 'john' }); // You can also throw HTTP errors directly const createError = require('http-errors'); ctx.throw(createError(404, 'User not found', { user: 'john' })); -
Replace
ctx.response.redirect('back')withctx.back() -
Test your application thoroughly to ensure compatibility