Window.open() vs $.get()

Hi,

I am running a few tests for my Quote Machine Challenge App. Besides Twitter, I’d linke to share the quotes as well to Hubzilla.

Running window.open(hubzillaQueryLink) will open a new window and post fine according to the queryString.
Now I thought I might want to get the JSON that’s put in the newly opened window and extract the Hubzilla Site where the quote is actually posted, so you don’t see a JSON but the actual network you are posting to.

So I used the exact same string for the .get() method. Didn't work. Neither with .getJSON(). Sometimes I put https://cors-anywhere.herokuapp.com/ in front of the link as I suspected same-origin-policy to be the problem, but appearently it wasn’t…

I’m stuck.

In case it is of use, the API docu of Hubzilla is here:
https://hub.debenny.de/help/de/developer/api_zot

Update:
Just saw I forgot the codepen Link:

So, I’ve never heard of Hubzilla and don’t know exactly what’s involved with using their API, but one thing is clear: what you’re trying to do is not accomplished with a GET request. You need to make a POST request. $.get and $.getJSON won’t work, and window.open should never be used when making an API call. Here’s something I was playing around with but couldn’t get to work:

$.ajax({
    url: 'https://'+hub+'/api/z/1.0/item/update',
    type: 'POST',
    crossDomain: true,
    data: quote,
    headers: {
      'Authorization': `${username}:${password}`
    }
  })
  .then(console.log)
  .catch(console.error)

I’m not sure if it really needs the auth header. The API docs should have more info on how to authorize each action. Chances are that you won’t be able to get this to work in Codepen. Usually, when an API requires an authenticated user to authorize an action, it’s required that you make that transaction on a server or compiled client (like a mobile app) where the code isn’t easily readable. You’ll likely be getting warnings and errors regarding a missing Access-Control-Allow-Origin header. This is because Hubzilla doesn’t want you doing this sort of stuff in a web app.

1 Like

Thank you for your answer. Somewhere I read that if there’s a query String, it will be a GET method, as POST couldn’t be set up as a query String, so I figured it must be GET…

About Hubzilla: https://github.com/redmatrix/hubzilla

Authorization in the query string works like:

https://username:password@hub.debenny.de/api/z/1.0/item/update?&body=foo

This link with the actual username and password in the browser address field does succeed.

In case it is of any use: These are the response headers when the action is successful:

           X-Firefox-Spdy	h2
            cache-control	no-store, no-cache, must-revalidate
         content-encoding	gzip
             content-type	application/json
                     date	Thu, 18 Jan 2018 07:59:35 GMT
                  expires	Thu, 19 Nov 1981 08:52:00 GMT
                   pragma	no-cache
          referrer-policy	strict-origin-when-cross-origin
                   server	nginx
strict-transport-security	max-age=172800
                     vary	Accept-Encoding
   x-content-type-options	nosniff
          x-frame-options	SAMEORIGIN
         x-xss-protection	1; mode=block

Just found out another way, with the rpost property I can open a text dialogue on the server with preset text and title. I’ll use this with window.open and all should be fine.

You’re right that query params mean GET requests, but the documentation actually doesn’t tell you to have the body as a query parameter. Granted, I feel the documentation is sparse and I’d like to see some language specific examples, but when it says “body” it means to have a body field in the POST request’s body. Super confusing. The only example they give is using cURL: curl -u mychannel:mypassword https://xyz.macgirvin.com/api/z/1.0/item/update -d body="hello world". The -d option puts the following body="hello" in the POST’s body. So, my attempt was actually missing a crucial element:

$.ajax({
    url: 'https://'+hub+'/api/z/1.0/item/update',
    type: 'POST',
    crossDomain: true,
    data: {body: quote}, // << quote needs to be in a field 'body'
    headers: {
      'Authorization': `${username}:${password}`
    }
  })
  .then(console.log)
  .catch(console.error)

Does it actually display the data you sent, or do you just get a response? It’s entirely possible to check for query parameters in a POST request, but if it doesn’t and you send an empty body, it should still give you a valid response even though it didn’t change anything on the server. If query params work, then great, but this is something to watch out for.

window.open is not an API to use for AJAX. If your user’s browser is set up to block pop-ups, your app will break. You may have issues with other security features. Any of these problems will be invisible to the user since you can’t handle errors. This isn’t a good idea.

You can easily use $.ajax, the browser native fetch, Axios, or any number of other good interfaces for this sort of task. I’m not saying this just to make you feel bad or give you more work. If you want a solid portfolio, you cannot be using hacks like this. If a potential employer takes a look at your work and sees this, it’ll probably cost you a job interview. Learn to do it the right way and you’ll be much better prepared for life in web development.

1 Like

All I can say is that it works as a query link in the browser. I open a new tab, I enter

https://hub.debenny.de/api/z/1.0/item/update?body=foo

Then I get the following JSON printed in the new broser tab:


{
  "success": true,
  "item_id": "12260",
  "item": {
    "id": "12260",
    "mid": "2774cf2e4e9e0a082370ea06a1c18d828adb185054eb2de279eca49727398482@hub.debenny.de",
    "aid": "1",
    "uid": "3",
    "parent": "12260",
    "parent_mid": "2774cf2e4e9e0a082370ea06a1c18d828adb185054eb2de279eca49727398482@hub.debenny.de",
    "thr_parent": "2774cf2e4e9e0a082370ea06a1c18d828adb185054eb2de279eca49727398482@hub.debenny.de",
    "created": "2018-01-18 18:56:24",
    "edited": "2018-01-18 18:56:24",
    "expires": "0001-01-01 00:00:00",
    "commented": "2018-01-18 18:56:24",
    "received": "2018-01-18 18:56:25",
    "changed": "2018-01-18 18:56:25",
    "comments_closed": "0001-01-01 00:00:00",
    "owner_xchan": "7GUJg9yFkKc8bU0XkfvNz34g6lrIvQi2wTPIxwQ1YUc2fO6vM482NmhqUqY7Z47FpvNHg7psHK80m1zTzRkt5Q",
    "author_xchan": "7GUJg9yFkKc8bU0XkfvNz34g6lrIvQi2wTPIxwQ1YUc2fO6vM482NmhqUqY7Z47FpvNHg7psHK80m1zTzRkt5Q",
    "source_xchan": "",
    "mimetype": "text/bbcode",
    "title": "",
    "body": "foo",
    "html": "",
    "app": "",
    "lang": "",
    "revision": "0",
    "verb": "http://activitystrea.ms/schema/1.0/post",
    "obj_type": "http://activitystrea.ms/schema/1.0/note",
    "obj": "",
    "tgt_type": "",
    "target": "",
    "layout_mid": "",
    "postopts": "",
    "route": "",
    "llink": "https://hub.debenny.de/display/2774cf2e4e9e0a082370ea06a1c18d828adb185054eb2de279eca49727398482@hub.debenny.de",
    "plink": "https://hub.debenny.de/channel/tce/?f=&mid=2774cf2e4e9e0a082370ea06a1c18d828adb185054eb2de279eca49727398482@hub.debenny.de",
    "resource_id": "",
    "resource_type": "",
    "attach": "",
    "sig": "j9Ley1KkHOLXFHldbsY204GPFTXCNelQ5nTKSGHwLlB1KIHYjXc3s5Um6mPYkbGMWWjakX3MyX7OIUkEnWPx7cnhqk4hOBTihPNzNFGqqHfITSfhacs-K8cfLNiiT91imDTmjidlktw5Sozk9SShooT7aiQ6gn8DxueR8VF0v2B6eWhm6KkzDn2bALYkGKMf-mQepR3xSrNMSnhLEefgUfew8SmNJtuo2DylkjQgFoulV1QOTajVhPkBq03HaqzaYzbkUfJtTd11wphffzYEXYXxYGPBGn-0cDRcXpZp4pRxQwe1EyF0SCBhVtk99OYi9sRntXXOIJ-8im5DeVNO1EXhOQVtU_-xeui4YBsOryeg-KmrRNSVyPnjUR-xB1mN3j6-YJ7cTOMEVn2npHbKD78NDbEZVaNvny6xf_a9LW48T9bg08unp_kKAl4T0npn26rRhiWr8D3Hck5zbtibnqDGNgIBQQVz0a0CPCiyfsUTFbaqfVmYgoQNXNSzycxOnHRub6jSNzaP-DwT84xQALxtsOLr5D65ufPyzmB5V5sTk8_C7HcYDplftbmBxgTN1nxOzp1ebVCSolr--9JhNudm7hORXSYlj5kXu_CVNZVgGeR4kX58Ja5uNK87jPcHsvOedm97XdcYGEkVvXgRyGn5y6IZnXETB2pNlxWPv4w",
    "location": "",
    "coord": "",
    "public_policy": "",
    "comment_policy": "public",
    "allow_cid": "",
    "allow_gid": "",
    "deny_cid": "",
    "deny_gid": "",
    "item_restrict": "0",
    "item_flags": "0",
    "item_private": "0",
    "item_origin": "1",
    "item_unseen": "0",
    "item_starred": "0",
    "item_uplink": "0",
    "item_consensus": "0",
    "item_wall": "1",
    "item_thread_top": "1",
    "item_notshown": "0",
    "item_nsfw": "0",
    "item_relay": "0",
    "item_mentionsme": "0",
    "item_nocomment": "0",
    "item_obscured": "0",
    "item_verified": "1",
    "item_retained": "0",
    "item_rss": "0",
    "item_deleted": "0",
    "item_type": "0",
    "item_hidden": "0",
    "item_unpublished": "0",
    "item_delayed": "0",
    "item_pending_remove": "0",
    "item_blocked": "0"
  }
}

And if I open my stream in Hubzilla, I get the message like so:

Okay,so I shall stick with POST…

I got a message from the main developer of Hubzilla saying I’d need to add application/x-www-form-urlencode, so I did:

$.ajax({
    url: 'https://'+hub+'/api/z/1.0/item/update',
    type: 'POST',
    crossDomain: true,
    data: quote,
    headers: {
      'Authorization': `${username}:${password}`,
      'Content-Type':'application/x-www-form-urlencode'
    }
  })
  .then(console.log)
  .catch(console.error)

Still get an error.

window.open is not an API to use for AJAX. If your user’s browser is set up to block pop-ups, your app will break.

This is something I didn’t consider. Thank you. As I intended to get all interaction in an external window or kind of overlay, I thought this would be ideal,especially since I found out the link to an input field for network posts. I could set the text of the textfield and let the user edit before it is sent to the network…
But what you write is a deal breaker. I think I might look into Bootstrip Modals or something similar instead of relying on pop-ups…
I never heard of fetch or Axios. Thank you for the links.

I keep fighting with $.ajax() sending a POST request to the server and it seems, the problem lies in me not being able to authenticate due to same-origin-policy.

I cannot rely on all Hubzilla servers setting proper cors headers, I myself only have my Hubzilla instance running on a webspace without having control over the web server, so I cannot rely on that.

The only chance there is would be to use Code that runs on the server and voila, that’s exactly what I can access through window.open(), be it through a pop-up, a new tab or an iframe, maybe within a bootstrap modal, if that is possible (I will find out).

There is just no way in this setting to do otherwise - as far as I can see.

So I shall use window.open(). As it will be in reaction to a button pushed, popup-blockers should not hinder it.

I guess I learned quite a bit reading through all kinds of texts on all that, and I am happy about it. It broadened my view, and I will definately keep all that in mind when getting to the point where I write server code.

Thank you for your help.