RapidAPI предоставляет множество новостных API. От новостей технологий до статей о кино — вы, скорее всего, найдете здесь то, что вам нужно для вашего приложения. В этой статье мы сосредоточимся на Hacker News API. Это API для известного веб-сайта Hacker News, на котором публикуются, голосуются и комментируются статьи о технологиях и других типах статей. Мы создадим простой клон веб-сайта, используя Ruby on Rails и API. Это должно дать вам краткое представление о том, как использовать предоставленные различные API, а также как интегрировать их в приложение Ruby on Rails.

По теме: Как преобразовать существующее приложение Rails в API

API хакерских новостей

Hacker News API довольно прост и умен. Почти все на сайте считается Item. Это означает, что и статьи, и комментарии используют одну и ту же конечную точку. Более того, у Item есть потомки или kids. Так, например, представленная статья будет иметь комментарии относительно своих потомков, и каждый комментарий будет иметь ответы на этот комментарий как его потомки. Давайте поиграем с ним, чтобы мы могли лучше понять, как это работает. Для этого перейдите на страницу Hacker News API на RapidAPI. Обратите внимание на список конечных точек в левом нижнем углу:

Мы будем использовать конечные точки «Главные новости» и «Элементы». Конечная точка «Пользователи» — это то, что мы оставим вам для изучения в конце этого руководства. Выберите конечную точку Top Stories, а затем нажмите кнопку «Проверить конечную точку» справа. Через несколько секунд вы должны увидеть список чисел в правом нижнем углу страницы:

Это идентификаторы предметов. Конечная точка «Главные новости» возвращает только идентификаторы главных новостей, а не возвращает их напрямую. Это оставляет за клиентом ответственность за независимую загрузку каждого элемента. Теперь выберите идентификатор первого элемента из списка, выберите конечную точку «Элементы» в левой части страницы и вставьте идентификатор элемента в поле параметра id в середине страницы, как показано на снимке экрана ниже. Затем нажмите кнопку «Проверить конечную точку».

Это должно загрузить и вернуть подробный вид элемента. Обратите внимание, что у нас есть название, время, оценка, имя пользователя отправителя, а также kids. Это потомки этого элемента, в данном случае комментарии.

Чтобы получить подробную информацию о каждом комментарии, вы можете просто повторить процесс. Скопируйте идентификатор комментария, вставьте его в поле параметра id, как и раньше, и нажмите кнопку «Проверить конечную точку». Вы должны получить детали комментария.

Hacker News API также доступен в GraphQL.

Как использовать News API с Ruby On Rails

Требования

Теперь, когда вы немного понимаете, как работает API, мы можем приступить к созданию нашего клона Hacker News. Для этого вам понадобится Ruby, установленный в вашей системе. Посетите официальную страницу установки, так как инструкции по установке зависят от платформы. После того, как вы закончите с этим, убедитесь, что у вас установлен Rails. Просто запустите gem install rails и дождитесь завершения команды. Если вы совсем не знакомы с Rails, возможно, попробуйте эту статью, которая даст вам краткое представление о том, как это работает.

Теперь мы можем создать новое приложение. Для этого выполните следующую команду на своем терминале:

rails new hackernews --skip-action-mailer --skip-action-mailbox --skip-action-text --skip-active-record --skip-active-storage

Обратите внимание, что мы не устанавливаем кучу модулей, так как они нам не нужны. Вы можете проверить, что делает каждый из них, погуглив их, но в целом это в основном вещи, связанные с электронной почтой и базой данных / хранилищем, которые этому проекту не понадобятся. Когда вы закончите, вы сможете переключиться на только что созданную папку hackernews и запустить rails s, чтобы запустить сервер. Как только эта команда будет запущена, вы можете использовать свой браузер, чтобы перейти на http://localhost:3000, где вас должно приветствовать следующее:

Вы успешно создали и запустили свое приложение Rails. Мы также добавим Bootstrap, чтобы упростить создание каркаса приложения. Откройте свой Gemfile и добавьте это внизу:

gem 'bootstrap', '~> 4.4.1'

Запустите bundle install и, как только это будет сделано, переименуйте app/assets/stylesheets/application.css в app/assets/stylesheets/application.scss. Удалите строки, начинающиеся с require, и добавьте эту строку внизу:

@import "bootstrap";

Нам также потребуется установить гем Excon. Снова откройте Gemfile и добавьте это:

gem 'excon'

И запустить bundle install.

Создайте наш API-клиент

Чтобы наши контроллеры могли взаимодействовать с API, мы создадим клиент, чтобы упростить его. Таким образом, мы избегаем дублирования кода повсюду. Создайте новую папку в папке lib с именем hackernews, затем создайте новый файл с именем client.rb. Вставьте это туда:

module Hackernews
  class Client
    def initialize
      @host = 'YOUR_HOST'
      @key = 'YOUR_API_KEY'
    end

    def item(id)
      get("item/#{id}")
    end

    def topstories
      get('topstories')
    end

    private

    def get(path)
      response = Excon.get(
        'https://' + @host + '/' + path + '.json?print=pretty',
        headers: {
          'x-rapidapi-host' => @host,
          'x-rapidapi-key' => @key,
        }
      )

      return false if response.status != 200

      JSON.parse(response.body)
    end
  end
end

Чтобы Rails автоматически подбирал этот файл, нам нужно добавить некоторый код конфигурации. Откройте config/application.rb и добавьте эти две строки в класс Application:

config.autoload_paths << Rails.root.join('lib') config.eager_load_paths << Rails.root.join('lib')

Кроме того, убедитесь, что вы инициализировали клиент в контроллере приложения, чтобы все контроллеры могли иметь к нему доступ. Убедитесь, что файл в app/controllers/application_controller.rb выглядит следующим образом:

class ApplicationController < ActionController::Base def client @client ||= Hackernews::Client.new end end

Создать домашнюю страницу

Наша домашняя страница будет очень похожа на настоящую домашнюю страницу Hacker News. Для этого нам нужно создать новый контроллер, добавить некоторый код в маршрутизатор и добавить несколько шаблонов. Давайте перейдем к делу. Начните с создания нового контроллера: app/controllers/stories_controller.rb. Добавьте это в файл:

class StoriesController < ApplicationController def top @stories = client.topstories(0, 10) end end

Вы заметите, что мы передаем два параметра в метод topstories. Это поможет нам с нумерацией страниц позже. Давайте изменим наш клиент, чтобы отразить это:

def topstories(start = 0, per_page = 10, expand = true) stories = get('topstories')[start...start + per_page] if expand stories.map! do |story| item(story) end end stories end

Новый метод принимает три параметра (с разумными значениями по умолчанию). Параметр start, чтобы указать нашему методу, с чего начать показ главных новостей, параметр per_page, чтобы рассчитать, сколько элементов на странице нужно показать, и параметр expand. Последнее очень важно, поскольку, как вы помните, конечная точка topstories возвращает только идентификаторы историй, а не сами истории. Наш новый метод сначала получит только те идентификаторы, которые соответствуют нужной нам странице (путем нарезки массива возвращаемых идентификаторов), а затем расширит каждую историю с помощью метода item.

<% @stories.each do |story| %>
  <div class="media mb-3">
    <div class="media-body">
      <h5 class="mt-0 mb-1">
        <a href="<%= story['url'] %>"><%= story['title'] %></a>
      </h5>
<%= story['score'] %> points
      by <%= story['by'] %>
      <%= time_ago_in_words(story['time']) %> ago
      | <%= story['descendants'] %> comments
    </div>
  </div>
<% end %>

Этот шаблон будет перебирать все истории на текущей странице и создавать строку с URL-адресом, заголовком, количеством комментариев, оценкой и автором. Кроме того, давайте немного изменим макет нашего приложения. Откройте файл app/views/layouts/application.html.erb и измените тело, чтобы оно выглядело примерно так:

<body>
  <div class="container">
    <h1><%= link_to 'Hacker News', root_path %></h1>
<%= yield %>
  </div>
</body>

Что подводит нас к заключительной части этого раздела. Нам нужно добавить маршрут к нашему маршрутизатору, чтобы Rails знал, какой контроллер использовать. Откройте config/routes.rb и добавьте этот маршрут:

root to: 'stories#top'

Теперь вы сможете перейти на http://localhost:3000 и увидеть список историй:

Добавить пагинацию

Чтобы добавить пагинацию, нам нужно немного изменить наш контроллер, а также добавить немного кода в наш шаблон. Сначала займемся контроллером. Измените содержимое метода top в StoriesController, чтобы оно выглядело примерно так:

def top
  @start = (params[:start] || 0).to_i
  @per_page = (params[:per_page] || 10).to_i
  @per_page = [@per_page, 20].min # max 20 per page
@stories = client.topstories(@start, @per_page)
end

Теперь давайте добавим в наш шаблон элементы управления разбиением на страницы. Добавьте это к шаблону top.html.erb:

<nav>
  <ul class="pagination justify-content-center">
    <li class="page-item <%= 'disabled' if @start == 0 %>">
      <%= link_to 'Previous', root_path(start: @start - @per_page), class: 'page-link' %>
    </li>
    <li class="page-item">
      <%= link_to 'Next', root_path(start: @start + @per_page), class: 'page-link' %>
    </li>
  </ul>
</nav>

Показать комментарии

Каждая история в Hacker News имеет комментарии. Помните, как мы раньше изучали API? Они встроены в качестве идентификаторов комментариев в каждую историю как kids. Поскольку они также являются предметами, нам не нужно менять нашего клиента. Мы просто создадим новый метод в нашем контроллере историй и будем использовать его для отображения комментариев. Но сначала, чтобы избежать дублирования кода, мы выделим рендеринг деталей истории в партиал. Создайте новый файл в app/views/stories с именем _story.html.erb. Здесь просто вставьте код, который мы использовали для отображения деталей истории:

<div class="media mb-3">
  <div class="media-body">
    <h5 class="mt-0 mb-1">
      <a href="<%= story['url'] %>"><%= story['title'] %></a>
    </h5>

    <%= story['score'] %> points
    by <%= story['by'] %>
    <%= time_ago_in_words(story['time']) %> ago
    | <%= story['descendants'] %> comments
  </div>
</div>

В файле top.html.erb измените код истории следующим образом:

<%= render partial: 'story', collection: @stories %>

Это зациклит массив @stories и отобразит частичный шаблон для каждого. Давай, попробуй. До сих пор сайт должен работать точно так же.

Теперь создайте новый метод в StoriesController:

def show @story = client.item(params[:id]) @comments = (@story['kids'] || []).map do |comment| client.item(comment) end end

Это получает детали истории, а затем получает детали комментариев (помните, мы получаем только идентификаторы комментариев для каждой истории). Обратите внимание, что мы делаем (@story['kids'] || []). Это связано с тем, что если в истории нет комментариев, атрибут kids не будет существовать, поэтому нам нужно по умолчанию использовать пустой массив, чтобы избежать ошибки. Теперь создайте новое представление в app/views/stories с именем show.html.erb и добавьте в него это:

<%= render partial: 'story', object: @story %> <%= render partial: 'comments/comment', collection: @comments %>
<div class="media mb-3"> <div class="media-body"> <span class="text-muted"> <%= comment['by'] %> <%= time_ago_in_words(comment['time']) %> ago | <%= comment.fetch('kids', []).count %> responses </span> <p><%= sanitize comment['text'] %></p> </div> </div> <hr>

Для этого нам нужно создать новый маршрут. Итак, откройте config/routes.rb и добавьте этот маршрут:

get 'stories/:id', to: 'stories#show', as: :story

Наконец, отредактируйте партиал _story.html.erb, чтобы создать ссылку на детали. Измените часть комментариев, чтобы она стала ссылкой:

<%= time_ago_in_words(story['time']) %> ago | <%= link_to "#{story['descendants']} comments", story_path(story['id']) %> </div>

Попробуйте. Вы должны иметь возможность обновить домашнюю страницу и щелкнуть ссылку комментариев, чтобы получить подробный обзор комментариев:

Как вы, возможно, заметили ранее, комментарии могут иметь ответы, и они могут иметь ответы, и, таким образом, владеть собой. На исходном веб-сайте Hacker News они показаны в виде дерева. Чтобы немного упростить этот урок, мы выделим его на отдельную страницу, на которую пользователь может щелкнуть, чтобы углубиться в каждую цепочку. Во-первых, измените партиал для комментариев (_comment.html.erb), чтобы была ссылка на представление темы:

<%= comment['by'] %> <%= time_ago_in_words(comment['time']) %> ago | <%= link_to "#{comment.fetch('kids', []).count} responses", comment_path(comment['id']) %> </span>

При этом создайте новый контроллер с именем comments_controller.rb и добавьте к нему это:

class CommentsController < ApplicationController def show @comment = client.item(params[:id]) @comments = (@comment['kids'] || []).map do |kid| client.item(kid) end end end

Мы делаем почти то же самое, что и для деталей истории, где мы получаем родительский комментарий, а затем извлекаем его дочерние элементы (если они есть). Нам также нужно создать шаблон для этого нового маршрута. Создайте новый файл в app/views/comments с именем show.html.erb и добавьте следующее:

<%= render partial: 'comment', object: @comment %> <h4>Responses</h4> <%= render partial: 'comment', collection: @comments %>

Чтобы это работало, нам нужно добавить новый маршрут в наш файл routes.rb:

get 'comments/:id', to: 'comments#show', as: :comment

Если вы обновите свой веб-сайт, вы сможете просмотреть каждый комментарий и погрузиться в каждую тему.

Вывод

Я надеюсь, что это руководство помогло показать вам, как использовать Hacker News API, но также показало, насколько мощным может быть Rails при создании приложения. Несмотря на то, что мы не использовали базу данных, использование Rails для создания клиента API может быть столь же полезным и простым. В качестве дальнейшего упражнения я бы порекомендовал создать представление профиля для пользователя. Hacker News API имеет конечную точку user, которая предоставляет вам некоторую информацию о пользователях, а также истории и комментарии, которые они отправили. Вы должны иметь возможность использовать частичные шаблоны, которые мы создали, чтобы сделать это без особых усилий.

Первоначально опубликовано на https://rapidapi.com 25 февраля 2020 г.