1

I'm trying to fetch external JSON data into Jekyll and things are not working out.

I found this code (link to a gist), that is a fork of another gist... this just adds the external method ("from url").

I tried to morph that into my own tag plugin (or what ever they are called), in order to simplify it and possibly resolve some issues:

_plugins/externaljson.rb

require 'json'
require 'net/http'

module ExternalJSON
  class ExternalJSON_tag < Liquid::Tag

    def initialize(tag_name, text, tokens)
      super
      @text = text
    end

    def render(context)

        if /(.+) from (.+)/.match(@text)
        url = context[$2].strip
            uri = URI( url )
            response = Net::HTTP.get( uri )
            data = JSON.parse( response )
            context[$1] = JSON data
            return ''
        end

    end
  end
end

Liquid::Template.register_tag('externalJSON', ExternalJSON::ExternalJSON_tag)

...but I didn't really solve all my issues or learn much of anything from that. The only thing I think I learned is that the problem is likely somewhere between parsing the file in ruby and jekyll reading it.

I ran this test using the tag plugin code above(↑):

---
layout: default
---

<!-- Using the code I modified -->
<!-- This capture exists to combine a string and a variable, but it's just a static url for the purposes of this example -->
{% capture myUrl %}
    https://api.guildwars2.com/v2/recipes/2889
{% endcapture %}

{% externalJSON jsonData from myUrl %}
{% for data in jsonData %}
    {{ data}}
{% endfor %}

<!-- Jekyll's native way of handling local data files -->
<!-- I just saved that json data from the url above(↑) locally for this one -->
{% for data in site.data.example %}
    {{ data }}
{% endfor %}

This test made me realize that both methods output the data slightly differently.

My external attempt:

{"type":"Meal","output_item_id":12210,"output_item_count":2,"min_rating":0,"time_to_craft_ms":1000,"disciplines":["Chef"],"flags":[],"ingredients":[{"item_id":24359,"count":1},{"item_id":12132,"count":1}],"id":2889,"chat_link":"[&CUkLAAA=]"} 

Jekyll's native method (for local files)

{"type"=>"Meal", "output_item_id"=>12210, "output_item_count"=>2, "min_rating"=>0, "time_to_craft_ms"=>1000, "disciplines"=>["Chef"], "flags"=>[], "ingredients"=>[{"item_id"=>24359, "count"=>1}, {"item_id"=>12132, "count"=>1}], "id"=>2889, "chat_link"=>"[&CUkLAAA=]"}

And if I try to do for example {{ data.type }}, my external attempt returns nothing and the Jekyll method returns the value just like it should. I just can't figure out how to change the formatting or what ever the missing piece is there.

What am I doing wrong?

Joonas
  • 7,227
  • 9
  • 40
  • 65
  • That `return ''` looks suspicious – ashmaroli Aug 17 '17 at 14:04
  • @ashmaroli I just copied it over from the original gist. In it, outside the if statement there is a another return that is a string telling you about an error. In my situation I probably could have taken it off, but it didn't seem necessary. – Joonas Aug 18 '17 at 02:04
  • I can't see the "other `return`" in the code you provided. And I can't see how `@text` is being used either – ashmaroli Aug 18 '17 at 03:54
  • @ashmaroli, [this is the other return](https://gist.github.com/geekles/6081967#file-jsonball-rb-L76). I don't know what the purpose of `@text` is either, but it was in the original code and also in the [Jekyll example for Tags](https://jekyllrb.com/docs/plugins/#tags) so I didn't see a reason to get rid of that. – Joonas Aug 18 '17 at 04:07
  • @text is the argument you give to the tag – ashmaroli Aug 18 '17 at 04:20
  • @ashmaroli, that makes sense. – Joonas Aug 18 '17 at 04:44
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/152224/discussion-between-ashmaroli-and-joonas). – ashmaroli Aug 18 '17 at 08:22

1 Answers1

2

replace your render(context) with following:

def render(context)
  if /(.+) from url (.+)/.match(@text)
    resp = Net::HTTP.get_response(URI($2.strip))
    data = resp.body
    context[$1] = JSON data
    nil
  else
    # syntax error
    raise ArgumentError, 'ERROR:bad_syntax'
  end
end

Then call the data like so:

{% externalJSON data from url http://foo.json %}

This will provide you with a data object that can be called to render individual keys.

If the data is an array, loop through the elements and call the desired key

{% for entry in data %}
  {{ entry.type }}
{% endfor %}

If the data is an object (hash), call the key directly.

{{ data.type }}
ashmaroli
  • 5,209
  • 2
  • 14
  • 25