Self-hosted webpage. How to differentiate GET to load the page/ GET with ajax

hi all,

I started with the very cool snackbot code and have created a page that almost works.

The snackbot agent loads the web page by recognizing an empty body and returning the html for the page like this:

//from electric imp snackbot code
http.onrequest(function(request,res){ if (request.body == "") { res.send(200, html); }else{ if(request.body == "small"){ server.log("Agent: Dispensing Small"); device.send("dispense", 0.4); }else if(request.body == "medium"){ server.log("Agent: Dispensing Medium"); device.send("dispense", 0.8); }else if(request.body == "large"){ server.log("Agent: Dispensing Large"); device.send("dispense", 1.0); }else{ server.log("Unrecognized Body: "+request.body); } res.send(200, ""); } });

When the body is empty it loads a page and otherwise it responds to buttons on the web page that post values and those are sending a body of “small”, “medium” for example.

so far so good.

i added AJAX code like this (taken from controlCloud’s excellent April code example)

function poll(){ var currentval = document.getElementById('com').value; $.ajax({ type: "get", url: "https://agent.electricimp.com/y........../", dataType: "json", success: function(agentMsg) { $("#hd").text(agentMsg.vdd+" deg C"); $("#rssi").val(agentMsg.rssi+" dBm"); $("#temp").val(agentMsg.vdd+" deg C"); $("#com").val(currentval + agentMsg.Serial); }, error: function(err) { console.log("err"+ err.status) } }); }

This request also has body=="" and so the agent is not easily able to tell the difference between the two requests.

had I changed nothing, the http.onrequest function would try to return the entire web page in response to the GET.

so…

I analyzed the two different requests and found when the web page loads, the request has these unique elements:

[Agent] index=x-requested-with value=XMLHttpRequest
[Agent] index=referer value=https://agent.electricimp.com/y…
[Agent] index=accept value=application/json, text/javascript, /; q=0.01

and the AJAX request has these unique elements

[Agent] index=accept value=text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
[Agent] index=cache-control value=max-age=0

with all the other elements being the same.

Being a complete hack, I first took the value of the “accept” property and noticed one starts with ‘a’ and the other starts with ‘t’. I used that to check the request and got my code to work - no trouble so far.

I’m sure that is a bad long-term solution and so I am looking for a good and permanent solution to discern the difference between a GET from ajax and a GET when the browser loads the web page with an http request

I have found that if I add the value “MYUNIQUEPATH” to the agent url as shown below everything still seems to function

$.ajax({ type: "get", url: "https://agent.electricimp.com/y.........../MYUNIQUEPATH", dataType: "json",

and the http request has “/MYUNIQUEPATH” returns as the path property. This would be a unique element of that GET request.

trouble is that to me it seems incorrect to add some random path to the end of that url.

anyone have an opinion about this? Sorry for the long post but I am trying to be really clear and also add what I have learned.

Here are a number of strategies to use with some pros and cons:

  1. Use a query parameter (add a ?page=somePage to the end of the URL, and act based on that). This is a really simple way of getting things up and running, so that’s really great. The downside is that it’s kind of a hack. Web developers will frown on your API if you set it up this way.

  2. Use different HTTP verbs/methods. HTTP has a bunch of standard verbs (GET/POST/PUT/DELETE/OPTIONS). You can view what method was called with request.method. Typically, you would do something like “GET” means you display the page, “POST” means you do something else. Once again, this is really easy but kind of a hack. Verbs aren’t really meant to be used this way (but nothing is stopping you).

  3. Build unique paths. This is what you’ve suggested, and is what would be viewed as best practice in terms of “web development.” When I’m building imp-enabled devices with an agent served webpage + an API, I tend display the webpage is the browse to the root agent URL, and do API/ajax type things if the browse to /api/somefunction.

http.onrequest(function(req, resp) { // make it lower case so it's easier to deal with local path = req.path.tolower(); try { if (path == "" || path == "/") { resp.send(200, index()); } else if (path == "/api/poll" || path == "/api/poll/") { resp.send(200, poll()); } else { // default response resp.send(404, unknownPage()); } } catch (ex) { resp.send(500, internalSeverError(ex)); } }

Each of the functions in the resp.send() would return some HTML string of one kind or another. This keeps you code nice and clean, and the flow is really obvious. If you wanted, you could easily add checking methods as well. Using methods and path, you should be able to build fully RESTful APIs if you want to :slight_smile:

A better way of parsing the path is likely to split it on “/” and look at the resulting array:

local pathParts = req.path.tolower().split("/"); local numParts = pathParts.len(); if (numParts == 0) { // index resp.send(200, index()); } else if (numParts > 1 && pathParts[0] == "api") { if (pathParts[1] == "poll") { resp.send(200, poll()); } else if (pathParts[1] == "somethingElse" && req.method=="POST") { doAThing(); resp.send(200, SomeOtherResponse); } } // ...

many thanks beardedinventor,

This method of appending a path to the url is working well. One small change I had to make is to change the first line to this:
local pathParts = split(request.path.tolower(),"/");

otherwise this error is returned;

the index ‘split’ does not exist

Ah sorry, that was coded in the forum editor :slight_smile:

Glad it helped!