diff --git a/lib/volumen/api_routes.rb b/lib/volumen/api_routes.rb index af412a2..c531304 100644 --- a/lib/volumen/api_routes.rb +++ b/lib/volumen/api_routes.rb @@ -41,6 +41,10 @@ module Volumen feed_xml end + app.get "/api/volumen/feed.json" do + json(feed_json) + end + app.get "/api/volumen/sitemap.xml" do content_type "application/xml" sitemap_xml diff --git a/lib/volumen/server.rb b/lib/volumen/server.rb index 47f5487..d2667c8 100644 --- a/lib/volumen/server.rb +++ b/lib/volumen/server.rb @@ -168,6 +168,41 @@ module Volumen end end + def feed_json + site = config.site + feed_url = "#{base_url}/api/volumen/feed.json" + { + "version" => "https://jsonfeed.org/version/1.1", + "title" => site["title"], + "home_page_url" => base_url, + "feed_url" => feed_url, + "description" => site["description"], + "language" => site["language"], + "items" => published_posts.first(20).map { |post| json_feed_item(post) } + } + end + + def json_feed_item(post) + link = "#{base_url}/#{post.slug}" + item = { + "id" => link, + "url" => link, + "title" => post.title, + "content_html" => post.html, + "summary" => post.excerpt, + "date_published" => iso_date(post.metadata["date"]), + "tags" => post.tags + } + item.reject { |_k, v| v.nil? || v == "" || v == [] } + end + + def iso_date(value) + case value + when Date then value.iso8601 + when Time then value.to_date.iso8601 + end + end + def sitemap_xml urls = published_posts.map do |post| url = " #{escape("#{base_url}/#{post.slug}")}" diff --git a/test/server_test.rb b/test/server_test.rb index c37d98a..af3d59d 100644 --- a/test/server_test.rb +++ b/test/server_test.rb @@ -141,4 +141,16 @@ class ServerTest < Minitest::Test slugs = JSON.parse(last_response.body)["posts"].map { |post| post["slug"] } refute_includes slugs, "later" end + + def test_json_feed_endpoint + get "/api/volumen/feed.json" + assert_predicate last_response, :ok? + data = JSON.parse(last_response.body) + assert_equal "https://jsonfeed.org/version/1.1", data["version"] + assert_equal "My Blog", data["title"] + assert_equal 1, data["items"].length + assert_equal "Hello", data["items"].first["title"] + assert_includes data["items"].first["content_html"], "world" + refute_includes data["items"].map { |i| i["title"] }, "Draft" + end end