ShangriLa Anime APIを使って簡易的なアニメ情報サイトを作ってみた

# はじめに
この記事は[Life is Tech ! Tokai Advent Calendar 2022](https://qiita.com/advent-calendar/2022/life-is-tech-tokai)の19日目の記事です。

現在と過去のAnime情報を取得できるAPIであるShangriLa Anime APIの使い方とその詳細ページの画面出しわけ方法について紹介しています。

### 使用している技術
- ShangriLa Anime API
- Ruby
- Sinatra

# ShangriLa Anime APIについて
ShangriLa Anime APIとはアニメ作品の情報を返すREST形式のAPIサーバーのことです。
詳しい内容については[公式ドキュメント](https://github.com/Project-ShangriLa/sora-playframework-scala)をみてください。この記事では最低限必要な情報を紹介していきます。

- エンドポイント：http://api.moemoe.tokyo/anime/v1
- 認証：行わない
- レートリミット(利用制限のこと)：なし

## 今期のアニメ情報を取ってくるには
GETメゾットで/anime/v1/master/:year/:nリソースにアクセスすると取得できます。
:yearのところに取ってきたい年、:nのところに季節を入れます
| nの値 | 1 | 2 | 3 | 4 |
|:-:|:-:|:-:|:-:|:-:|
| 季節 | 春 | 夏 | 秋 | 冬 |

よって今(2022年冬クール)のアニメ情報を取るには以下のようなコードになる。

```ruby:app.rb
base_url = 'https://api.moemoe.tokyo/anime/v1/master/2022/4'
url = URI.parse(base_url)
@result = Net::HTTP.get(url).force_encoding("utf-8")
```
`@result`の中にアニメ情報が格納されます。
受け取れる情報としては以下のようなものがあります。(公式ドキュメント引用)
| Property|	Value|	Required|	description|	Sample|
|:-:|:-:|:-:|:-:|:-:|
|id	|Number|	◯|	APIで管理するアニメ作品に割り当てられているユニークなID	|125|
|title	|String|	◯|	アニメ作品名|	"冴えない彼女の育てかた"|
|title_short1|	String|	-	|アニメ作品名の略称1	|"冴えカノ"|
|title_short2|	String|	-	|アニメ作品名の略称2|	|
|title_short3|	String|	-	|アニメ作品名の略称3	|
|public_url|	String|	◯	|アニメ作品の公式URL|	"http://www.saenai.tv/"|
|twitter_account|	String|	◯	|ツイッターアカウント|	"saenai_heroine"|
|twitter_hash_tag|	String|	◯	|ツイッターハッシュタグ|	"saekano"|
|cours_id|	Number|	◯	|coursマスターのID|	5|
|created_at	|String	|◯	|データの作成日時|	"2015-01-08 09:37:01.0"|
|updated_at	|String|	◯	|データの更新日時	|"2015-01-08 09:37:01.0"|
|sex|	Number|	-	|男性向け=0, 女性向け=1|	0|
|sequel|	Number|	-	|続編モノの場合は1以上の数値が入る|	0|
|city_code|	Number|	-	|代表聖地地区の5桁の市区町村コード(RESAS APIなど地方自治体のオープンデータと連携する時に使用)|	22203|
|city_name|	String|	-	|代表聖地地区の市区町村名|	静岡県静岡市|

# さぁアニメ情報サイトを作ってみよう
こんな感じのサイトを作っていこうかと思います。
<iframe width="560" height="315" src="https://www.youtube.com/embed/r-w2wp4MlFM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

## まずアニメ情報を取ってくる
```ruby:app.rb
require 'bundler/setup'
Bundler.require
require 'sinatra/reloader' if development?
require 'date'
require 'net/http'
require 'uri'

def call_api
    anime_cool = (Date.today.month - 1).div(3) + 1
    base_url = 'https://api.moemoe.tokyo/anime/v1/master/' + Date.today.year.to_s + '/' + anime_cool.to_s
    url = URI.parse(base_url)
    returned_json = Net::HTTP.get(url).force_encoding("utf-8")
    hash_data = JSON.parse(returned_json)  # RubyのHashに変換している
    return hash_data
end
```
`Date.today.year` `Date.today.month`で今日の年と月を取得できます。
`Date.today.month.div(3)`で取得した今月の月の数を3で割った商をURLに入れます。(例：12月なら4)

## 取ってきたアニメ情報を表示する

アニメ情報を検索・表示するだけなら以下のようなコードでできます。
```ruby:app.rb
get '/' do
    @result = []
    api_data = call_api
    if params[:keyword]
        api_data.each do |res|
            if res["title"].include?(params[:keyword])
                @result.push(res)
            end
        end
    end
    erb :index
end
```
サイトのトップ画面にて検索と表示ができるようにデータを取得しています。

表示側は以下のようになります。

```erb:index.erb
<form action="/" method="get">
    <input type="text" name="keyword">
    <input type="submit" value="検索">
</form>
<% @result.each do |res| %>
    <a href="/info/<%= res["id"] %>">
        <h5><%= res["title"] %></h5>
    </a>
<% end %>
```
`<a href="/info/<%= res["id"] %>">`で個別のアニメ情報ページへのリンク誘導をしています。


Bootstrapを使用し、レイアウトを整えると以下のようなコードになります。
```erb:index.erb
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>アニメ情報サイト</title>
	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>
<body class="p-5">
	<form action="/" method="get" class="row g-2 d-flex justify-content-center">
		<div class="col-auto">
		<input class="form-control" type="text" name="keyword">
		</div>
		<div class="col-auto">
		<input class="btn btn-primary mb-3" type="submit" value="検索">
		</div>
	</form>
	<div class="row d-flex justify-content-center">
		<% @result.each do |res| %>
			<div class="card-body">
                <a class="btn" href="/info/<%= res["id"] %>">
                    <h5><%= res["title"] %></h5>
                </a>
            </div>
		<% end %>
	</div>
	<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
</html>
```

## 個別のアニメ情報を表示する
トップページで/info/id(取ってきたアニメの固有id)にてアニメごとの個別の詳細ページへのリンクになっているので、以下のようにコードを記載します。
```ruby:app.rb
# :idをつけておくことであとでparamsでデータが取ってこれる
get '/info/:id' do
    api_data = call_api
    api_data.each do |res|
        if res["id"] == params[:id].to_i
            @info = res
        end
    end
    erb :info
end
```
表示するページは以下のようにコードを書きます。(こちらは最初からBootstrapにてレイアウト適応済)
```erb:info.erb
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>アニメ情報サイト</title>
	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>
<body class="p-5">
	<div class="row d-flex justify-content-center">
	    <div class="card p-5 w-50">
		<h1><%= @info["title"] %></h1>
	    <a class="btn btn-primary mt-3 mb-5" href="<%= @info["public_url"] %>">公式サイトはこちら</a>
		<a class="twitter-timeline" href="https://twitter.com/<%= @info["twitter_account"] %>?ref_src=twsrc%5Etfw">Tweets by <%= @info["twitter_account"] %></a> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
        </div>
	</div>
	<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
</html>
```

# さいごに
手軽にアニメの情報を取得して、いい感じのサイトを作ることができるのでぜひやってみてください。