405 error / CORS Allow Origin error

After a few days of research and debugging, I'm here to see if anyone can shed some light on my problem. I apologize for the long post. I just want to be thorough.
Main Problem
The 405 error. I'm almost certain that fixing this will solve the CORS error. According to research, the 405 error means that the LS API recognizes my request, but rejects it. I'm not sure what is causing this rejection. The main fix is to make sure the requested URL is correct. This can't be my issue because the same URL works perfectly in Postman. Possibly something wrong in my headers? The only thing I can assume is that Lightspeed won't give access to http://localhost. Most other suggested fixes involve changing around backroom settings inside the CMS being used.
Overview
Here is my file:
import React, { useState, useEffect } from "react" import Layout from "../components/layout" import Seo from "../components/seo" const axios = require("axios") const IndexPage = () => { const [item, setItem] = useState([]) const [loading, setLoading] = useState(true) // My super secret keys const key = process.env.ACC_ID const token = process.env.TOKEN const access_token = `Bearer ${token}` // Using Axios to make request, and storing it inside fetchItems to be called later inside a React useEffect hook. const fetchItems = async () => { axios .get( `https://api.lightspeedapp.com/API/Account/${key}/Item.json?load_relations=["ItemShops", "Category"]&ItemShops.qoh=>,1&categoryID=15&limit=5`, { headers: { Authorization: access_token, Accept: "application/json", // Some suggested adding this in the header, but it seems to achieve absolutely nothing. "Access-Control-Allow-Origin": "*", }, } ) .then(function (response) { // handle success console.log(response) // Remove the loader from screen and display the content. setLoading(false) }) .catch(function (error) { // handle error console.log(error) }) .then(function () { // always executed }) } useEffect(() => { fetchItems() // eslint-disable-next-line }, []) return loading ? ( <h2>Loading...</h2> ) : ( <Layout> <Seo title="Home" /> <h1>Hello World!</h1> </Layout> ) } export default IndexPage
The Important Bit
const fetchItems = async () => { axios .get( `https://api.lightspeedapp.com/API/Account/${key}/Item.json?load_relations=["ItemShops", "Category"]&ItemShops.qoh=>,1&categoryID=15&limit=5`, { headers: { Authorization: access_token, Accept: "application/json", // Some suggested adding this in the header, but it seems to achieve absolutely nothing. "Access-Control-Allow-Origin": "*", }, } ) ... ... }
Either I'm not providing sufficient credentials or I'm providing them incorrectly.
More Info
The error in Firefox Dev Tools. No errors appear in my development environment.
The successful request from Postman. Proof the URL is correct.
I've set both the Website and Redirect URI to http://localhost when setting up my Lightspeed Retail API Client at https://cloud.lightspeedapp.com/oauth/update.php
Bottom Line
The request is fine in Postman. When the same information is transferred to my IDE, I'm suddenly not authorized by Lightspeed. I don't know what I'm missing. Let me know if I can offer more information.
Links
Axios GitHub - https://github.com/axios/axios
Info on 405 Errors - https://airbrake.io/blog/http-errors/405-method-not-allowed
7 comments
Hey,
Thanks for reaching out! Are you still experiencing this error?
Thanks
Paul
Hello,
I haven't found a solution yet. I still believe the problem lies within my fetch request.
Here is how the calls interact over the network:
I'm getting the "CORS Missing Allow Origin" and "NS_ERROR_DOM_BAD_URI" errors. The first error is caused by Lightspeed's rejection of my request. It returns an options call that is supposed to contain the "Access-Control-Allow-Origin" in the response header. It isn't listed though which makes me wonder how I'm supposed to gain access to the api.
I thought part of the problem was caused from a cross-domain specification while trying to request information from https:// to http://. I stopped believing this when I hosted the project on an https:// Netlify url and was receiving the same issues.
Another weird thing is when I click the NS error related to the POST request, the description says "The request method must be POST when requesting an access token". The browser is recognizing it as a POST as shown in the picture above, so I'm at a loss.
I've read each documentation page at least 10 times now, some related community questions from others here, and loads of other forums, blog posts, and videos. I just can't seem to figure out where I'm going wrong. Cors doesn't seem to like me very much.
This appears to be a challenge running Axios on a localhost. Here's a long discussion thread on their GitHub project site. Perhaps one of the workarounds in there might help?
https://github.com/axios/axios/issues/569
I don't believe axios is the problem. I tried using the fetch API as well. Everything comes full circle to:
I don't know how anybody else using the LS Retail API bypassed this. I've made many api calls in many projects. This api is proving more difficult to access than any I've used. Here are the only possible solutions I've come across:
This article explains my exact problem:
Through trial, error, and researching, my understanding is the the LS API does not offer cors support and I'm in no position to enable it. The above error keeps being thrown because the https://api.lightspeedapp.com/API/Account.json endpoint (for example) will ONLY give access to someone who is making a request from https://api.lightspeedapp.com. Since I'm using http://localhost:8000 (development) or https://juicemenu.netlify.app/ (production), it doesn't match the Same https://api.lightspeedapp.com Origin and automatically refuses anyone making a request from another url. This is a theory. I don't actually know who is given access since its not returned in the OPTIONS response header. I thought the purpose of setting up the API Client details at https://cloud.lightspeedapp.com/oauth/update.php was to "ok" access to localhost and then I would change it to the Netlify url when it was ready to be hosted, just like every other api.
I've tried installing the cors package, but its use of express destroys my dev environment for some reason.
If I swap the url to something like https://jsonplaceholder.typicode.com/todos using the same http request, it works perfectly fine and I receive the requested data. It is a "simple" call that doesn't require any credentials though. As soon as I add the
header, it turns into a "non-simple" or "complex" http request. I've tried every combination of non-forbidden header out there but nothing is enough because I can't get the OPTIONS method returned by the browser from Lightspeed to return the Access-Control-Allow-Origin header.
I self-host my own API web service, which in turn makes the API calls out to the Lightspeed Retail API endpoints. It works fine and doesn't fail due to CORS issues.
While the source code below is in C#, you get the idea about what my Options method is doing. When it receives an OPTIONS request, it sends back the following header values.
public HttpResponseMessage Options()
{
var resp = new HttpResponseMessage(HttpStatusCode.OK);
resp.Headers.Add("Access-Control-Allow-Origin", "*");
resp.Headers.Add("Access-Control-Allow-Methods", "*");
resp.Headers.Add("Access-Control-Allow-Headers", "*");
resp.Headers.Add("Access-Control-Allow-Credentials", "true");
return resp;
}
It's up to the API server end to specify CORS policy. So you'd likely have to implement your own API web service in order to API clients to consume things.
All I'm trying to do is render product information returned from the LS API to my website using javascript.
Here's what I've learned in this process:
It seems I'm misunderstanding the purpose of this API and/or how it's meant to be used. If it's up to the API server end to specify cors policy, what's stopping LS from modifying it to fit these needs? I scanned ~800 discussions and the 3 that were relatable weren't that helpful. Is my issue really that odd?
If anyone's still interested in helping me find a solution, check out the website for more info -> https://juicemenu.netlify.app/