nodejs / help

:sparkles: Need help with Node.js? File an Issue here. :rocket:
1.46k stars 279 forks source link

Is there a way to create a http server based on Fetch API? (Request, Response, Headers, ...) #4174

Open krutoo opened 1 year ago

krutoo commented 1 year ago

Details

I want to create basic HTTP server with Node.js. I also want to declare request handler based on Fetch API like this:

import { serve } from 'node:http/nonexistent';

async function handler(request) {
  await doSomething();
  return new Response('{}', { headers: { 'content-type': 'application/json' } });
}

serve(handler, { port: 1234 });

Are there any built-in packages to achieve this?

If not, how to properly use the http package and convert IncomingMessage to Request and use the Response to send response in the handler of createServer function?

Node.js version

18+

Example code

Here is my naive implementation of the serve function. I have several quetions about it:

import { createServer } from 'node:http';
import { Readable } from 'node:stream';

export function serve({ port, fetch }) {
  const base = `http://localhost:${port}`;

  const server = createServer(async (req, res) => {
    const response = await fetch(
      new Request(new URL(req.url ?? '', base), {
        // body: ???
        headers: toHeaders(req.headers),
      }),
    );

    res.writeHead(response.status, [...response.headers]);

    if (response.body) {
      Readable.fromWeb(response.body).pipe(res);
    } else {
      res.end();
    }
  });

  server.listen(port);
}

function toHeaders(headers) {
  return Object.entries(headers).reduce((acc, [name, value]) => {
    if (typeof value === 'string') {
      acc.push([name, value]);
    } else if (Array.isArray(value)) {
      value.forEach(item => acc.push([name, item]));
    }

    return acc;
  }, []);
}

Operating system

macos

Scope

runtime

Module and version

Not applicable.

preveen-stack commented 1 year ago

Can you show how the request looks like

krutoo commented 1 year ago

@preveen-stack not quite understand what the request means?

preveen-stack commented 1 year ago

If not, how to properly use the http package and convert IncomingMessage to Request and use the Response to send response in the handler of createServer function? the "Request" you mentioned in the issue

krutoo commented 1 year ago

@preveen-stack global Node.js constructors Request and Response from Fetch API:

new Request('http://site.com', { method: 'POST' });
new Response('Not found', { status: 404 });
jensmeindertsma commented 10 months ago

This seems like a pretty nice thing for Node.js to have. I'm trying to write these conversion methods myself but it's easy to mis something 😅 could this be a rework of createServer

bra1nDump commented 10 months ago

Stumbled upon this while looking for solutions on how to use itty-router with node.js. Found this so far https://www.npmjs.com/package/@whatwg-node/server ... but it says it ponyfills, which is better than polyfilling, but it still does too much magic for my liking

github-actions[bot] commented 4 months ago

It seems there has been no activity on this issue for a while, and it is being closed in 30 days. If you believe this issue should remain open, please leave a comment. If you need further assistance or have questions, you can also search for similar issues on Stack Overflow. Make sure to look at the README file for the most updated links.

krutoo commented 4 months ago

@bra1nDump @whatwg-node/server is great, thanks

But it looks like a little tricky solution and i dont think this is get great performance