Files
supabase/apps/temp-docs/docs/reference/dart/upgrade-guide.mdx
Joshen Lim adac616e86 update
2022-10-27 15:50:41 +07:00

582 lines
9.8 KiB
Plaintext

---
id: upgrade-guide
title: Upgrade to supabase-flutter v1
description: 'Learn how to upgrade to supabase-flutter v1.'
---
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
supabase-flutter focuses on improving the developer experience and making it easier to use. This guide will help you upgrade from supabase-flutter v0 to v1.
## Upgrade the client library
Update the package in your pubspec.yaml file.
```yaml
supabase_flutter: ^1.0.0
```
## Error handling
The way supabase-flutter throws error has changed in v1. In v0, errors were returned as a response. In v1, errors are thrown as exceptions. This makes it more intuitive as a Flutter developer to handle errors.
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final res = await supabase.from('my_table').select().execute();
final error = res.error;
if(error != null) {
// handle error
}
final data = res.data;
```
</TabItem>
<TabItem value="1.x">
```dart
try {
final data = supabase.from('my_table').select();
} catch (error) {
// handle error
}
```
</TabItem>
</Tabs>
## Auth classes / methods
### Usage of `SupabaseAuthState` and `SupabaseAuthRequiredState` classes
In v0, `SupabaseAuthState` and `SupabaseAuthRequiredState` were required to handle automatic token refresh and to listen to auth state change. In v1, `SupabaseAuthState` and `SupabaseAuthRequiredState` are deprecated, and token refresh will happen automatically just by initializing Supabase. [`onAuthStateChange`](/docs/reference/dart/upgrade-guide#listening-to-auth-state-change) can be used to action on auth state change.
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await Supabase.initialize(
url: 'SUPABASE_URL',
anonKey: 'SUPABASE_ANON_KEY',
);
...
class AuthState<T extends StatefulWidget> extends SupabaseAuthState<T> {
...
}
...
class AuthRequiredState<T extends StatefulWidget> extends SupabaseAuthState<T> {
...
}
```
</TabItem>
<TabItem value="1.x">
```dart
await Supabase.initialize(
url: 'SUPABASE_URL',
anonKey: 'SUPABASE_ANON_KEY',
);
```
</TabItem>
</Tabs>
### Listening to auth state change
`onAuthStateChange` now returns a `Stream`.
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final authSubscription = supabase.auth.onAuthStateChange((event, session) {
// handle auth state change
});
// Unsubscribe when no longer needed
authSubscription.data?.unsubscribe();
```
</TabItem>
<TabItem value="1.x">
```dart
final authSubscription = supabase.auth.onAuthStateChange.listen((data) {
final AuthChangeEvent event = data.event;
final Session? session = data.session;
// handle auth state change
});
// Unsubscribe when no longer needed
authSubscription.cancel();
```
</TabItem>
</Tabs>
### Sign in with email and password
The signIn() method has been deprecated in favor of more explicit method signatures to help with type hinting. Previously it was difficult for developers to know what they were missing (e.g., a lot of developers didn't realize they could use passwordless magic links).
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase.auth.signIn(email: email, password: password);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.auth.signInWithPassword(email: email, password: password);
```
</TabItem>
</Tabs>
### Sign in with magic link
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase.auth.signIn(email: email);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.auth.signInWithOtp(email: email);
```
</TabItem>
</Tabs>
### Sign in with a third-party OAuth provider
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase.auth.signInWithProvider(
Provider.github,
options: AuthOptions(
redirectTo: kIsWeb
? null
: 'io.supabase.flutter://reset-callback/'),
);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.auth.signInWithOAuth(
Provider.github,
redirectTo: kIsWeb ? null : 'io.supabase.flutter://reset-callback/',
);
```
</TabItem>
</Tabs>
### Sign in with phone
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase.auth.signIn(
phone: '+13334445555',
password: 'example-password',
);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.auth.signInWithPassword(
phone: '+13334445555',
password: 'example-password',
);
```
</TabItem>
</Tabs>
### Sign in with phone using OTP
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final res = await supabase.auth.signIn(phone: phone);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.auth.signInWithOtp(
phone: phone,
);
// After receiving a SMS with a OTP.
await supabase.auth.verifyOTP(
type: OtpType.sms,
token: token,
phone: phone,
);
```
</TabItem>
</Tabs>
### Reset password for email
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase.auth.api.resetPasswordForEmail(
email,
options:
AuthOptions(redirectTo: 'io.supabase.flutter://reset-callback/'),
);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.auth.resetPasswordForEmail(
email,
redirectTo: kIsWeb ? null : 'io.supabase.flutter://reset-callback/',
);
```
</TabItem>
</Tabs>
### Get the user's current session
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final session = supabase.auth.session();
```
</TabItem>
<TabItem value="1.x">
```dart
final Session? session = supabase.auth.currentSession;
```
</TabItem>
</Tabs>
### Get the logged-in user
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final user = supabase.auth.user();
```
</TabItem>
<TabItem value="1.x">
```dart
final User? user = supabase.auth.currentUser;
```
</TabItem>
</Tabs>
### Update user data for a logged-in user
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase.auth.update(
UserAttributes(data: {'hello': 'world'})
);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.updateUser(
UserAttributes(
data: { 'hello': 'world' },
),
);
```
</TabItem>
</Tabs>
## Data methods
`.insert()` / `.upsert()` / `.update()` / `.delete()` don't return rows by default.
Previously, these methods return inserted/updated/deleted rows by default (which caused [some confusion](https://github.com/supabase/supabase/discussions/1548)), and you can opt to not return it by specifying `returning: 'minimal'`. Now the default behavior is to not return rows. To return inserted/updated/deleted rows, add a `.select()` call at the end.
Also, calling `.execute()` at the end of the query was a requirement in v0, but in v1 `.execute` is deperecated.
### Insert without returning inserted data
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
await supabase
.from('my_table')
.insert(data, returning: ReturningOption.minimal)
.execute();
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.from('my_table').insert(data);
```
</TabItem>
</Tabs>
### Insert with returning inserted data
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final res = await supabase
.from('my_table')
.insert(data)
.execute();
```
</TabItem>
<TabItem value="1.x">
```dart
final insertedData = await supabase.from('my_table').insert(data).select();
```
</TabItem>
</Tabs>
## Realtime methods
### Stream
`.stream()` no longer needs the `.execute()` at the end. Also, filtering by `eq` is a lot easier now. `primaryKey` is now a named parameter to make it more obvious what to pass.
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
supabase.from('my_table:id=eq.120')
.stream(['id'])
.listen();
```
</TabItem>
<TabItem value="1.x">
```dart
supabase.from('my_table')
.stream(primaryKey: ['id'])
.eq('id', '120')
.listen();
```
</TabItem>
</Tabs>
### Subscribe
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
final subscription = supabase
.from('countries')
.on(SupabaseEventTypes.all, (payload) {
// Handle realtime payload
})
.subscribe();
```
</TabItem>
<TabItem value="1.x">
```dart
final channel = supabase.channel('*');
channel.on(
RealtimeListenTypes.postgresChanges,
ChannelFilter(event: '*', schema: '*'),
(payload, [ref]) {
// Handle realtime payload
},
).subscribe();
```
</TabItem>
</Tabs>
### Unsubscribe
<Tabs
groupId="version"
values={[
{label: 'Before', value: '0.x'},
{label: 'After', value: '1.x'},
]}>
<TabItem value="0.x">
```dart
supabase.removeSubscription(subscription);
```
</TabItem>
<TabItem value="1.x">
```dart
await supabase.removeChannel(channel);
```
</TabItem>
</Tabs>