Swiftでサーバーサイドに入門してみる(Vapor編)
SwiftはAppleデバイスのソフトウェア開発で有名な言語ではありますが、Swiftでもサーバーサイドを開発出来るとのことでちょっと試してみることにしました。
はじめに
サーバーサイドSwiftで有名なフレームワークVaporのドキュメントからHello, world!
実行までとJSONを返すところまでの初歩的な記事になります。
環境
- Xcode 12.2
- Swift 5.7.2
- Vapor 4
Vapor 4 には Swift 5.2 以降が必要です。
インストール
Xcodeはインストールされている前提で進めていきます。
HomeBrewのインストール
Vapor ToolboxはHomebrew経由で配布される為、Homebrewをインストールする必要があります。既にインストール済みの場合はこの手順は必要ありません。
Homebrewのページにてインストール手順の記載があり、ターミナルに下記を入力し実行することでインストールが行えます。
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Vaporのインストール
Homebrewがインストールされた(されている)場合は、ターミナルに下記を入力してVaporをインストールします。
brew install vapor
ここまででVapor Toolboxがインストール出来ました。
プロジェクトの作成
作成する場所はどこでも良いですが、今回はデスクトップ上に作成する為、ターミナルを使用してデスクトップを現在のディレクトリに変更します。
cd ~/desktop
同じくターミナル上で、Vaporプロジェクトを新規で作成します。hello-world
の箇所は任意の名前で問題ないです。
vapor new hello-world
vapor new
を実行すると、作成が始まります。
Fluentフレームワークを使用するか問われます。
Cloning template... name: hello-world Would you like to use Fluent? (--fluent/--no-fluent) y/n>
今回は使用しない為n
を入力します。
すると、次にLeafフレームワークを使用するか問われます。
Would you like to use Leaf? (--leaf/--no-leaf) y/n>
同じく今回は使用しない為、n
を入力します。
アスキーアート的なものがターミナル上に表示されたら作成は完了です。
プロジェクトが作成されたので、Package.swiftをクリックしてプロジェクトを立ち上げます。
フォルダ構造
プロジェクトのフォルダ構造はこのようになっています。
. ├── Public ├── Sources │ ├── App │ │ ├── Controllers │ │ ├── Migrations │ │ ├── Models │ │ ├── configure.swift │ │ └── routes.swift │ └── Run │ └── main.swift ├── Tests │ └── AppTests └── Package.swift
引用: Folder Structure
Hello, world
Vaporのプロジェクトを作成しました。デフォルトの状態で既にローカルホスト上でサーバーを起動することが出来ます。
起動するデバイスをMy Macに設定し、ランを実行します。
ランに成功すると、デバッグコンソールにローカルホスト上でサーバーが起動したことが出力されています。
[ WARNING ] No custom working directory set for this scheme, using /Users/your-user-name/Library/Developer/Xcode/DerivedData/hello-world-fhdbhamkzhbtycannplsuwagehin/Build/Products/Debug [ NOTICE ] Server starting on http://127.0.0.1:8080
WARNINGが出ていますが、後ほど解消するとして、先に実際にローカルホスト http://127.0.0.1:8080
にアクセスして結果を確認します。
It works
という文字が表示されているのを確認出来ました!
VaporプロジェクトのSources > App > routes.swiftに記述されているコードを確認すると、ルートパスがない場合でGET
を実行した場合はIt works!
と表示されるようになっております。
import Vapor func routes(_ app: Application) throws { app.get { req async in "It works!" } app.get("hello") { req async -> String in "Hello, world!" } }
パスをhello
にした場合は、Hello, world!
という実行結果を得ることが出来るのでhttp://127.0.0.1:8080/hello
にアクセスしてみましょう。
Hello, world!
が確認出来ました!
警告を消す
デバッグコンソールに警告があったので解消しておきます。
[ WARNING ] No custom working directory set for this scheme, using /Users/your-user-name/Library/Developer/Xcode/DerivedData/hello-world-fhdbhamkzhbtycannplsuwagehin/Build/Products/Debug
このスキームではカスタムワーキングディレクトリが設定されていませんという内容なので設定してあげます。
Product > Scheme > Edit Schemes...を選択します。
表示された画面上で Run > Options を選択すると、ワーキングディレクトリが設定されていないのが確認出来ます。
Use Custom Working Directoryにチェックを入れて、任意のディレクトリを設定します。今回はVaporプロジェクトのディレクトリを設定しました。
これで警告は消えるようになりました。
JSONを返す
せっかくなので、ただの文字列だけではなく、JSONを返すところまで試してみたいと思います。
今回は、緯度経度と近くのランドマークの値を持つ構造体を作成しました。
struct Location { let latitude: Double let longitude: Double let nearLandmark: String }
また、今回はapi/location
というルートにしたかった為、下記にようなルートを設定しました。ネストを深くしたい場合は、その分パスを追加するだけです。
// http://127.0.0.1:8080/api/location app.get("api", "location") { req async -> [Location] in let location = Location(latitude: 34.39781747719756, longitude: 132.47562536097118, nearLandmark: "広島駅") return [location] }
しかし、このままだとVaporフレームワークが用意しているContent
型にLocation
が準拠していない為、エラーが発生します。
エラーの指示通り、Location
をContent
型に準拠させるとエラーが消えます。
struct Location: Content { let latitude: Double let longitude: Double let nearLandmark: String }
ランを実行して、http://127.0.0.1:8080/api/location
で結果を見てみましょう。
今回の目標だったJSONの値を確認出来ました!
おわりに
Swiftでサーバーサイドを実装する初歩的な内容を自分で試してみました。Swiftでサーバーサイドも書けるなんてワクワクしますね。これは充実した正月休みを送れそうです。
今回はGETまでだったので、POSTしたりDELETEしたり色々と試していきたいと思います。