From fdc6aec0965ce5590541090834ebbb01391d0c13 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Wed, 8 Nov 2023 07:27:17 -0300 Subject: [PATCH] docs: remove README examples --- README.md | 336 ++++-------------------------------------------------- 1 file changed, 25 insertions(+), 311 deletions(-) diff --git a/README.md b/README.md index 489a1bab..a52523cf 100644 --- a/README.md +++ b/README.md @@ -4,34 +4,19 @@ Supabase client for swift. Mirrors the design of [supabase-js](https://github.com/supabase/supabase-js/blob/master/README.md). -## Contents -- [Installation](#installation) -- [Usage](#usage) -- [Login Implementation](#login-implementation) -- [Social Login Implementation](#social-login-implementation) - - [Setup Callback URL](#setup-callback-url) - - [Google Sign In](#google-sign-in) - - [Apple Sign In](#apple-sign-in) - - [Other Social Logins](#other-social-logins) -- [Basic CRUD Implementation](#basic-crud-implementation) - - [Insert Data](#insert-data) - - [Select Data](#select-data) -- [Contributing](#contributing) -- [Sponsors](#sponsors) +* Documentation: [https://supabase.com/docs/reference/swift/introduction](https://supabase.com/docs/reference/swift/introduction) ---- -## Installation +## Usage -Swift Package Manager: +Install the library using the Swift Package Manager. -Add the following lines to your `Package.swift` file: ```swift let package = Package( ... dependencies: [ ... - .package(name: "Supabase", url: "https://github.com/supabase/supabase-swift.git", branch: "master"), // Add the package + .package(name: "Supabase", url: "https://github.com/supabase/supabase-swift.git", from: "1.0.0"), // Add the package ], targets: [ .target( @@ -44,306 +29,35 @@ let package = Package( If you're using Xcode, [use this guide](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app) to add `supabase-swift` to your project. Use `https://github.com/supabase/supabase-swift.git` for the url when Xcode asks. -## Usage +If you don't want the full Supabase environment, you can also add individual packages, such as `Functions`, `GoTrue`, `Realtime`, `Storage`, or `PostgREST`. -To make requests to the `Supabase` database, you will need to initialize a `SupabaseClient` object: +Then you're able to import the package and establish the connection with the database. ```swift -let client = SupabaseClient(supabaseURL: "{ Supabase URL }", supabaseKey: "{ Supabase anonymous Key }") +/// Create a single supabase client for interacting with your database +let client = SupabaseClient(supabaseURL: URL(string: "https://xyzcompany.supabase.co")!, supabaseKey: "public-anon-key") ``` -## Login Implementation - -Inside the `SupabaseClient` instance created before, you can find an `auth` property of type `GoTrueClient`. You can use it to perform sign in and sign up requests. - -- Here's how to sign up with an email and password and get the signed in user `Session` info: +### Initialize with custom options ```swift -Task { - do { - try await client.auth.signUp(email: email, password: password) - let session = try await client.auth.session - print("### Session Info: \(session)") - } catch { - print("### Sign Up Error: \(error)") - } -} -``` - -If you wish to add metadata for the user, you can pass it as part of the `data` parameter, just be sure to `import GoTrue` first to use the User metadata values. - -```swift -Task { - do { - try await client.auth.signUp( - email: email, - password: password, - data: [ - "name": .string("John Doe"), - "age": .number(25), - "some_boolean_parameter": .bool(true) - ] - ) - - let session = try await client.auth.session - print("### Session Info: \(session)") - } catch { - print("### Sign Up Error: \(error)") - } -} -``` - -- For existing users, here's how to log in with an email and password and get the logged in user `Session` info: - -```swift -Task { - do { - try await client.auth.signIn(email: email, password: password) - let session = try await client.auth.session - print("### Session Info: \(session)") - } catch { - print("### Sign Up Error: \(error)") - } -} -``` - -## Social Login Implementation - -### Setup Callback URL - -We need to first set up the callback URL for all Social Logins inside the app. - -- Setup the callback `URL` on `Info.plist`: - -```xml - - - CFBundleTypeRole - Editor - CFBundleURLSchemes - - app.yourapp://login-callback - - - -``` - -- Add this callback `URL` on `Supabase` under `Authentication -> URL Configuration -> Redirect URLs`. - -### Google Sign In - -- Setup Google Auth as per [Supabase's Documentation](https://supabase.com/docs/guides/auth/social-login/auth-google). -- Note: For iOS we still need to use Google Consent Form for Web. -- Import `SafariServices` in your `ViewController` and create a `SFSafariViewController` instance: - -```swift -import SafariServices - -var safariVC: SFSafariViewController? -``` - -- Get the `URL` for Google Sign in from `Supabase` and load it on `SFSafariViewController`. -- Pass the previous callback `URL` you set up in the `redirecTo` parameter: - -```swift -Task { - do { - let url = try await client.auth.getOAuthSignInURL(provider: Provider.google, redirectTo: URL(string: {Your Callback URL})!) - safariVC = SFSafariViewController(url: url as URL) - self.present(safariVC!, animated: true, completion: nil) - } catch { - print("### Google Sign in Error: \(error)") - } -} -``` - -- Handle the callback `URL` on `SceneDelegate` (for older projects, you can use `AppDelegate` if `SceneDelegate` is not present). -- Post a `NotificationCenter` call to let the `ViewController` know the callback has been fired and pass the `URL` received. This `URL` will be used to get the user session. - -```swift -func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { - if let url = URLContexts.first?.url as? URL { - if url.host == "login-callback" { - let urlDict: [String: URL] = ["url": url] - NotificationCenter.default.post(name: Notification.Name("OAuthCallBack"), object: nil, userInfo: urlDict) - } - } -} -``` - -- In your `ViewController`, observe for the `Notification` and handle it minimizing the `SFSafariViewController` and getting the session: - -```swift -NotificationCenter.default.addObserver( - self, - selector: #selector(self.oAuthCallback(_:)), - name: NSNotification.Name(rawValue: "OAuthCallBack"), - object: nil) - -@objc func oAuthCallback(_ notification: NSNotification){ - guard let url = notification.userInfo?["url"] as? URL else { return } - Task { - do { - let session = try await SupaBaseAuth().client.session(from: url) - print("### Session Info: \(session)") - } catch { - print("### oAuthCallback error: \(error)") - } - } - safariVC?.dismiss(animated: true) -} -``` - -### Apple Sign In - -- Setup Apple Auth as per [Supabase's Documentation](https://supabase.com/docs/guides/auth/social-login/auth-apple). -- For Sign in with Apple follow the above as per Google Sign In and just replace the provider. -- Once the user moves to the `SFSafariViewController`, an Apple native pop-up will slide up to continue with the sign in. - -```swift -Task { - do { - let url = try await client.auth.getOAuthSignInURL(provider: **Provider.apple**, redirectTo: URL(string: {Your Callback URL})!) - safariVC = SFSafariViewController(url: url as URL) - self.present(safariVC!, animated: true, completion: nil) - } catch { - print("### Apple Sign in Error: \(error)") - } -} -``` - -### Other Social Logins - -- If using a WebViews, other social logins will be similar to above. Just follow the [Supabase's Documentation](https://supabase.com/docs/guides/auth/) for their setup. - -## Basic CRUD Implementation - -First, import and initialize `SupabaseClient`, as explained in "Usage" section. - -### Insert Data - -- You can either use `Codable` or `Encodable` and `Decodable` protocols for the model's struct. However without either, you will get an error saying `Cannot convert value of type 'Void' to specified type 'InsertModel'` when trying to cast the response to your model. -- Create a model which follows your table's data structure: - - -```swift -struct InsertModel: Encodable, Decodable { - let id: Int? // you can choose to omit this depending on how you've setup your table - let title: String? - let desc: String? -} - -let insertData = InsertModel(title: "Test", desc: "Test Desc") -let query = client.database - .from("{ Your Table Name }") - .insert(values: insertData, - returning: .representation) // you will need to add this to return the added data - .select(columns: "id") // specifiy which column names to be returned. Leave it empty for all columns - .single() // specify you want to return a single value. - -Task { - do { - let response: [InsertModel] = try await query.execute().value - print("### Returned: \(response)") - } catch { - print("### Insert Error: \(error)") - } -} -``` - -### Select Data - -- Using the same model as before: - -```swift -let insertData = InsertModel(title: "Test", desc: "Test Desc") -let query = client.database - .from("{ Your Table Name }") - .select() // keep it empty for all, else specify returned data - .match(query: ["title" : insertData.title, "desc": insertData.desc]) - .single() - -Task { - do { - let response: [InsertModel] = try await query.execute().value - print("### Returned: \(response)") - } catch { - print("### Select Error: \(error)") - } -} -``` - -### Update Data - -- Using the same model as before: - -```swift -// Assuming the record above was inserted with id 1 -let updateData = InsertModel(id: 1, title: "Test Edited", desc: "Test Desc Edited") -let query = client.database - .from("{ Your Table Name }") - .update(values: updateData, - returning: .representation) // you will need to add this to return the updated data - .select(columns: "id") // specifiy which column names to be returned. Leave it empty for all columns - .single() // specify you want to return a single value. - -Task { - do { - let response: [InsertModel] = try await query.execute().value - print("### Returned: \(response)") - } catch { - print("### Update Error: \(error)") - } -} -``` - -### Delete Data - -```swift -let query = client.database - .from("{ Your Table Name }") - .delete(returning: .representation) // you will need to add this to return the deleted data - .match( - query: ["id" : 1] // assuming the record above was inserted with id 1 - // You can add additional conditions here - ) - .select() // specifiy which column names to be returned. Leave it empty for all columns - .single() - -Task { - do { - let response: [InsertModel] = try await query.execute().value - print("### Returned: \(response)") - } catch { - print("### Delete Error: \(error)") - } -} -``` - -## Postgres Functions - -- Unlike the JavaScript library, you can't use the `rpc` method on the `SupabaseClient`, instead you need to use the `rpc` method on the `PostgresClient`: - -```swift -struct YourFunctionNameParams: Codable { - let param1: String - let param2: String -} - -let query = client.database.rpc( - fn: "your_function_name", - params: YourFunctionNameParams(param1: "param1", param2: "param2") +let client = SupabaseClient( + supabaseURL: URL(string: "https://xyzcompany.supabase.co")!, + supabaseKey: "public-anon-key", + options: SupabaseClientOptions( + db: .init( + schema: "public" + ), + auth: .init( + storage: MyCustomLocalStorage(), + flowType: .pkce + ), + global: .init( + headers: ["x-my-custom-header": "my-app-name"], + session: URLSession.myCustomSession + ) + ) ) -// Like in Supabase-js, you can use the `.single` method to return a single value. - -Task { - do { - let response: [DataModel] = try await query.execute().value // Where DataModel is the model of the data returned by the function - print("### Returned: \(response)") - } catch { - print("### RPC Error: \(error)") - } -} ``` ## Contributing