Build your first app
You will build a simple note-taking app in this tutorial. You will learn the fundamental building blocks of Serverpod that enable you to create powerful and scalable server-side applications with ease.
We are assuming you have all the tools setup and ready to go. If not, please follow the Installing Serverpod guide to get up and running.
We will cover the following topics:
- Creating serializable objects
- Creating a database table
- Creating API endpoints for CRUD operations
- Using the serverpod code generator
- Using the generated client library
- Connecting a Flutter app to the server
Demo of what we will build: (Full code example).
Create a new project
Create a new project using the Serverpod CLI. Run the following command in your terminal:
$ serverpod create notes
To start the server:
cd notes/notes_server
docker compose up --build --detach
dart bin/main.dart
Serialize objects
Serverpod comes with a convenient way to create serializable objects with the help of code generation. These objects can easily be sent back and forth between the server and the client. This is managed by defining our objects in a YAML file which the code generator then parses and generates the necessary code for.
To define the structure of our Note object, we will create a YAML file called note.yaml
. Navigate to the lib/src/protocol
folder in your Serverpod project (notes_server
). Create the file and add the following content:
### Holds a note with a text written by the user.
class: Note
fields:
### The contents of the note.
text: String
Let's take a closer look at the content of the notes.yaml
file:
- class: Note Specifies the name of the class to be generated, which in this case is Note.
- fields: This keyword indicates the beginning of the field definitions for the Note class.
- text: String Defines a text field of type String in the Note class, in this minimal example we only have one field but you can add however many fields you need.
Use the code generator to generate the code for the Note
class from the definition in notes.yaml
. Run the following command from the root of your server project:
$ serverpod generate
After the code generation process is complete, you can access the generated code for the Note
class in lib/src/generated/note.dart
inside your Serverpod project.
By extending the SerializableEntity
class, the Note
object becomes capable of automatic serialization and deserialization. This makes the Note
object transmittable between the server and the client.
In simpler terms, we have created a class, Note
, that can hold information and be passed around within the server. Additionally, we can send this object all the way to the client side of our application. Serverpod takes care of handling the conversion between the object and its serialized representation, making it convenient to work with and transfer data seamlessly.
Create database tables
Serverpod provides built-in support for database integrations. By defining a database table named note
in the YAML file using the table
keyword, we create database bindings for our Note
class.
The updated content of the note.yaml
file should look like this:
### Holds a note with a text written by the user.
class: Note
table: note
fields:
### The contents of the note.
text: String
Run the code generator again to generate the necessary code for the database table:
$ serverpod generate
Take a look at the updated lib/src/generated/note.dart
file. You will notice that the code generator has added new methods for interacting with the database.
Access the generated SQL code
The code generator also generate the necessary SQL code for creating the database table. The SQL code can be found in the notes_server/generated/tables.pgsql
file.
Here is the SQL code generated for the Note table:
--
-- Class Note as table note
--
CREATE TABLE "note" (
"id" serial,
"text" text NOT NULL
);
ALTER TABLE ONLY "note"
ADD CONSTRAINT note_pkey PRIMARY KEY (id);
Apply database changes
To apply the changes to the database, you need to execute the SQL code generated in the notes_server/generated/tables.pgsql
file. You can use a database administration tool or the command line to run the SQL code.
- MacOS & Linux
- Windows
docker compose run -T --rm postgres env PGPASSWORD="<DATABASE_PASSWORD>" psql -h postgres -U postgres -d notes < generated/tables.pgsql
type .\generated\tables.pgsql | docker compose run -T postgres env PGPASSWORD="<DATABASE_PASSWORD>" psql -h postgres -U postgres -d notes
You need to replace <DATABASE_PASSWORD>
with the password for the database, you can find it inside the notes_server/config/passwords.yaml
file.
If you didn't name your project notes
you need to replace -d notes
with the name of your project.
Once the SQL code is executed successfully, the database table for storing the note data will be created.
Any time you update the table definitions you have to run the sql code on your database to update the database schema.
Create API endpoints
In Serverpod, endpoints are defined in the endpoints
folder within your server project. The code generator analyzes the code within these endpoints and generates a client library based on the defined functions. This client library is then used by your Flutter app to interact with your backend server.
Create a new file called notes_endpoint.dart
inside lib/src/endpoints
folder.
import 'package:serverpod/server.dart';
import '../generated/protocol.dart';
class NotesEndpoint extends Endpoint {
// Endpoint implementation goes here
}
In the above code, we import the necessary dependencies and import the generated Note
class from the protocol.dart file. We also define the NotesEndpoint
class, which extends the Endpoint
class provided by Serverpod. This is required for the endpoint to be recognized by Serverpod's code generator.
Define endpoints
To define a method that can be called from the client, we need to create a method inside the NotesEndpoint
class. This method must return a Future
of a serializable object, primitive datatype, or void.
The first method parameter must be a Session
object. This is a special object in Serverpod that contains information about the current session, as well as other helpful methods.
Future<void> example(Session session) async {
// Endpoint implementation goes here
}
The method is also allowed to have any number of extra parameters. These parameters will be passed from the client when the endpoint is called. The parameters follow the same type restrictions as the return type.
Store notes in the database
To store notes in the database we define a createNote
method in the NotesEndpoint
class. The method takes a Note
object and stores it in the database. To make the method accessible from the app, make sure that its first parameter is a Session
object.
Future<void> createNote(Session session, Note note) async {
await Note.insert(session, note);
}
In the above code, we use the Note.insert
method, created by serverpod generate
, to insert the specified Note
object into the database.