Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Koa example in Typescript - cant modify stream #1143

Open
webrunner42 opened this issue Apr 6, 2023 · 3 comments
Open

Koa example in Typescript - cant modify stream #1143

webrunner42 opened this issue Apr 6, 2023 · 3 comments

Comments

@webrunner42
Copy link

I'm a trading card game, and looking for a way to set up the decks at the beginning of the match.
The docs have an example :

const server = Server({ /* options */ });

// Add middleware to the create game route.
server.router.use('/games/:name/create', async (ctx, next) => {
  // Decide number of players etc. based on some other API.
  const { numPlayers, setupData } = await fetchDataFromSomeCustomAPI();
  // Set request body to be used by the create game route.
  ctx.request.body.numPlayers = numPlayers;
  ctx.request.body.setupData = setupData;
  next();
});

server.run(8000);

but I'm not sure if something has changed since here but using koa, the body isn't parsed yet when we get to this point, so ctx.request.body doesnt exist. If we try to parse the body here (using koaBody() or something) then later, since the body is already parsed, the boardgame.io game creation ui breaks because the stream is already closed and no longer readable.

I've tried something like this:

ctx.request.body = {}
ctx.request.body.setupData = {decks:decks}
next();

but it gets clobbered by koabody.

And obviously I cant make the changes -after- the game creation api does it's thing because the game constructor is already called.

Is there a work around? making the changes and writing 'back' a new stream to the context? A setting that makes bgio use the previously parsed body and skip using koaBody?

@webrunner42
Copy link
Author

For people in the future3 who have this problem:

 let chunk;
    while (null !== (chunk = ctx.req.read())) {
      // get rid of the existing things
    }
    const toUnshift = JSON.stringify(bodyJson);
    ctx.req.unshift(toUnshift);
    ctx.req.headers["content-length"] = toUnshift.length.toString();

this will clobber the existing body and replace it with your own

@kevinddchen
Copy link
Contributor

Your specific use-case may be handled by the setup() callback: https://boardgame.io/documentation/#/api/Game

However, I also want to add middleware to modify the server behavior, e.g. invalidate player names upon joining a match if another player has that same name. #1107 is another issue on the same topic.

@kevinddchen
Copy link
Contributor

@webrunner42 Thank you very much for your snippet! 🎉 I was able to arrive at a good workaround. My use-case was pretty simple, since I just needed to intercept the body and then pass it without any changes. For reference, this is what I used:

async (ctx, next) => { 

    const chunks = [];
    let chunk;
    while (null !== (chunk = ctx.req.read())) {
      chunks.push(chunk);
    }

    const rawBody = Buffer.concat(chunks).toString('utf8');
    const body = JSON.parse(rawBody);

    // do stuff

    ctx.req.unshift(rawBody);
    ctx.req.headers["content-length"] = rawBody.length.toString();
    await next();
  });

It seems that a more permanent fix may be added to the koa library: koajs/bodyparser#127.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants