REST API post not working

I’m playing around with creating a simple jQuery ajax request to turn on a light. Here is my JS

$(".test").click(function() {
  var data;
  data = {
    "entity_id": "light.lifx"
  };
  return $.ajax({
    url: 'http://HASSIP:8123/api/services/light/turn_on',
    headers: {
      "x-ha-access": "MYPASS"
    },
    dataType: "json",
    data: JSON.stringify(data),
    contentType: 'application/json',
    type: 'POST',
    success: console.log("The Light is on!")
  });
});

When I click my link, i get these errors

[Error] Failed to load resource: the server responded with a status of 405 (Method Not Allowed) (turn_on, line 0)
[Error] Failed to load resource: Preflight response is not successful (turn_on, line 0)
[Error] XMLHttpRequest cannot load http://HASIP:8123/api/services/light/turn_on. Preflight response is not successful

When I call the service with curl, it works.
When I call the service with postman, it works.
Can anyone tell what I’m doing wrong?
Thanks.

Are you familiar with web technologies? Currently your problem seems to be with CORS. As can be seen with the error message “Preflight response is not successful”. Please make sure to read up on CORS and pre-flight.

Your solution is within here: https://home-assistant.io/components/http/

Let me know if you need further explanation :slight_smile:

~Cheers

Thanks for the reply, I looked over the HTTP docs and added the below to my config, although, I don’t think that CORS is the issue considering I am able to have it work with curl and postman from the same machine and environment.
After adding the below, I now get a 403:Forbidden Error instead of the 405

http:
api_password: !secret api_password
cors_allowed_origins:
- http://10.0.0.11
trusted_networks:
- 10.0.0.11

My goal is to just test out building a simple custom web ui using the REST API. For now, I’m building it on my dev machine, but I plan on hosting it on my raspi when I figure it all out

That’s why I asked you about your familiarity with web technologies. You miss a basic point here. curl and postman are working BECAUSE they don’t do preflight, jQuery does. That’s why you got method not allowed before. 403 forbidden means wrong password. Try either without the password header or without the trusted network would be my guess.

~Cheers

My familiarity with apis is limited to integrating services that provide api_keys, so I’m not familiar with the fundamentals of CORS to answer your question.
With that being said, I’ve checked my password and its correct and I’ve also tried removing the api_password requirement, still getting the error below.

[Error] Failed to load resource: the server responded with a status of 403 (Forbidden) (toggle, line 0)
[Error] Failed to load resource: Preflight response is not successful (toggle, line 0)
[Error] XMLHttpRequest cannot load http://10.0.0.6:8123/api/services/switch/toggle. Preflight response is not successful

Also, will I have to worry about CORS etc if I host local on my raspi?
Thanks for your help with this.

You have to worry about cors as soon as your HA IP != the host from where the JS comes. I’ll give this a try myself and see what I come up with.

~Cheers

Just tried it out worked flawlessly. I have it running on a server here and had a apache on a different machine. First I got the 405 but after adding it the cors part to the http it worked. Maybe you could share your whole http config as well as some more details? Maybe remove the password for testing purposes?

~Cheers

Thanks phyber,
Here is the entire http section of my configuration.yaml
My HASS raspi has the IP 10.0.0.6
My dev machine IP where I am making the api call is 10.0.0.11 and is serving the JS and HTML on MAMP.

http:
  api_password: password
  cors_allowed_origins:
    - http://10.0.0.11

Ive tried commenting out the api_password for testing, but get the same result.
I do my JS in CoffeeScript, but it compiles to

(function() {
  $(function() {
    var callService;
    callService = function(domain, service, data, callback) {
      return $.ajax({
        url: 'http://10.0.0.6:8123/api/services/' + domain + '/' + service,
        headers: {
          "x-ha-access": "password"
        },
        dataType: 'json',
        data: JSON.stringify(data),
        contentType: 'application/json',
        type: 'POST',
        success: function(res) {
          return console.log(res);
        }
      });
    };
    return $(".test").click(function() {
      var data;
      event.preventDefault();
      data = {
        "entity_id": "switch.kitchen"
      };
      return callService('switch', 'turn_on', data);
    });
  });

}).call(this);

My HASS is HAssbian

Just dawned on me, could it have to do with the JS be served from MAMP?

So I got it working after stumbling across this site https://www.thepolyglotdeveloper.com/2014/08/bypass-cors-errors-testing-apis-locally/ thanks to @PhyberApex for mentioning CORS.
The problem as it turns out is due to me using Safari. I had to check “Disable Cross-Origin restriction” in the Develop menu, then it started working.
I’m not sure if this is an actually solution though, I am suspecting it has to do with me using MAMP to serve my JS and disabling this setting is just a bypass

2 Likes

Like I said it works for me without changing anything in my browser. Don’t know about safari but if it’s not working in chrome for you by default your config is not quite right. You are not typing “localhost” in your browser are you?

~Cheers

1 Like

Ahh… yes. I was using localhost:8888 in my browser which is what MAMP opens up when starting. After going to 10.0.0.11:8888 instead everything works without having to disable anything.

Thanks!

1 Like

Thanks for coming back and confirming :slight_smile:

~Cheers

1 Like

Thanks for all the help

1 Like

I had the same problem on my desktop localhost server.
What was strange about it was that I copied the files from an isolated development directory structure into the project directory with the same directory structure.
The page loaded and executed correctly in the development directory but the dreaded “Preflight response is not successful” whenever the same script was executed in the project directory. Changing the php filename on the file and in the code had no effect.
However changing the php file’s name and copying the contents followed by creating a new file with the original filename and pasting the original file’s contents into it and the problem disappeared.
I have had to use this trick several times but this is the first time i got the “Preflight response is not successful” error message.
This was on an iMac with Safari.

Thank you very much for sharing your findings, I have found that since HA v0.110.x I have had to check “Disable Cross-Origin restriction” for things to work, with the base_url from older versions this was not needed.

I’ve tried changing the cors_allowed_origins in the HA config but no luck so far.

I am writing a HA compatible web application. And every time I bounced on this topic when I was looking for a solution with CORS issues.

Following errors I saw: SecurityError: Blocked a frame with origin “https://osgdb.nl” from accessing a cross-origin frame. Protocols, domains, and ports must match.

And: Failed to load resource: Preflight response is not successful. Status code: 403

My application is running in an iFrame of Home Assistant. And my application must do a Rest API call to HA.

In /config/configuration.yaml I added:

http:
  cors_allowed_origins:
    - http://localhost
    - https://localhost
    - http://127.0.0.1
    - https://127.0.01
    - https://osgdb.nl
    - http://ha.oplan.nl:8123

But whatever I tried, nothing really worked.
The web application is seated somewhere on the internet.
Home Assistant Server is seated somewhere on my local network.

The Rest Api call is done from a javascript request from the webpage in the iFrame.
So the way of thinking of making the list of cors_allowed_origins was wrong.
I need to fill in de IP-address of the device the request is coming from. So in my case ip-address 192.168.3.23.
But I do not have 1 device in my network. I have a lot of devices in my network.
My subnet is 192.168.0.0/21 (1514 possible addresses). I am lazy and don’t want to add 1514 addresses in the configuration.yaml .The solution is:

http:
  cors_allowed_origins:
    - https://192.168.*
1 Like

Thank u very much.
Two days try to find, how by jquery post a state.