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

Unable to access request body when using the router #132

Open
radu-matei opened this issue Feb 19, 2023 · 7 comments
Open

Unable to access request body when using the router #132

radu-matei opened this issue Feb 19, 2023 · 7 comments

Comments

@radu-matei
Copy link
Member

radu-matei commented Feb 19, 2023

I seem to be unable to access the request body when using the router. If I parse the body in handleRequest (the commented line), I can access it and everything works well.
When I pass the request to the router, I can't access the body anymore.

For example:

router.post("/api/test", async req => {
    console.log(JSON.stringify(req));
    console.log(new TextDecoder().decode(req.body));
});

export async function handleRequest(request: HttpRequest): Promise<HttpResponse> {
    // console.log(new TextDecoder().decode(request.body));
    return await router.handleRequest(request);
}

This results in:

{"method":"POST","url":"http://localhost:3001/api/test","query":{},"params":{}}
Handler returned an error: Uncaught TypeError: cannot read property 'buffer' of undefined

I am able to pass it as an extra argument:

    return await router.handle({
        method: request.method, url: request.uri}, { body: request.body });

However, I think it should be part of the request object passed by default.

@karthik2804
Copy link
Collaborator

This is because of how itty-router works. The first parameter passed to itty-router is of type RequestLike which does not contain a body field (only method & url).
https://github.com/kwhitley/itty-router/blob/ab002f2e43964874ad60e91e8610c76c4c347268/src/itty-router.ts#L5

The first parameter passed to the route handling function is of type IRequest which does not contain the body field either.
https://github.com/kwhitley/itty-router/blob/v3.x/src/itty-router.ts#L5

I will look into this to see if there are any easy ways of bypassing this issue.

@radu-matei
Copy link
Member Author

Ok, that is good to know.
Ideally, we want to document this behavior and make it clear how it should be used.

@bacongobbler
Copy link
Member

bacongobbler commented May 5, 2023

I just hit a similar issue while migrating over to the new JS router. Thanks @radu-matei for the workaround.

It appears there's some middleware in itty-router-extras that will allow users to safely parse and embed request bodies. Is that something we can integrate with here?

https://www.npmjs.com/package/itty-router-extras#withcontent

@karthik2804
Copy link
Collaborator

The last time I looked at it, It did not run properly due to missing functions in the runtime I think. I will take a look again and see if it is a quick fix.

@bacongobbler
Copy link
Member

bacongobbler commented May 5, 2023

Yeah, I just tested this locally by attempting to bypass spin's builtin router and use itty-router directly. You get a stack trace as soon as you call req.json().

code snippet:

import { HandleRequest, HttpRequest, HttpResponse } from "@fermyon/spin-sdk";
import { Router } from "itty-router";

const router = Router();

router.post("/", async req => {
	console.log("Parsing body");
	let content = req.json();
	return {
		status: 200,
		body: JSON.stringify(content)
	}
}

export const handleRequest: HandleRequest = async function (request: HttpRequest): Promise<HttpResponse> {
	return await router.handle({
		url: request.uri,
		method: request.method
	});
};

Log output from a POST request:

Parsing body
Handler returned an error: Uncaught TypeError: not a function

@bacongobbler
Copy link
Member

For others, here's a full example showing how to read the request body using the Spin router:

import { HandleRequest, HttpRequest, HttpResponse } from "@fermyon/spin-sdk";

const router = utils.Router();
let decoder = new TextDecoder();

router.post("/", async (_, body) => {
	let message = decoder.decode(body);

	return {
		status: 200,
		body: message,
	};
});

export const handleRequest: HandleRequest = async function (request: HttpRequest): Promise<HttpResponse> {
	return await router.handleRequest(request, request.body);
};

@karthik2804
Copy link
Collaborator

@bacongobbler, The error you ran into might be due to the function not existing on the body. There was a bug with the typing fixed by the following

7ff233a

But excluding that, I also notice that you are not using the itty-router-extras middleware. itty-router by default does not take in a body. The first example you tried also seems broken because the entire request is not even being passed.

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

3 participants