incubrain / astrotribe

A global network of astronomers helping to inspire and educate the next generation.
https://astrotribe.vercel.app
6 stars 2 forks source link

learning: H3Event object #80

Open Drew-Macgibbon opened 1 year ago

Drew-Macgibbon commented 1 year ago

This will be a running thread about the H3Event and how I can work with the data I have access to.

The event object is a H3Event which is a circular object, which means you cannot directly log it without using a 3rd party library like import { stringify } from 'flatted'.

Drew-Macgibbon commented 1 year ago

event.req Node Object

Below is a list of some of the methods/properties. There are many more, however, these seem to be the most useful.

Property/Method Use Example
req.url The URL of the request. This can be used to determine what resource the client is requesting. logger.info(\event start: ${req.url}`)`
req.method The HTTP method used in the request. This can be used to determine what operation the client is trying to perform. if (req.method === 'GET') { /* handle GET request */ }
req.headers An object containing the headers of the request. This can be used to get additional information about the request, such as cookies or the 'User-Agent' string. const userAgent = req.headers['user-agent']
req.addListener('error', callback) or req.on('error', callback) To listen for any error events that might occur while receiving the request. req.on('error', (err) => { logger.error(`Request error: ${err.message}`) })
req.pipe() This is used when you want to directly forward the request body to another stream, for example, to a file or to another HTTP request. req.pipe(fs.createWriteStream('./path/to/destination'))
req.isPaused() This method is used to check if the request stream is paused. This can be used to control the flow of data, especially in case of large data transfers. if (req.isPaused()) { req.resume() }
req.pause() and req.resume() These methods are used to manually manage the flow of data in the request. pause() pauses the request, and resume() resumes it. if (/* some condition */) { req.pause() } else { req.resume() }
Drew-Macgibbon commented 1 year ago

event.res Node Object

These are some of the most useful event.res methods/properties.

Property/Method Use Example
res.statusCode This property is used to set the HTTP status code for the response. res.statusCode = 200;
res.setHeader(name, value) This method is used to set a specific HTTP header for the response. res.setHeader('Content-Type', 'application/json');
res.writeHead(statusCode, [statusMessage], [headers]) This method is used to send an HTTP response header to the request. This header includes the given status code, a reason phrase as a status message, and the response headers. res.writeHead(200, {'Content-Type': 'text/plain'});
res.write(chunk, [encoding]) This method is used to send a body to the response. The body can be sent in multiple 'chunks' of data. res.write('Hello World');
res.end([data], [encoding]) This method signals to the server that all of the response headers and body have been sent, and that the server should consider this message to be complete. res.end('Goodbye World');
res.addListener('finish', callback) or res.on('finish', callback) Event handler for the 'finish' event, which is emitted when the response is finished. res.on('finish', () => { logger.info('Response finished'); })
res.addListener('error', callback) or res.on('error', callback) Event handler for the 'error' event, which is emitted when there is an error generating the response. res.on('error', (err) => { logger.error(`Response error: ${err.message}`) })
Drew-Macgibbon commented 1 year ago

Other Useful event Properties/Methods

Property/Method Use Example
event.path This property can be used to access the path of the incoming request. console.log(Request path: ${event.path});
event.context This property holds context data related to the event including params and session. console.log(User Id: ${event.context.userId});
event.respondWith(response) This method is used to send a response to the client. event.respondWith(new Response('Hello, client!', {status: 200}));
Drew-Macgibbon commented 1 year ago

Putting It All Together

This would be a file in the server/ dir, usually inside the middleware || api directories.

export default defineEventHandler((event) => {
  const { req, res } = event.node
  const { path, context, respondWith } = event

  const startTime = Date.now()
  logger.info(`Event start: ${req.url}`)

  // Access the path
  console.log(`Request path: ${path}`);

  // Access the context
  console.log(`User Id: ${context.userId}`);

  // Check the HTTP method of the incoming request
  if(req.method === 'POST') {
    console.log('POST request received.')
  }

  // Set request timeout
  req.setTimeout(5000, () => {
    console.log('Request timed out.')
  })

  // Listen for 'finish' event on response
  res.on('finish', () => {
    const endTime = Date.now()
    logger.info(`Request finished: ${endTime - startTime}ms`)
  })

  // Set response headers
  res.setHeader('Content-Type', 'application/json')

  // End response with a message
  res.end(JSON.stringify({ message: 'Hello, client!' }))

  // Respond to the client
  respondWith(new Response('Hello, client!', {status: 200}))
})
Drew-Macgibbon commented 1 year ago

As far as I can tell, assigning event.context has to be done at the root level of the defineEventHandler.

eg.

// works
export default defineEventHandler(async (event) => {
  event.context.isAuthenticated = true
})
// does not work
export default defineEventHandler(async (event) => {
  function updateContext(newVal: boolean) {
     event.context.isAuthenticated = newVal
  }
  updateContext(false)
})