---
title: SPMとSwift OpenAPIGenerator
tags:  #swift #openapigenerator  
author: [Kazuya Ueoka](https://www.docswell.com/user/fromkk)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/8EDYW12WEG.jpg?width=480
description: 沖縄モバイルアプリ開発勉強会 #2（https://okimobdev.connpass.com/event/306586/）で登壇した資料です。
published: February 24, 24
canonical: https://www.docswell.com/s/fromkk/56YPEL-openapi-generator
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/8EDYW12WEG.jpg)

SPMとSwift OpenAPIGenerator
@fromkk かっくん


# Page. 2

![Page Image](https://bcdn.docswell.com/page/V7P69Q1XJ8.jpg)

自己紹介
• 名前：植岡 和哉（かっくん）
• SNS: @fromkk (X, note, GitHub, Qiita, Zenn, etc…)
• フリーランスのiOSデベロッパー
• 埼玉県所沢市に中古マンションを購入・リノベーションして住
んでいます
• 猫が2匹います
• 主な趣味は写真です。最近編み物始めました。


# Page. 3

![Page Image](https://bcdn.docswell.com/page/2JV3M5Y3EQ.jpg)

kyuとは
https://kyu-o.com/
• TranSe Inc.が運営しているイメージングブランド
• 過去にはバックパック、クロス、SDカードスリーブを生産・販売
• 今はカメラ・アプリの開発に注力中


# Page. 4

![Page Image](https://bcdn.docswell.com/page/5EG3G69Y7L.jpg)

kyu app
https://apps.apple.com/jp/app/kyu-memories-never-fade/id6451095022
• 現在（2024/02/24）招待された方のみ公開中
• 簡単にいうと部屋を作って友だちを招待して動画を撮影して共有するアプリ
• 動画は1動画9秒制限、1日に9つまでアップロード可能
• 動画は一度下書きに保存され、6時間に一度公開される
• Highlight機能でまとめ動画を生成する
• Highlight動画にはSpotifyからBGMを設定することができる


# Page. 5

![Page Image](https://bcdn.docswell.com/page/4JQ5X4W67P.jpg)

kyu app
https://apps.apple.com/jp/app/kyu-memories-never-fade/id6451095022
• 現在（2024/02/24）招待された方のみ公開中
• 簡単にいうと部屋を作って友だちを招待して動画を撮影して共有するアプリ
• 動画は1動画9秒制限、1日に9つまでアップロード可能
• 動画は一度下書きに保存され、6時間に一度公開される
• Highlight機能でまとめ動画を生成する
• Highlight動画にはSpotifyからBGMを設定することができる


# Page. 6

![Page Image](https://bcdn.docswell.com/page/K7496QKME1.jpg)

機能紹介


# Page. 7

![Page Image](https://bcdn.docswell.com/page/LJ1KVPXY7G.jpg)

OpenAPI Generator
• OpenAPI(元Swagger)はymlファイルなどによりAPIのリクエスト・レスポンスの
パラメータや型を定義する仕組み
• AppleがSwiftでライブラリを提供
• サーバーサイドやクライアントのコードも生成してくれる
• DerivedData配下に設置されるので実態は見えない
• 詳しくはWWDC 2023の動画や公式ドキュメントなどを見てください
• 年末に1.0.0がリリースされた🎉
• その後もアップデート繰り返し現在（2024/02/17）は1.2.1


# Page. 8

![Page Image](https://bcdn.docswell.com/page/GJWDL2N172.jpg)

参考
• https://developer.apple.com/videos/play/wwdc2023/10171/
• https://zenn.dev/kamimi01/articles/7c6f79e42c3750
• https://zenn.dev/kamimi01/articles/1bb2a5f6f2bcf0


# Page. 9

![Page Image](https://bcdn.docswell.com/page/4EZGMD3XJ3.jpg)

今回気になったこと
• WWDCの発表の中ではメインアプリの中にSPM経由でライブラリを追加して
いた
• SPMを利用したマルチモジュール構成の場合にどうなるのか気になった
• 結論から言うと、特にメインアプリに追加するのと大きく変わらずに実装す
ることができた
• 設定ファイルとAPIの定義ファイルをPackage内に入れておくだけ


# Page. 10

![Page Image](https://bcdn.docswell.com/page/Y76YN1XPEV.jpg)

注意点
• 認証情報などの管理までうまくはやってくれない
• 認証情報やカスタムヘッダーなどはClientMiddlewareを作成して注入する
• 今回はアクセストークンを取得するAPIを手動で叩いて、その結果を元に検
索APIをコールするサンプルを作成してみた
• 事前にClientIDとClientSecretを取得しておく
• https://developer.spotify.com/ に登録して、アプリを登録することで取
得できる


# Page. 11

![Page Image](https://bcdn.docswell.com/page/G75G54XP74.jpg)

Spotifyの検索APIを叩いてみる


# Page. 12

![Page Image](https://bcdn.docswell.com/page/9J2YNVXZJR.jpg)

実装
必要なパッケージの追加
dependencies: [
.package(url:
.package(url:
.package(url:
.package(url:
],
&quot;https://github.com/apple/swift-openapi-generator&quot;, from: &quot;1.2.1&quot;),
&quot;https://github.com/apple/swift-openapi-runtime&quot;, from: &quot;1.3.2&quot;),
&quot;https://github.com/apple/swift-openapi-urlsession&quot;, from: &quot;1.0.1&quot;),
&quot;https://github.com/apple/swift-http-types&quot;, from: &quot;1.0.3&quot;),


# Page. 13

![Page Image](https://bcdn.docswell.com/page/DEYGP38NEM.jpg)

実装
ターゲットに必要なライブラリやファイルを追加
targets: [
.target(name: &quot;SpotifyAPI&quot;, dependencies: [
.product(name: &quot;OpenAPIURLSession&quot;, package: &quot;swift-openapi-urlsession&quot;),
.product(name: &quot;OpenAPIRuntime&quot;, package: &quot;swift-openapi-runtime&quot;),
.product(name: &quot;HTTPTypes&quot;, package: &quot;swift-http-types&quot;),
], resources: [
.process(&quot;openapi-generator-config.yaml&quot;),
.process(&quot;openapi.yaml&quot;),
], plugins: [
.plugin(name: &quot;OpenAPIGenerator&quot;, package: &quot;swift-openapi-generator&quot;)
])
]
設定ファイルと定義ファイルを忘れずに


# Page. 14

![Page Image](https://bcdn.docswell.com/page/VJNG5VQV78.jpg)

実装
openapi-generator-con g.yaml
generate:
- types
- client
fi
今回はクライアントだが、サーバーのコード生成もできる


# Page. 15

![Page Image](https://bcdn.docswell.com/page/YE9WY6DVE3.jpg)

実装
openapi.yaml
openapi: &#039;3.0.3&#039;
info:
description: |
You can use Spotify&#039;s Web API to discover music and podcasts, manage your Spotify library, control audio playback, and much more. Browse our
available Web API endpoints using the sidebar at left, or via the navigation bar on top of this page on smaller screens.
In order to make successful Web API requests your app will need a valid access token. One can be obtained through &lt;a href=&quot;https://
developer.spotify.com/documentation/general/guides/authorization-guide/&quot;&gt;OAuth 2.0&lt;/a&gt;.
The base URI for all Web API requests is `https://api.spotify.com/v1`.
Need help? See our &lt;a href=&quot;https://developer.spotify.com/documentation/web-api/guides/&quot;&gt;Web API guides&lt;/a&gt; for more information, or visit the
&lt;a href=&quot;https://community.spotify.com/t5/Spotify-for-Developers/bd-p/Spotify_Developer&quot;&gt;Spotify for Developers community forum&lt;/a&gt; to ask
questions and connect with other developers.
version: &#039;1.0.0&#039;
title: &#039;Spotify Web API&#039;
termsOfService: &#039;https://developer.spotify.com/terms/&#039;
contact:
name: Spotify for Developers Community
url: https://community.spotify.com/t5/Spotify-for-Developers/bd-p/Spotify_Developer
servers:
- url: https://api.spotify.com/v1
tags:
- name: Albums
- name: Artists
.
.
.
https://developer.spotify.com/reference/web-api/open-api-schema.yaml からダウンロード


# Page. 16

![Page Image](https://bcdn.docswell.com/page/GE8N6Z347D.jpg)

実装
アクセストークンの取得
func token() async throws -&gt; SpotifyAPIAccessToken {
let url = URL(string: &quot;https://accounts.spotify.com/api/token&quot;)!
var request = URLRequest(url: url)
guard let clientId = SpotifyAuth.clientId else {
throw SpotifyAPIClientError.noClientId
}
guard let clientSecret = SpotifyAuth.clientSecret else {
throw SpotifyAPIClientError.noClientSecret
}
if let data = &quot;\(clientId):\(clientSecret)&quot;.data(using: .utf8) {
request.allHTTPHeaderFields = [
&quot;Authorization&quot;: &quot;Basic \(data.base64EncodedString())&quot;,
&quot;Content-Type&quot;: &quot;application/x-www-form-urlencoded&quot;,
]
}
request.httpBody = &quot;grant_type=client_credentials&quot;.data(using: .utf8)
request.httpMethod = &quot;POST&quot;
let configuration = URLSessionConfiguration.default
let urlSession = URLSession(configuration: configuration)
let (data, _) = try await urlSession.data(for: request)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let result = try decoder.decode(SpotifyAPIAccessToken.self, from: data)
return result
}


# Page. 17

![Page Image](https://bcdn.docswell.com/page/LELP9DVV7R.jpg)

実装
APIのコール
public func search(_ q: String) async throws -&gt; [SpotifyTrack] {
let accessToken = try await token()
let accessTokenMiddleware = AccessTokenMiddleware(accessToken: accessToken.accessToken)
let client = Client(
serverURL: try Servers.server1(),
transport: URLSessionTransport(),
middlewares: [accessTokenMiddleware]
)
let headers = Operations.search.Input.Headers()
let response = try await client.search(
query: Operations.search.Input.Query(q: q, _type: [.track]),
headers: headers
)
switch response {
case let .ok(items):
guard let tracks = try items.body.json.tracks?.value2.items else {
return []
}
let results = tracks.map {
SpotifyTrack(
id: $0.id,
title: $0.name,
artistName: $0.artists?.first?.name,
uri: $0.uri,
artworkUrl: $0.album?.value1.value1.images.first.flatMap {
URL(string: $0.url)
},
previewUrl: $0.preview_url.flatMap { URL(string: $0) },
href: $0.external_urls?.value1.spotify.flatMap { URL(string: $0) }
)
}
return results
default:
throw SpotifyAPIClientError.failed
}
}


# Page. 18

![Page Image](https://bcdn.docswell.com/page/4JM4ZPGN7W.jpg)

結果


# Page. 19

![Page Image](https://bcdn.docswell.com/page/PJRW61Z479.jpg)

まとめ
• Swift OpenAPI GeneratorをSwift Package Managerでどのように利用す
るのか試してみました
• 結果的にメインアプリで実装するのと同様に実装することができました
• GitHubにサンプルコードをアップしています
• https://github.com/fromkk/SpotifyAPISampler


