PUT request works in Postman but not a deno typescript file as a fetch request

Issue

I can do a put request just fine in Postman.
enter image description here

But when I try to do the same put request in a deno fresh app through a fetch command like this:

async function sendSignature() {
        const signer = provider.getSigner();
        const nonce = "asdf123492fd";
        const signatureSigned = await signer.signMessage(nonce);
        const headers = new Headers({
            'Content-Type': 'application/json'
          });
        const opts = {
            method: 'PUT',
            headers: headers,
            body: JSON.stringify({
                key: props.singleUser,
                wallet_address: walletAddrs,
                signature: signatureSigned
          })
        }
        console.log(opts.body);
        const rawPosts = await fetch('http://localhost:4000/users/kythis1', opts);
        console.log(rawPosts);
    }

Btw all of the values are being populated in body. I can confirm that key, wallet_address, and signature are not null and are strings. It fails though… Here’s what the browser’s console looks like.
enter image description here

This is the entry point for the backend oak (deno’s version of express) server.

import { Application } from "https://deno.land/x/oak/mod.ts";
import { APP_HOST, APP_PORT } from "./config.js";
import router from "./routes.js";
import _404 from "./controllers/404.js";
import errorHandler from "./controllers/errorHandler.js";
import { oakCors } from "https://deno.land/x/cors/mod.ts";

const app = new Application();

app.use(oakCors()); // Enable CORS for All Routes
app.use(errorHandler);
app.use(router.routes());
app.use(router.allowedMethods());
app.use(_404);

console.log(`Listening on port:${APP_PORT}...`);

await app.listen(`${APP_HOST}:${APP_PORT}`);

This is the function that is getting called by the put request:

import User from "../db/database.js";

export default async ({ request, response }) => {
  if (!request.hasBody) {
    response.status = 400;
    response.body = { msg: "Invalid user data" };
    return;
  }

  const body = request.body();
  const {
    key, wallet_address, signature
  } = JSON.parse(await body.value);

  console.log(signature);

  if (!key) {
    response.status = 422;
    response.body = { msg: "Incorrect user data. Email and key are required" };
    return;
  }

  const foundUser = await User.where('key', '=', key).first();
  if (!foundUser) {
    response.status = 404;
    response.body = { msg: `User with key ${key} not found` };
    return;
  }
  foundUser.wallet_address = wallet_address;
  foundUser.updated_at = new Date();
  const updatedResp = await foundUser.update();

  response.body = { msg: "User updated", updatedResp };
};

Finally this is the backend routes:

import { Router } from "https://deno.land/x/oak/mod.ts";

import getUsers from "./controllers/getUsers.js";
import getUserDetails from "./controllers/getUserDetails.js";
import createUser from "./controllers/createUser.js";
import updateUser from "./controllers/updateUser.js";
//import deleteUser from "./controllers/deleteUser.js";

const router = new Router();

router
  .get("/users", getUsers)
  .get("/users/:key", getUserDetails)
  .post("/users", createUser)
  .put("/users/:key", updateUser);
  
  //.delete("/users/:id", deleteUser);

export default router;

So why can I successfully call this function with a Postman put request, but I can’t do a successful put request with fetch through a typescript file?

Solution

Your postman and fetch call aren’t exactly the same.
Looking at postman it has 8 headers, and content-type seems to be set on Text.
While the fetch() is set on application/json.

When content type is application/json your request.body() is likely already parsed. Thus another JSON.parse will throw an error.
One easy fix with your current code would be to set your javascript headers to this:

const headers = new Headers({
            'Content-Type': 'text/plain'
          });
      

This will avoid 2 times parsing of the json file.

But the better fix would be to actually use application/json and see/log what request.body() returns.

Answered By – Hedgelot

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published