Only [multipart/form-data] content type allowed. but got application/x-www-form-urlencoded NODE.JS SDK

Hello everyone,
I’m encountering a 400 response while using the new node.js SDK. I was wondering if anyone has seen this error when trying to upload images through the catalogApi.createCatalogImage function. Any help would be much appreciated, if more information is needed, just ask below :slight_smile:

//imports being used for endpoint

const fs = require('fs-extra');
const FileWrapper = require('file-wrapper');
const { Client, Environment } = require('square')



let file = new FileWrapper(fs.createReadStream('./Assets/crush-it.png'));

  try {
    const response = await client.catalogApi.createCatalogImage({
      idempotencyKey: v4(),
      image: {
        type: 'IMAGE',
        id: '#crushit',
        imageData: {
          name: 'Crush It T-Shirt',
          caption: 'Crush It T-Shirt'
        }
      }
    },
    file);

    console.log(response.result);
  } catch(error) {
    console.log(error);
  }

Hi @EJ132 welcome to the forums!

Which version of the node.js SDK are you using? So far I’ve been unable to replicate.

Hey @sjosey thanks :slight_smile:

I am currently using square: 9.1.0, and node: 12.16.1.

I modified the seed script from Square’s connect-api-examples repo. My version is here: square-express-shopping-cart-public/seed-catalog.js at main · manda-farmer/square-express-shopping-cart-public · GitHub
Make sure that you backup your catalog before running this script.
I just tested it with version 9.1 of the SDK and was able to push data to the catalog. It uses ES6-style imports, so make sure you run

~$ npm install esm --save

and append

-r esm

to your script like so:

{
  "name": "square-seed-catalog",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "seed": "NODE_ENV=sandbox node -r esm ./seed-catalog.js generate",
    "help": "NODE_ENV=sandbox node -r esm ./seed-catalog.js --help"
  },

The script pulls data from file sample-seed-data.json. For your use case:

 "#Crush It T-Shirt": {
   "image": {
      "url": ".Assets/crush-it.png",
      "id": "#crushit",
      "caption": "Crush It T-Shirt"
    },

Here is the relevant section of the seed script:

import { Client, Environment, FileWrapper } from 'square';

import sampleData from './sample-seed-data.json';
import fs from 'fs';
import readline from 'readline';
import 'dotenv/config';

// We don't recommend to run this script in production environment
// Configure OAuth2 access token for authorization: oauth2
const config = {
  environment: Environment.Sandbox,
  accessToken: process.env.SQUARE_SANDBOX_ACCESS_TOKEN
};
// Configure catalog API instance
const { catalogApi } = new Client(config);

/*
 * Given an object with image data and a corresponding catalogObjectId,
 * calls the createCatalogImage API and uploads the image to the corresponding catalogObjectId.
 * For more information on the createCatalogImage API, visit:
 * https://developer.squareup.com/reference/square/catalog-api/create-catalog-image
 * @param Object with Image information
 * @param String catalogObjectId
 */
const addImages = async (image, catalogObjectId, success) => {
  // Create JSON request with required image information requirements.
  const request = {
    idempotencyKey: require("crypto").randomBytes(64).toString("hex"),
    objectId: catalogObjectId,
    image: {
      id: image.id,
      type: "IMAGE",
      imageData: {
        name: image.name,
        caption: image.caption,
      },
    },
  };

  const fileReadStream = fs.createReadStream(image.url);
  const imageFile = new FileWrapper(fileReadStream, {
    contentType: 'image/jpeg',
  });

  try {
    const { result: { image } } = await catalogApi.createCatalogImage(request,imageFile);
    success();

  } catch (error) {
    console.error("Image upload failed with error: ", error);
  }
}
*
 * Main driver for the script.
 */
const args = process.argv.slice(2);
if (args[0] == "generate") {
  addImages();
} else if (args[0] == "-h" || args[0] == "--help") {
  console.log(
    "Please check the README.md for more information on how to run our catalog script.\nAvailable commands include:\n npm run seed - Generates catalog items for your sandbox catalog.\n npm run clear - Clears your sandbox catalog of all items.\n\n More information can also be found on our Quick Start guide at https://developer.squareup.com/docs/orders-api/quick-start/start."
  );
} else {
  console.log("Command not recognized. Please try again.");
}

Obviously, it will need some tweaking, but hopefully this points you in the right direction and will allow you to scale out your code a little more to add batches of images.

Thank you so much @mniaey definitely helpful!

Yay! What kind of app are you building?

@mniaey I’m building a react/node.js app for a client that wants a custom built gym site!

That’s awesome! I’m building a React + Express Node stack for my farm! So far, I have written a product page and some functions to add items to a cart for the front end, and the back end has pretty much all the functionality I need (for now - I still have to figure out my method for handling pre-packaged items of variable weight, like frozen meat.) Feel free to clone my repo and use whatever you need as a base. I have already adapted it to use ES6 imports, and tested most of it against SDK 9.1.0. It also includes a (sloppy) fix for the switch to BigInt over numbers in SDK >= 9.0.0 Sorry about the incomplete documentation - hopefully, it creates a good enough picture for you to work your way through the different routes. I also include the option to create an invoice in the checkout flow so that unpaid orders can be pushed to a Square POS and paid in person for lower fees, while still being accessible outside of the application itself.

My hope is to build a decoupled boiler plate stack for other to use, sort of like the API examples on GitHub but more geared towards a microservices environment so that a client login that accesses the Customers API can be integrated while minimizing the chances of customer data exposure. Based on the documentation I have been reading, I think FusionAuth will be the best bet for an out of the box solution with ExpressJS focused documentation.

Feel free to DM me if you have questions/are stuck/want to collaborate on building out reusable tools for the greater Square dev community. I have only been writing JS since August during small pockets of “spare” time since my farm needs a spiffy site, but sometimes a fresh set of eyes can make a big difference!

I got an e-mail notification with your original, unedited post, and it looks like we’re actually using the same frameworks for our stacks. In light of that, DEF HMU if you’re interested in bouncing ideas off of each other.

Yes please! I def have some questions, I don’t know if DM’s are a thing on this site but my email is ejg132@gmail.com

Send me an email and I’ll be in touch :slight_smile:

Looking forward!