diff --git a/docs/tutorial.md b/docs/tutorial.md index ecf74951..d2cfa075 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -213,8 +213,7 @@ Now, let's create a singleton class to store our notes. import { Elysia } from 'elysia' import { swagger } from '@elysiajs/swagger' -class Note { - // [!code ++] +class Note { // [!code ++] constructor(public data: string[] = ['Moonhalo']) {} // [!code ++] } // [!code ++] @@ -251,8 +250,7 @@ const app = new Elysia() .use(swagger()) .decorate('note', new Note()) .get('/note', ({ note }) => note.data) - .get('/note/:index', ({ note, params: { index } }) => { - // [!code ++] + .get('/note/:index', ({ note, params: { index } }) => { // [!code ++] return note.data[index] // [!code ++] }) // [!code ++] .listen(3000) @@ -289,8 +287,7 @@ const app = new Elysia() ({ note, params: { index } }) => { return note.data[index] }, - { - // [!code ++] + { // [!code ++] params: t.Object({ // [!code ++] index: t.Number() // [!code ++] @@ -345,8 +342,7 @@ const app = new Elysia() .get('/note', ({ note }) => note.data) .get( '/note/:index', - ({ note, params: { index }, status }) => { - // [!code ++] + ({ note, params: { index }, status }) => { // [!code ++] return note.data[index] ?? status(404) // [!code ++] }, { @@ -430,8 +426,7 @@ import { swagger } from '@elysiajs/swagger' import { note } from './note' // [!code ++] -class Note { - // [!code --] +class Note { // [!code --] constructor(public data: string[] = ['Moonhalo']) {} // [!code --] } // [!code --] @@ -440,17 +435,13 @@ const app = new Elysia() .use(note) // [!code ++] .decorate('note', new Note()) // [!code --] .get('/note', ({ note }) => note.data) // [!code --] - .get( - // [!code --] + .get( // [!code --] '/note/:index', // [!code --] - ({ note, params: { index }, status }) => { - // [!code --] + ({ note, params: { index }, status }) => { // [!code --] return note.data[index] ?? status(404, 'oh no :(') // [!code --] }, // [!code --] - { - // [!code --] - params: t.Object({ - // [!code --] + { // [!code --] + params: t.Object({ // [!code --] index: t.Number() // [!code --] }) // [!code --] } // [!code --] @@ -478,20 +469,17 @@ import { Elysia, t } from 'elysia' class Note { constructor(public data: string[] = ['Moonhalo']) {} - add(note: string) { - // [!code ++] + add(note: string) { // [!code ++] this.data.push(note) // [!code ++] - + // [!code ++] return this.data // [!code ++] } // [!code ++] - remove(index: number) { - // [!code ++] + remove(index: number) { // [!code ++] return this.data.splice(index, 1) // [!code ++] } // [!code ++] - update(index: number, note: string) { - // [!code ++] + update(index: number, note: string) { // [!code ++] return (this.data[index] = note) // [!code ++] } // [!code ++] } @@ -499,10 +487,8 @@ class Note { export const note = new Elysia() .decorate('note', new Note()) .get('/note', ({ note }) => note.data) - .put('/note', ({ note, body: { data } }) => note.add(data), { - // [!code ++] - body: t.Object({ - // [!code ++] + .put('/note', ({ note, body: { data } }) => note.add(data), { // [!code ++] + body: t.Object({ // [!code ++] data: t.String() // [!code ++] }) // [!code ++] }) // [!code ++] @@ -517,40 +503,31 @@ export const note = new Elysia() }) } ) - .delete( - // [!code ++] + .delete( // [!code ++] '/note/:index', // [!code ++] - ({ note, params: { index }, status }) => { - // [!code ++] + ({ note, params: { index }, status }) => { // [!code ++] if (index in note.data) return note.remove(index) // [!code ++] - + // [!code ++] return status(422) // [!code ++] }, // [!code ++] - { - // [!code ++] - params: t.Object({ - // [!code ++] + { // [!code ++] + params: t.Object({ // [!code ++] index: t.Number() // [!code ++] }) // [!code ++] } // [!code ++] ) // [!code ++] - .patch( - // [!code ++] + .patch( // [!code ++] '/note/:index', // [!code ++] - ({ note, params: { index }, body: { data }, status }) => { - // [!code ++] + ({ note, params: { index }, body: { data }, status }) => { // [!code ++] if (index in note.data) return note.update(index, data) // [!code ++] - + // [!code ++] return status(422) // [!code ++] }, // [!code ++] - { - // [!code ++] - params: t.Object({ - // [!code ++] + { // [!code ++] + params: t.Object({ // [!code ++] index: t.Number() // [!code ++] }), // [!code ++] - body: t.Object({ - // [!code ++] + body: t.Object({ // [!code ++] data: t.String() // [!code ++] }) // [!code ++] } // [!code ++] @@ -710,10 +687,8 @@ There are several lifecycles that we can use, but in this case we will be using ```typescript [note.ts] export const note = new Elysia({ prefix: '/note' }) .decorate('note', new Note()) - .onTransform(function log({ body, params, path, request: { method } }) { - // [!code ++] - console.log(`${method} ${path}`, { - // [!code ++] + .onTransform(function log({ body, params, path, request: { method } }) { // [!code ++] + console.log(`${method} ${path}`, { // [!code ++] body, // [!code ++] params // [!code ++] }) // [!code ++] @@ -772,91 +747,71 @@ Let's create a `user.ts` file that will handle the user authentication: ```typescript [user.ts] import { Elysia, t } from 'elysia' // [!code ++] -// [!code ++] + // [!code ++] export const user = new Elysia({ prefix: '/user' }) // [!code ++] - .state({ - // [!code ++] + .state({ // [!code ++] user: {} as Record, // [!code ++] session: {} as Record // [!code ++] }) // [!code ++] - .put( - // [!code ++] + .put( // [!code ++] '/sign-up', // [!code ++] - async ({ body: { username, password }, store, status }) => { - // [!code ++] - if (store.user[username]) - // [!code ++] - return status(400, { - // [!code ++] + async ({ body: { username, password }, store, status }) => { // [!code ++] + if (store.user[username]) // [!code ++] + return status(400, { // [!code ++] success: false, // [!code ++] message: 'User already exists' // [!code ++] }) // [!code ++] - // [!code ++] + // [!code ++] store.user[username] = await Bun.password.hash(password) // [!code ++] - // [!code ++] - return { - // [!code ++] + // [!code ++] + return { // [!code ++] success: true, // [!code ++] message: 'User created' // [!code ++] } // [!code ++] }, // [!code ++] - { - // [!code ++] - body: t.Object({ - // [!code ++] + { // [!code ++] + body: t.Object({ // [!code ++] username: t.String({ minLength: 1 }), // [!code ++] password: t.String({ minLength: 8 }) // [!code ++] }) // [!code ++] } // [!code ++] ) // [!code ++] - .post( - // [!code ++] + .post( // [!code ++] '/sign-in', // [!code ++] - async ({ - // [!code ++] + async ({ // [!code ++] store: { user, session }, // [!code ++] status, // [!code ++] body: { username, password }, // [!code ++] cookie: { token } // [!code ++] - }) => { - // [!code ++] - if ( - // [!code ++] + }) => { // [!code ++] + if ( // [!code ++] !user[username] || // [!code ++] !(await Bun.password.verify(password, user[username])) // [!code ++] - ) - // [!code ++] - return status(400, { - // [!code ++] + ) // [!code ++] + return status(400, { // [!code ++] success: false, // [!code ++] message: 'Invalid username or password' // [!code ++] }) // [!code ++] - + // [!code ++] const key = crypto.getRandomValues(new Uint32Array(1))[0] // [!code ++] session[key] = username // [!code ++] token.value = key // [!code ++] - - return { - // [!code ++] + // [!code ++] + return { // [!code ++] success: true, // [!code ++] message: `Signed in as ${username}` // [!code ++] } // [!code ++] }, // [!code ++] - { - // [!code ++] - body: t.Object({ - // [!code ++] + { // [!code ++] + body: t.Object({ // [!code ++] username: t.String({ minLength: 1 }), // [!code ++] password: t.String({ minLength: 8 }) // [!code ++] }), // [!code ++] - cookie: t.Cookie( - // [!code ++] - { - // [!code ++] + cookie: t.Cookie( // [!code ++] + { // [!code ++] token: t.Number() // [!code ++] }, // [!code ++] - { - // [!code ++] + { // [!code ++] secrets: 'seia' // [!code ++] } // [!code ++] ) // [!code ++] @@ -901,21 +856,16 @@ export const user = new Elysia({ prefix: '/user' }) user: {} as Record, session: {} as Record }) - .model({ - // [!code ++] - signIn: t.Object({ - // [!code ++] + .model({ // [!code ++] + signIn: t.Object({ // [!code ++] username: t.String({ minLength: 1 }), // [!code ++] password: t.String({ minLength: 8 }) // [!code ++] }), // [!code ++] - session: t.Cookie( - // [!code ++] - { - // [!code ++] + session: t.Cookie( // [!code ++] + { // [!code ++] token: t.Number() // [!code ++] }, // [!code ++] - { - // [!code ++] + { // [!code ++] secrets: 'seia' // [!code ++] } // [!code ++] ), // [!code ++] @@ -926,7 +876,7 @@ export const user = new Elysia({ prefix: '/user' }) { secrets: 'seia' } - ) // [!code ++] + ) }) // [!code ++] .put( '/sign-up', @@ -943,9 +893,9 @@ export const user = new Elysia({ prefix: '/user' }) message: 'User created' } }, - { + { // [!code ++] body: 'signIn' // [!code ++] - } + } // [!code ++] ) .post( '/sign-in', @@ -973,10 +923,10 @@ export const user = new Elysia({ prefix: '/user' }) message: `Signed in as ${username}` } }, - { + { // [!code ++] body: 'signIn', // [!code ++] cookie: 'session' // [!code ++] - } + } // [!code ++] ) ``` @@ -1070,47 +1020,37 @@ export const user = new Elysia({ prefix: '/user' }) cookie: 'optionalSession' } ) - .get( - // [!code ++] + .get( // [!code ++] '/sign-out', // [!code ++] - ({ cookie: { token } }) => { - // [!code ++] + ({ cookie: { token } }) => { // [!code ++] token.remove() // [!code ++] - // [!code ++] - return { - // [!code ++] + // [!code ++] + return { // [!code ++] success: true, // [!code ++] message: 'Signed out' // [!code ++] } // [!code ++] }, // [!code ++] - { - // [!code ++] + { // [!code ++] cookie: 'optionalSession' // [!code ++] } // [!code ++] ) // [!code ++] - .get( - // [!code ++] + .get( // [!code ++] '/profile', // [!code ++] - ({ cookie: { token }, store: { session }, status }) => { - // [!code ++] + ({ cookie: { token }, store: { session }, status }) => { // [!code ++] const username = session[token.value] // [!code ++] - // [!code ++] - if (!username) - // [!code ++] - return status(401, { - // [!code ++] + // [!code ++] + if (!username) // [!code ++] + return status(401, { // [!code ++] success: false, // [!code ++] message: 'Unauthorized' // [!code ++] }) // [!code ++] - // [!code ++] - return { - // [!code ++] + // [!code ++] + return { // [!code ++] success: true, // [!code ++] username // [!code ++] } // [!code ++] }, // [!code ++] - { - // [!code ++] + { // [!code ++] cookie: 'session' // [!code ++] } // [!code ++] ) // [!code ++] @@ -1167,26 +1107,20 @@ export const userService = new Elysia({ name: 'user/service' }) // [!code ++] export const user = new Elysia({ prefix: '/user' }) .use(userService) // [!code ++] - .state({ - // [!code --] + .state({ // [!code --] user: {} as Record, // [!code --] session: {} as Record // [!code --] }) // [!code --] - .model({ - // [!code --] - signIn: t.Object({ - // [!code --] + .model({ // [!code --] + signIn: t.Object({ // [!code --] username: t.String({ minLength: 1 }), // [!code --] password: t.String({ minLength: 8 }) // [!code --] }), // [!code --] - session: t.Cookie( - // [!code --] - { - // [!code --] + session: t.Cookie( // [!code --] + { // [!code --] token: t.Number() // [!code --] }, // [!code --] - { - // [!code --] + { // [!code --] secrets: 'seia' // [!code --] } // [!code --] ), // [!code --] @@ -1248,27 +1182,22 @@ export const userService = new Elysia({ name: 'user/service' }) // [!code ++] if (!enabled) return // [!code ++] - return { - beforeHandle({ - status, - cookie: { token }, - store: { session } - }) { - // [!code ++] - if (!token.value) - // [!code ++] - return status(401, { - // [!code ++] + return { // [!code ++] + beforeHandle({ // [!code ++] + status, // [!code ++] + cookie: { token }, // [!code ++] + store: { session } // [!code ++] + }) { // [!code ++] + if (!token.value) // [!code ++] + return status(401, { // [!code ++] success: false, // [!code ++] message: 'Unauthorized' // [!code ++] }) // [!code ++] const username = session[token.value as unknown as number] // [!code ++] - if (!username) - // [!code ++] - return status(401, { - // [!code ++] + if (!username) // [!code ++] + return status(401, { // [!code ++] success: false, // [!code ++] message: 'Unauthorized' // [!code ++] }) // [!code ++] @@ -1290,10 +1219,8 @@ export const user = new Elysia({ prefix: '/user' }).use(userService).get( ({ cookie: { token }, store: { session }, status }) => { const username = session[token.value] - if (!username) - // [!code --] - return status(401, { - // [!code --] + if (!username) // [!code --] + return status(401, { // [!code --] success: false, // [!code --] message: 'Unauthorized' // [!code --] }) // [!code --] @@ -1327,12 +1254,10 @@ This ensures that the property like `cookie: 'session'` exists before creating a ```ts [user.ts] export const getUserId = new Elysia() // [!code ++] .use(userService) // [!code ++] - .guard({ - // [!code ++] + .guard({ // [!code ++] cookie: 'session' // [!code ++] }) // [!code ++] - .resolve(({ store: { session }, cookie: { token } }) => ({ - // [!code ++] + .resolve(({ store: { session }, cookie: { token } }) => ({ // [!code ++] username: session[token.value] // [!code ++] })) // [!code ++] ``` @@ -1525,8 +1450,8 @@ export const note = new Elysia({ prefix: '/note' }) note.add({ data, author: username }), { // [!code ++] body: 'memo' // [!code ++] - } - ) // [!code ++] + } // [!code ++] + ) .guard({ params: t.Object({ index: t.Number() @@ -1552,7 +1477,7 @@ export const note = new Elysia({ prefix: '/note' }) if (index in note.data) return note.update(index, data) // [!code --] ({ note, params: { index }, body: { data }, status, username }) => { // [!code ++] if (index in note.data) // [!code ++] - return note.update(index, { data, author: username })) // [!code ++] + return note.update(index, { data, author: username }) // [!code ++] return status(422) }, @@ -1560,7 +1485,7 @@ export const note = new Elysia({ prefix: '/note' }) body: t.Object({ // [!code --] data: t.String() // [!code --] }), // [!code --] - body: 'memo' + body: 'memo' // [!code ++] } ) ``` @@ -1682,8 +1607,7 @@ import { user } from './user' const app = new Elysia() .use(swagger()) - .onError(({ error, code }) => { - // [!code ++] + .onError(({ error, code }) => { // [!code ++] if (code === 'NOT_FOUND') return // [!code ++] console.error(error) // [!code ++] @@ -1715,8 +1639,7 @@ import { note } from './note' const app = new Elysia() .use(swagger()) - .onError(({ error, code }) => { - // [!code ++] + .onError(({ error, code }) => { // [!code ++] if (code === 'NOT_FOUND') return 'Not Found :(' // [!code ++] console.error(error) // [!code ++] @@ -1760,7 +1683,7 @@ Now let's apply the OpenTelemetry plugin to our server. ::: code-group ```typescript [index.ts] -import { Elysia, t } from 'elysia' +import { Elysia } from 'elysia' import { opentelemetry } from '@elysiajs/opentelemetry' // [!code ++] import { swagger } from '@elysiajs/swagger'