Can I get a Discourse/JSON example?

javascript

(Scott Trager) #1

Is there an example someone can show me of some JSON which works with the /top/monthly.json page? - I’ve tried like 15 different scripts and every single one does not seem to function with this as the json path - since there is no way to actually run a script anywhere, I’m running it from a local “test.html” file at the moment until I have something that works so I can find a way to actually execute it on the server.

Thanks.


(Mittineague) #2

Are you saying you don’t get JSON if you go to
https://meta.discourse.org/top/monthly.json
or that you don’t know what to do with it?


(Scott Trager) #3

I get the data when I go to there, but every JSON snippet I throw at it returns nothing. I have experience working with XML and RSS but there doesn’t seem to be an RSS for that page so I think I’m stuck using JSON. I literally googled “JSON Example” and tried every Javascript example for like 10 pages of results, and nothing… I just need a simple example so I can figure out what I’m doing wrong.


(Mittineague) #4

So the question isn’t specific to Discourse, but how to consume the JSON.

What I do for a Firefox extension is use XHR (AJAX) to get the returned JSON, get the values from the response object, and add them to the display using createElement and appendChild.

It takes a little bit of studying to determine the response object structure, but once you know the nesting and key names it works well.

Have you done much with AJAX?

Does something like this jQuery example look understandable?

function getUsersUsernamesJson(stripped_url) {
	$.getJSON(stripped_url + '.json', function (result) {
	var stringified_result = "";
		for (var prop in result) {
			if (prop == "user") {
				var user = result[prop];
				for (var prop in user) {
					if (prop == "username") {
						stringified_result += prop + " = " + user[prop] + "\r\n";
					}
				}
			}
		}
//		alert(stringified_result.toLowerCase());
	});
}

(Scott Trager) #5

Sure does. I have worked with AJAX some, but i’m not nearly as profiecent with it as I’d like…

My issue isn’t with JSON itself, but rather with the JSON file that Discourse has specifically. I was able to read data from numerous other JSON sources, but as soon as I stuck in a discourse link it won’t pull anything at all. Tried both using meta’s and our own pages.

Here is an example I took from a JSON tutorial:

    <html>
<head>

<script style="text/javascript">
function showrecentposts(json) {
  // start a loop
  // in this loop we get the entry from the feed and parse it
  for (var i = 0; i < numposts; i++) {
    // get entry i from feed
    var entry = json.feed.entry[i];
    // get the posttitle
    var posttitle = entry.title.$t;
    // get the post url
    // check all links for the link with rel = alternate
    var posturl;
    if (i == json.feed.entry.length) break;
    for (var k = 0; k < entry.link.length; k++) {
      if (entry.link[k].rel == 'alternate') {
        posturl = entry.link[k].href;
        break;
      }
    }
    // get the postdate, take only the first 10 characters
    var postdate = entry.published.$t.substring(0,10);
    // get the post author
    var postauthor = entry.author[0].name.$t;
    // get the postcontent
    // if the Blogger-feed is set to FULL, then the content is in the content-field
    // if the Blogger-feed is set to SHORT, then the content is in the summary-field
    if ("content" in entry) {
      var postcontent = entry.content.$t;}
    else
    if ("summary" in entry) {
      var postcontent = entry.summary.$t;}
    else var postcontent = "";
    // strip off all html-tags
    var re = /<\S[^>]*>/g; 
    postcontent = postcontent.replace(re, "");
    // reduce postcontent to numchar characters
    if (postcontent.length > numchars) postcontent = postcontent.substring(0,numchars);
    // display the results
    document.write('<br>');
    document.write('Entry #' + i + '<br>');
    document.write('Post title    : '+ posttitle + '<br>');
    document.write('Post url      : '+ posturl + '<br>');
    document.write('Post author   : '+ postauthor + '<br>');
    document.write('Postdate      : '+ postdate + '<br>');
    document.write('Postcontent   : '+ postcontent + '<br>');
    document.write('<br>');
  }
}
</script>
</head>
<body>
RECENT POSTS

<script style="text/javascript">
var numposts=5;
var numchars=100;
</script>
<script src="http://yourblog.blogspot.com/feeds/posts/default?alt=json-in-script&callback=showrecentposts"></script>
</body>
</html>

This works perfectly. But if I do something similar (updating the code to use id etc. ) I get absolutely nothing…

Here is a quickly re-modified version- I might have missed something but this is pretty close to what I tried to do:

<html>
<head>

<script style="text/javascript">
function showrecentposts(json) {
  // start a loop
  // in this loop we get the entry from the feed and parse it
  for (var i = 0; i < numposts; i++) {
    // get entry i from feed
    var entry = json.feed.topic[i];
    // get the posttitle
    var posttitle = entry.title.$t;
    // get the post url
    // check all links for the link with rel = alternate
    
    // strip off all html-tags
    var re = /<\S[^>]*>/g; 
    postcontent = postcontent.replace(re, "");
    // reduce postcontent to numchar characters
    if (postcontent.length > numchars) postcontent = postcontent.substring(0,numchars);
    // display the results
    document.write('<br>');
    document.write('Entry #' + i + '<br>');
    document.write('Post title    : '+ posttitle + '<br>');
    document.write('<br>');
  }
}
</script>
</head>
<body>
RECENT POSTS

<script style="text/javascript">
var numposts=5;
var numchars=100;
</script>
<script src="https://meta.discourse.org/top/monthly.json"></script>
</body>
</html>

(Mittineague) #6

I’m guessing you’re not so much interested in “users” eg.

["users"]=>
  array(43) {
    [0]=>
    object(stdClass)#2 (4) {
      ["id"]=>
      int(214880)
      ["username"]=>
      string(5) "zackw"
      ["uploaded_avatar_id"]=>
      int(20413)
      ["avatar_template"]=>
      string(59) "/user_avatar/community.sitepoint.com/zackw/{size}/20413.png"
    }

but rather “topic_list” eg.

["topic_list"]=>
  object(stdClass)#45 (6) {
    ["can_create_topic"]=>
    bool(false)
    ["draft"]=>
    NULL
    ["draft_key"]=>
    string(9) "new_topic"
    ["draft_sequence"]=>
    NULL
    ["for_period"]=>
    string(5) "daily"
    ["topics"]=>
    array(32) {
      [0]=>
      object(stdClass)#46 (25) {
        ["id"]=>
        int(110117)
        ["title"]=>
        string(63) "Anybody else annoying at the trend of web apps as desktop apps?"
        ["fancy_title"]=>
        string(63) "Anybody else annoying at the trend of web apps as desktop apps?"
        ["slug"]=>
        string(62) "anybody-else-annoying-at-the-trend-of-web-apps-as-desktop-apps"
        ["posts_count"]=>
        int(6)
        ["reply_count"]=>
        int(4)
        ["highest_post_number"]=>
        int(6)
        ["image_url"]=>
        NULL
        ["created_at"]=>
        string(24) "2015-01-15T16:06:07.928Z"
        ["last_posted_at"]=>
        string(24) "2015-01-16T00:25:55.300Z"
        ["bumped"]=>
        bool(true)
        ["bumped_at"]=>
        string(24) "2015-01-16T00:32:00.359Z"
        ["unseen"]=>
        bool(false)
        ["pinned"]=>
        bool(false)
        ["unpinned"]=>
        NULL
        ["visible"]=>
        bool(true)
        ["closed"]=>
        bool(false)
        ["archived"]=>
        bool(false)
        ["views"]=>
        int(31)
        ["like_count"]=>
        int(5)
        ["has_summary"]=>
        bool(false)
        ["archetype"]=>
        string(7) "regular"
        ["last_poster_username"]=>
        string(7) "mawburn"
        ["category_id"]=>
        int(3)
        ["posters"]=>
        array(2) {
          [0]=>
          object(stdClass)#47 (3) {
            ["extras"]=>
            NULL
            ["description"]=>
            string(15) "Original Poster"
            ["user_id"]=>
            int(214880)
          }
          [1]=>
          object(stdClass)#48 (3) {
            ["extras"]=>
            string(6) "latest"
            ["description"]=>
            string(18) "Most Recent Poster"
            ["user_id"]=>
            int(209558)
          }
        }
      }

So if you wanted to list the top 5 topic titles the callback would be something like

var titles = [];
for (var i = 0; i < 5; i++) {
  titles[i] = json["topic_list"]["topics"][i]["title"];
}

(Scott Trager) #7

Well I got something different this time at least…

Gave the same “blank” screen, but this time in Element Viewer in Chrome it says:

ahhh.html:1 Refused to execute script from ‘https://meta.discourse.org/top/monthly.json’ because its MIME type (‘application/json’) is not executable, and strict MIME type checking is enabled.


(Mittineague) #8

I use Firefox, so I haven’t had this problem. It seems Chrome has trouble with the “nosniff”

HTTP/1.1 200 OK
Server: nginx
Date: Fri, 16 Jan 2015 03:20:49 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Vary: Accept-Encoding
Status: 200 OK
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Request-Id: 44b2bde5-0aed-40b8-9c4a-a950efa28ca2
X-Runtime: 0.474395
X-UA-Compatible: IE=edge
Content-Encoding: gzip

(Kane York) #9

Why are you putting the json in a <script> tag?

The nosniff is important so that it never gets downloaded as a file, which opens users up to content reflection attacks @Mittineague.


(Scott Trager) #10

Because that is what the tutorial did…


(Kane York) #11

Why not request it with $.ajax and ACAO headers?


(Scott Trager) #12

Because I don’t know how to (I have a feeling this MIME issue might have been happening in a number of instances I just didn’t notice it and assumed my syntax was wrong) … hence the original request of, ‘can anyone provide a good example’ :smiling_imp: (Mittneague provided some good feedback i’m going to try in Firefox in the morning)


(Kane York) #13

I did the following:

  1. Opened a new tab to example.com

  2. Ran my “add jQuery” bookmark

  3. Typed the following:

    jQuery.ajax("https://meta.discourse.org/latest.json")
    

    Which resulted in:

     XMLHttpRequest cannot load https://meta.discourse.org/latest.json. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://example.com' is therefore not allowed access.
    

Now, if you add Access-Control-Allow-Origin: www.mainsite.com to the responses in Pound or Varnish, that error will go away, and you’ll get this: (if you want to follow along, run these on Meta.)

jQuery.ajax("https://meta.discourse.org/latest.json").done(function(result) { console.log(result); })

> Object {readyState: 1, getResponseHeader: function, getAllResponseHeaders: function, setRequestHeader: function, overrideMimeType: function…}
> Object {users: Array[49], topic_list: Object}

Let’s look at result.topic_list.

Object {can_create_topic: true, more_topics_url: "/latest.json?no_definitions=true&page=1", draft: null, draft_key: "new_topic", draft_sequence: 152…}can_create_topic: truedraft: nulldraft_key: "new_topic"draft_sequence: 152more_topics_url: "/latest.json?no_definitions=true&page=1"per_page: 30topics: Array[30]__proto__: Object

You can keep going like that until you have the data you need.


(Scott Trager) #14

That… almost looks simple… if that works you deserve a medal…

Now, if you add Access-Control-Allow-Origin: www.mainsite.com to the responses in Pound or Varnish

Explain that bit and I think I’ve got the rest… :grin:


(Kane York) #15

If your JS is on osmc.tv, then you want your proxy to AddHeader Access-Control-Allow-Origin: osmc.tv to the responses from the forum. Important: Make sure it does this for OPTIONS requests, too.


(Scott Trager) #16

huh?

I’m running this on a .html file on my desktop (for testing) at the moment, or in the old sidebar plugin (similar behavior there) directly on our discourse on a Digital Ocean droplet which seems to be the only place I can actually stick html or code without building a custom plugin which so far I can’t seem to find anything on how to do. What responses? Options requests? Where do I type the Addheader line?


(Kane York) #17

In your proxy configuration for discourse.osmc.tv.

[quote=“strager, post:16, topic:24067”]
I’m running this on a .html file on my desktop (for testing) at the moment
[/quote]Ah, that’ll be a problem for making requests to the web. As in, you can’t.

Oh, I was thinking you wanted to add something to your main site, which is why I was talking about ACAO.


(Scott Trager) #18

OK almost there… thanks for bearing with me, for some reason I’m just not explaining myself very well tonight :frowning: – Where is the proxy configuration on a Digital Ocean Droplet (since that rules out my local option :disappointed_relieved:)

Ah, that’ll be a problem for making requests to the web. As in, you can’t.

Really? Isn’t that tutorial code I quoted above making a request to the web? That worked locally…

Yep - strange… guess kinda irrelevant however :slight_smile:

<script src="http://yourblog.blogspot.com/feeds/posts/default?alt=json-in-script&callback=showrecentposts"></script>

(Kane York) #19

OOPS I CONFUSED YOU WITH SOMEONE ELSE

In my defense, you both have a pink S for an avatar. I’ve been trying to give you advice specific to the other person.


(Scott Trager) #20

:laughing: - no problem. Any chance I can get some advice specific to this person?