Serverpod
Init
-
create project
serverpod create <projectname>
-
prepare server
docker compose up --build --detach
-
run server
dart bin/main.dart --apply-migrations
Issue
- if you get error failed to connect to local serverpod postgres container, then try this:
docker compose down -v
then rundocker compose up --build --detach
again
- if you get error failed to connect to local serverpod postgres container, then try this:
-
run flutter app (client) on flutter dir
flutter run -d chrome
-
add auth package
-
on server
dart pub add serverpod_auth_server
-
in flutter
add 2 packages
dart pub add serverpod_auth_shared_flutter serverpod_auth_email_flutter
-
in client
dart pub add serverpod_auth_client
-
setup auth handler
server/lib/server.dart...
import 'package:serverpod_auth_server/serverpod_auth_server.dart' as auth;
void run(List<String> args) async {
// Initialize Serverpod and connect it with your generated code.
final pod = Serverpod(
args,
Protocol(),
Endpoints(),
authenticationHandler: auth.authenticationHandler,
);
auth.AuthConfig.set(auth.AuthConfig(
sendValidationEmail: (session, email, validationCode) async {
print('Email validation code: $validationCode');
return true;
},
sendPasswordResetEmail: (session, userInfo, validationCode) async {
print('Password reset code: $validationCode');
return true;
},
));
...
}
-
Changes which need generate
- after changes run this command on server
serverpod generate
- migration on server
serverpod create-migration
Session
flutter/main.dart
import 'package:serverpod_auth_shared_flutter/serverpod_auth_shared_flutter.dart';
final client = Client(
'http://$localhost:8080/',
authenticationKeyManager: FlutterAuthenticationKeyManager(),
)..connectivityMonitor = FlutterConnectivityMonitor();
final sessionManager = SessionManager(caller: client.modules.auth);
void main() {
WidgetsFlutterBinding.ensureInitialized();
sessionManager.initialize();
runApp(const MyApp());
}
class _MyHomePageState extends State<MyHomePage> {
void initState() {
sessionManager.addListener(() {
setState(() {});
});
super.initState();
}
Widget build(BuildContext context) {
return switch (sessionManager.isSignedIn) {
true => NotePage(),
false => SignInPage(),
};
}
}
Model
notes.spy.yaml
class: Note
table: note
fields:
text: String
createdBy: module:auth:UserInfo?, relation
Endpoint
notes_endpoint.dart
import 'package:notedtogether_server/src/generated/notes.dart';
import 'package:serverpod/serverpod.dart';
import 'package:serverpod_auth_server/serverpod_auth_server.dart';
class NotesEndpoint extends Endpoint {
bool get requireLogin => true;
Future<void> createNote(Session session, Note note) async {
final authenticatedInfo = await session.authenticated;
if (authenticatedInfo?.userId != note.createdById) {
throw FormatException('Usr mismatch');
}
await Note.db.insertRow(session, note);
}
Future<List<Note>> getAllNotes(Session session) async {
final authenticatedInfo = await session.authenticated;
final notes = await Note.db.find(
session,
orderBy: (note) => note.id,
where: (note) => note.createdById.equals(authenticatedInfo?.userId),
include: Note.include(
createdBy: UserInfo.include(),
),
);
return notes;
}
Future<void> deleteNote(Session session, Note note) async {
await Note.db.deleteRow(session, note);
}
}
Ready Template UI
SignInWithEmailButton(
caller: client.modules.auth,
)
Access Data
List<Note>? _notes;
Exception? _connectionException;
Future<void> _loadNotes() async {
try {
final notes = await client.notes.getAllNotes();
_notes = notes;
setState(() {});
} catch (e) {
_connectionFailed(e);
}
}
void _connectionFailed(exception) {
_notes = null;
_connectionException = exception;
setState(() {});
}
Future<void> _createNote(String text) async {
final note = Note(
text: text,
createdById: sessionManager.signedInUser!.id!,
);
_notes?.add(note);
setState(() {});
try {
await client.notes.createNote(note);
await _loadNotes();
} catch (e) {
_connectionFailed(e);
}
}
Future<void> _deleteNote(Note note) async {
_notes?.remove(note);
setState(() {});
try {
await client.notes.deleteNote(note);
await _loadNotes();
} catch (e) {
_connectionFailed(e);
}
}