kwhitley / itty-router

A little router.
MIT License
1.77k stars 78 forks source link

Using itty-router locally #106

Closed dremekie closed 1 year ago

dremekie commented 2 years ago

Could you share a snippet of how I would use Node to create a local http server that uses itty-router?

Something like:

const { Router } = require('itty-router');
const http = require('http');

const ittyRouter = Router();
ittyRouter.get('/about', () => {
  return 'My response';
});

const server = http.createServer(function (req) {
  ittyRouter.handle(req);
});

server.listen(4444);

With the above, GET http://127.0.0.1:4444/about throws TypeError [ERR_INVALID_URL]: Invalid URL

bever1337 commented 2 years ago

A node http request+response pair have almost no overlap with the JS-standard http request+response pair. There is no host or hostname field on the Node request, so it is not possible to construct a fully qualified url with new URL from a node request object. I think something like this will get you closer to using an itty handler:

const MY_HOST_NAME = ...; // I don't know your host name, but I bet you do!
const response = ittyRouter.handle(new Request(new URL(req.url, MY_HOST_NAME), request)); // this is async, should 
// now be sure to use node `res`! Unlike service workers or CF workers, you have to manually write to the response instead of just resolving
bever1337 commented 2 years ago

Is it possible to convert this into a discussion? I started a similar thread here: https://github.com/kwhitley/itty-router/discussions/107

Instead of using itty with a node http server, I am using itty inside a service worker. Service workers have unique requirements about responding to events synchronously which itty cannot do.

I wonder if the itty README examples can show some platform-specific nuances for each use-case?

Rush commented 2 years ago

I was considering using itty-router for a hybrid Cloudflare worker/node server app but looks like it's not supported. I need my code to run either on Cloudflare or locally depending on a use case.

janat08 commented 2 years ago

There's h3 router.

Rush commented 2 years ago

Will check out h3, thank you!

janat08 commented 2 years ago

Miniflare is a better place for this issue.

gerukin commented 2 years ago

If you want to use itty in a normal node environment (Node 18+) you can do something like this:

import http from 'http'
import { Router } from 'itty-router'

const HOST = 'localhost'
const PORT = 8000

const baseRouter = Router()
// healthcheck endpoint
baseRouter.get('/ok', () => new Response('🎉🎉🎉'))
// some json
baseRouter.get('/json', () => new Response(JSON.stringify({ status: 'ok' }), { headers: { 'content-type': 'application/json' } }))
// any other route is an error (should instead throw custom errors, with error codes and so on)
baseRouter.all('*', () => { throw new Error('💥💀💥') })

// start a regular node server
http.createServer(async (req, res) => {
    const resp = await baseRouter.handle(

        // ******************** 🙋‍♂️ ADAPTER STUFF : START ***********************
        // create a Request (requires node 18+) object from node's IncomingMessage,
        // which can be accepted by itty - router
        new Request(
            new URL(req.url, 'http://' + req.headers.host),
            {
                // should also map headers, body....
                method: req.method
            }
        )
        // *********************** ADAPTER STUFF : END ***********************

    ).catch(err => new Response(err.message, { status: 500 }))

    // ******************** 🙋‍♂️ ADAPTER STUFF : START ***********************
    // map the Response to node's expected ServerResponse
    res.writeHead(resp.status, resp.statusText, resp.headers)
    res.end(await resp.text() + '\n')
    // *********************** ADAPTER STUFF : END ***********************

}).listen(PORT, HOST, err => {
    if (err) throw err
    console.log('Server listening on ' + HOST + ':' + PORT)
})

Haven't run any mem or perf benchmarks. I love itty in CF, but I'm not sure how this version with adapter in node compares to using h3, polka or other routers.

ruslantalpa commented 1 year ago

Or ... you could just add this line before calling handle

if (req.url && req.url[0] === '/') req.url = `http://${req.headers.host}${req.url}`