Parse Server Swift SDKの使い方（認証機能の使い方）

[ニフクラ mobile backendは3月末で終了します](https://mbaas.nifcloud.com/info/2023/12/post-171.html)。

ニフクラ mobile backendからの移行先として、お勧めしているのが[Parse Server](https://parseplatform.org/)です。設計思想が近く、変更するコード量が少なく済むのではないかと思います。

Parse ServerではiOS向けにSDKを提供していますが、Swift SDKについてはあまりドキュメントが充実していません。そこで、各機能の使い方を解説します。今回は認証機能について紹介します。

## Swift SDKとObjective-C SDKのどちらを使うべきか

Parse ServerにはSwift SDKと[Objective-C SDK](https://docs.parseplatform.org/ios/guide/)が用意されています。機能的にいうと、Objective-C SDKの方が多いようです。しかし、公式メッセージとしてはSwift SDKを使っていくのを奨励しています。

## Parse Server Swift SDKのインストール

Swift SDKのインストールは、CocoaPodsやCarthageなどが使えます。しかし、一番簡単なのはXcodeのPackage Dependenciesを使う方法でしょう。

XcodeのFileメニューより、Add Package Dependenciesを選択して、出てきたダイアログで以下のURLを指定します。

```
https://github.com/parse-community/Parse-Swift.git
```

そして、利用するファイルでSDKをインポートします。

```swift
import ParseSwift
```

## 初期化

SwiftUIの例です。初期化は `(アプリ名)App.swift` にて行います。そして、初期化は `ParseSwift.initialize` にて行います。指定するアプリケーションID、クライアントキー、サーバーURLはそれぞれParse Serverを立ち上げる際に指定したものを使います。

マスターキーも指定できるようですが、アプリ側では使わない方が良いかと思います。

```swift
import SwiftUI
import ParseSwift

@main
struct ParseDemoApp: App {
    init() {
        ParseSwift.initialize(applicationId: "YOUR_APP_ID", clientKey: "YOUR_CLIENT_KEY", serverURL: URL(string: "https://example.com/parse")!)
    }
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
```

## 構造体の作成

認証を利用する際には、 `ParseUser` を継承した構造体を作成します。

```swift
struct User: ParseUser {
    //: ParseObjectの必須フィールドです
    var objectId: String?
    var createdAt: Date?
    var updatedAt: Date?
    var ACL: ParseACL?
    var originalData: Data?

    //: ParseUserの必須フィールドです
    var username: String?
    var email: String?
    var emailVerified: Bool?
    var password: String?
    var authData: [String: [String: String]?]?

    //: 独自のフィールドを追加できます
    var customKey: String?
}
```

## ユーザー登録

サインアップは `signup` メソッドを使います。非同期でのサインアップは以下の通りです。

```swift
User.signup(username: "hello", password: "world") { results in
    switch results {
    case .success(let user):
        guard let currentUser = User.current else {
            assertionFailure("すでに異なるユーザーでログインしています")
            return
        }

        if !currentUser.hasSameObjectId(as: user) {
            assertionFailure("異なるユーザーを紐付けようとしています")
        } else {
            print("サインアップ完了です \(user)")
        }

    case .failure(let error):
        assertionFailure("エラーです \(error)")
    }
}
```

## パスワードの検証

`verifyPassword` メソッドはパスワードの検証だけを行うメソッドです。

```swift
User.verifyPassword(password: "world", usingPost: false) { results in

    switch results {
    case .success(let user):
        print(user)

    case .failure(let error):
        print("パスワード検証エラー \(error)")
    }
}
```

## 現在ログイン中のユーザー情報を取得する

`User.current` で現在ログイン中のユーザー情報を取得できます。

```swift
var currentUser = User.current
```

## ログインユーザーの情報を更新する

`User.current.fetch` でログイン中のユーザー情報を更新できます。以下はユーザーに紐付いた `gameScore` データを取得します。

```swift
User.current?.fetch(includeKeys: ["gameScore"]) { result in
    switch result {
    case .success:
        print("取得成功 \(String(describing: User.current))")
    case .failure(let error):
        print("エラー \(error)")
    }
}
```

## ログアウト

ログアウトは `User.logout` メソッドを使います。

```swift
do {
    try User.logout()
    print("ログアウトしました")
} catch let error {
    print("ログアウトエラー: \(error)")
}
```

## メールアドレス確認

`User.verificationEmail` メソッドを使ってメールアドレス確認を行います。これは指定したメールアドレス宛にメールが送信されます。

```swift
do {
    try User.verificationEmail(email: "hello@parse.org")
    print("メールアドレス検証メールが送信されました")
} catch let error {
    print("メール送信エラー: \(error)")
}
```

## スワードリセット

`User.passwordReset` メソッドを使ってパスワードリセットを行います。これも指定したメールアドレス宛にメールが送信されます。

```swift
do {
    try User.passwordReset(email: "hello@parse.org")
    print("パスワードリセットを送信しました")
} catch let error {
    print("メール送信エラー: \(error)")
}
```

## 匿名認証

`User.anonymous.login` メソッドを使って匿名認証を行います。

```swift
//: Logging in anonymously.
User.anonymous.login { result in
    switch result {
    case .success:
        print("ログイン成功 \(String(describing: User.current))")
    case .failure(let error):
        print("エラー: \(error)")
    }
}
```

## ソーシャル認証

Swift SDKでは多様なソーシャル認証が提供されています。以下はSign in with Appleの例です。

```swift
User.apple.login { result in
    switch result {
    case .success:
    case .failure(let error):
        
    }
}
```

他に、以下のソーシャル認証用クラスが提供されています。

- ParseApple
- ParseFacebook
- ParseGithub
- ParseGoogle
- ParseInstagram
- ParseLDAP
- ParseLinkedIn
- ParseSpotify
- ParseTwitter

## まとめ

Parse ServerとNCMBは設計思想が似ていますので、移行時における全体の修正量はそこまで多くないと思われます。載せ替え先として検討に挙げてください。

認証についてはソーシャル認証が多種多様に用意されている印象です。ぜひ活用してください。

[parse\-community/Parse\-Swift: The Swift SDK for Parse Platform \(iOS, macOS, watchOS, tvOS, Linux, Android, Windows\)](https://github.com/parse-community/Parse-Swift)