【Swift】QiitaのAPI(v2)をiOSアプリで操作する方法!パラメータやクエリの実装

この記事からわかること
- QiitaのAPI(v2)で記事情報を取得する方法
- Swiftで表示するiOSアプリの作り方
- 受け取れるJSON形式
- パラメータやクエリの種類と使い方
index
[open]
\ アプリをリリースしました /
Qiitaの記事情報を表示するiOSアプリを開発してみたかったので実際に開発してみました。ちなみに以下記事ではAndroidアプリでQiitaの記事情報を表示するアプリを実装しています。
QiitaのAPI:Qiita API v2
Qiitaでは記事情報やユーザー情報をJSON形式の文字データとして取得できるように「Qiita API v2」というAPI(Application Programming Interface)が用意されています。このAPIは指定のURLにアクセスした際にJSON形式のデータを取得できるようになっており、任意のパラメータを指定することで取得するデータのフィルタリングや数をコントロールすることができるようになっています。
リクエストには制限があり、認証している状態ではユーザーごとに1時間に1000回まで、認証していない状態ではIPアドレスごとに1時間に60回までになっています。今回は認証をせずに実装していきます。
API URL
アクセスするのはhttps://qiita.com/api/v2
で始まるURLです。それ以降にitems
やusers
、パラメータなどを指定することで任意のデータを取得することができるようになります。
記事(1つ):https://qiita.com/api/v2/items/<記事ID>
例えば上記のURLにアクセスするとQiitaに投稿されている「【SwiftUI】MVVM構造でログイン機能を実装してみた」という記事の情報がJSON形式の文字列になった状態で取得することができます。記事ID
はQiitaの記事にアクセスしたURLの末尾の数字の羅列です。

ちなみに<記事ID>
を指定しない場合Qiitaの全ての記事(新着順20個)が受け取れるようです。
記事(新着順20個):https://qiita.com/api/v2/items
受け取れるJSON形式
受け取れるJSON形式には記事情報だけでなく、様々な情報が組み込まれているため必要となる情報のみを抽出する必要があります。必要になりそうなJSON形式は以下のようになります。
[{
"id": "記事の一意のID",
"title": "記事のタイトル",
"body": "記事の本文",
"created_at": "記事の作成日時",
"updated_at": "記事の更新日時",
"user": {
"id": "ユーザーの一意のID",
"name": "ユーザー名",
"profile_image_url": "ユーザーのプロフィール画像のURL"
},
// .....他にもさまざまな情報
}]
それ以外にもtagやいいね数、コメント数、参照URLなどがキーと値に割り振られて受け取ることができます。
JSONDecoderで変換する用のモデル構造体を定義
JSON形式で取得した記事情報をSwift内で操作するために構造体へと変換していきます。そのために変換対象となるUser
構造体とArticle
構造体を定義しておきます。
struct User : Decodable{
let id:String
let name:String
let profile_image_url:String
}
struct Article : Decodable{
let id:String
let title:String
let body:String
let created_at:String
let updated_at:String
let user:User
}
ここでは各プロパティ名をJSONのキーと一致するように命名することとDecodable
プロトコル(またはCodable
)への準拠が必要になります。
AlamofireでHTTP通信の実装
APIへのリクエスト処理はHTTPネットワーキングライブラリ「Alamofire」を使用していきます。
import UIKit
import Alamofire
class QiitaApiModel {
public func fetchArticles(completion:@escaping ([Article]) -> Void) {
AF.request("https://qiita.com/api/v2/items")
.responseData { response in
do {
let decoder = JSONDecoder()
let articles = try! decoder.decode([Article].self, from: response.data!)
print(articles)
completion(articles)
} catch {
print(error.localizedDescription)
}
}
}
}
上記の例ではhttps://qiita.com/api/v2/items
(全記事)を取得してるので[Article].self
になります。
あとはUIを調整して配置すれば以下のようにQiitaの記事を取得して表示させることができます。下にコードを載せておきます。

記事情報配列を観測するViewModel
class QiitaArticleViewModel:ObservableObject {
static let shared = QiitaArticleViewModel()
private let model = QiitaApiModel()
@Published var articles: [Article] = []
func setArticle(){
model.fetchArticles { array in
self.articles = array
}
}
}
Qiita日付調整用ViewModel
class DisplayDateViewModel {
private let df = DateFormatter()
public func getQiitaFormatToDate(str:String) -> String{
df.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
let date = df.date(from: str)!
df.dateFormat = "yyyy/MM/dd HH:mm"
return df.string(from: date)
}
}
Qiita記事表示用View(Swift UI)
struct ContentView: View {
@ObservedObject var qiitaArticleVM = QiitaArticleViewModel.shared
private let displayDateVM = DisplayDateViewModel()
var body: some View {
VStack{
List(qiitaArticleVM.articles){ article in
HStack{
AsyncImage(url: URL(string: article.user.profile_image_url)) { image in
image.resizable()
} placeholder: {
ProgressView()
}.frame(width: 30, height: 30)
VStack{
Text(article.title)
HStack{
Spacer()
Text(displayDateVM.getQiitaFormatToDate(str: article.created_at))
}
}
}
}
Button {
qiitaArticleVM.setArticle()
} label: {
Text("Button")
}
}
}
}
リクエストにパラメータやクエリを追加する
記事情報を取得できるURLに対してパラメータを渡すことで取得するページ番号などを指定することが可能です。
パラメータ | 概要 |
---|---|
page | 表示するページ番号(初期値:1/最大値:100) |
per_page | 1ページに対して含ませる記事数(初期値:20/最大値:100) |
query | 検索クエリ |
パラメータはURLの末尾に?
を追加し、複数のパラメータを指定する際は&
で連結していきます。
全記事を2個でページングした際の1ページ目
検索クエリで条件を絞る
query
パラメータの後にはさまざまな項目を指定することで条件にマッチした記事情報だけに絞った結果を取得することが可能です。?query=
の後にクエリ項目:値
という形式で指定します。
タイトルに「swift」が含まれる記事
クエリ項目 | 概要 |
---|---|
title | タイトルに指定の文字列が含まれる |
body | 本文に指定の文字列が含まれる |
tag | 指定のタグを持つ |
-tag | 指定のタグを持たない |
user | 指定のユーザー |
created | 作成日 |
updated | 更新日 |
stocks | ストック件数 |
URLの有効性をチェックする
クエリに渡す文字に日本語が含まれる場合は適切なエンコードをしないと正常に動作しません。またそれ以外にもURL自体が有効であるかどうかをチェックすることでエラーを起こすことなくリクエストを送信することができるようになります。
let url = "https://qiita.com/api/v2/items?page=1&per_page=5&query=title:日本語"
URL(string: url) // nil
上記のままではうまく変換できず、無効なURLになってしまうのでaddingPercentEncoding
を使用してエンコードする必要がある。
let url = "https://qiita.com/api/v2/items?page=1&per_page=5&query=title:"
let text = "日本語"
let encodeString = text.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!
URL(string: url + encodeString)! // https://qiita.com/api/v2/items?page=1&per_page=5&query=title:%E6%97%A5%E6%9C%AC%E8%AA%9E
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。