Skip to main content

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 run docker compose up --build --detach again
  • 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);
}
}