With a matter of little effort you could become a Fullstack developer with serverpod.
Serverpod is a complete backend framework designed for Flutter with Dart language. With Serverpod you can build Endpoints, Authentication, Job Scheduler, Websocket, and others, check out the list of its capabilities here.
Serverpod automatically generates your protocol and client-side code by analyzing your server. Calling a remote endpoint is as easy as making a local method call.
What to Expect in This Article
The objective of this article is to demonstrate a step-by-step guide to performing CRUD operations on the most recent version (1.1.0) of Serverpod.
we'll also walk through the installation process and deal with issues that might arise.
This tutorial doesn't expect any experience with the Serverpod framework.
Installation
The installation process is simple and very less error-prone.
Requirements:
Docker-desktop and Flutter must be installed.
The preceding step is important to be able to run the sample codes in this tutorial.
Installing:
To install Serverpod CLI on your machine; run the command below
dart pub global activate serverpod_cli
You have installed Serverpod if you see the sample output below in your terminal. The version could be different in the future though.
Creating a Project
Let's generate a sample project named noteapp
and examine its appearance. Execute the command below to create a project.
Note ⚠️
Docker must be up and running before you continue with the next step. check here to see why.
serverpod_cli create noteapp
Issue creating project:
Upon executing the command mentioned above for the first time, I encountered an issue that left me stuck, as illustrated in the image below.
You might not experience this issue.
The problem was resolved following the installation of net-tools on linux
Sample Project Overview
Let's uncover the directories within the sample project named noteapp
that you have generated.
The folder noteapp
should contain, noteapp_server
, noteapp_client
, noteapp_flutter
.
- noteapp_server: This contains your backend codes such as endpoints, Job schedules (Called Futures in Serverpod space) and e.t.c
- noteapp_client: Consist of auto-generate codes which you will use to communicate with your server. You don't even need any explicit http client; Serverpod takes care of all the hassle so you can focus.
-
noteapp_flutter: A pre-configured Flutter app to connect with your server through your generated
noteapp_client
.
In other not to make this article lengthy; I won't go deep into the details about the sub-folders of noteapp_server
, check this Youtube video by CodeX and for further information check here
Crud Operations
Let's demonstrate what Create
, Delete
, Update
, and Read
operation looks like in Serverpod with the created noteapp
.
Let's start with noteapp_server
folder. The image below should be our current folder structure.
Note: We will be dealing with the 3 highlighted folders above.
noteapp_server
This folder consists of our server codes. Let's look at some of its sub-folders and add the necessary changes.
-
protocol:
It contains configurations for our database objects. Delete
example.yaml
in the folder and createnote.yaml
and then paste the database configuration below.
# Yaml-files in the `protocol` directory specify which serializable objects # should be generated. When you add or modify a file, you will need to run # `serverpod generate` to make the generated classes available in the server and # client. # # Please consult the documentation for more information on what you can add to # your yaml-files. # Name of the class to generate. class: Note # Add the table key, if this class represents a row in the database. table: note # The fields (and columns if connected to the database) of the class. Supported # types are `bool`, `int`, `double`, `String`, `DateTime`, and any other # generated classes. You can also add lists of objects and types that have support # for null safety. Eg. `List<int>?` or `List<MyOtherClass?>`. fields: data: String date: DateTime
Now; run the command below to generate a database object
for the preceding configuration.
serverpod generate
-
endpoint:
The endpoint folder as the name suggests consists of our API endpoint codes. delete
example_endpoint.dart
and createnote_endpoint.dart
and then paste the code below.
class NoteEndpoint extends Endpoint { /// Create new note on the database Future<bool> createNote(Session session, Note note) async { await Note.insert(session, note); return true; } /// Delete note from database Future<bool> deleteNote(Session session, int id) async { final response = await Note.delete(session, where: (note) => note.id.equals(id)); return response == 1; } /// Update an existing note with the given note object Future<bool> updateNote(Session session, Note note) async { final response = await Note.update(session, note); return response; } /// Retrieve all saved notes from the database Future<List<Note>> getNotes(Session session) async { final notes = Note.find(session); return notes; } }
Note: Serverpod requires a naming convention to generate codes, Suffix whatever endpoint you're creating with "_endpoint" as in
note_endpoint.dart
.Execute the command below to generate endpoint codes.
serverpod generate
-
generated:
This folder hosts the generated codes for the endpoints and database protocol objects.
If you followed the instruction carefully; the folder structure should now look like this ...
Executing the Server
There are 3 steps to follow to run the server.
(1). Initialize the Database
The noteapp
has 2 databases that were pre-configured by Serverpod. The databases are Postgres and Redis; they both have different docker containers which must be up and running to interact with the database.
Execute the command below inside noteapp/noteapp_server/ to start Postgres
and Redis
docker container.
docker compose up --detach --build
(2). Configure Database Client
Now let's connect the database to a database client, I'm using Postbird.
This is the configuration needed to establish a connection with our local database client.
You should transfer this configurations to the database client.
You can see the password is missing.
To get the password for the database; check passwords.yaml
(Don't commit this file to version control for security reasons)
Copy the characters in front of database: and paste it on the password field of the database client. Finally, Save and connect.
Suppose you connected with the database; there is one more step to wrap up this part.
Copy the content of tables-serverpod.pgsql
in noteapp_server/generated
folder into your database client query tab and run the query. Do the same for tables.pgsql
which is in the same folder.
(3). Initiate the Server
Then execute the command below to start Serverpod.
dart bin/main.dart
If you do not follow the instructions you might get stuck with the issue below after executing the preceding command.
Now, you're all set. Let's check the connection.
Expect ouput like this in your terminal.
SERVERPOD version: 1.x.x, mode: development, time: 2022-09-12 17:22:02.825468Z
Insights listening on port 8081
Server default listening on port 8080
Webserver listening on port 8082
Showcasing Server Setup
Let's communicate with the server as we would with any other typical REST API, except in this scenario, there's no need to install an additional HTTP client package to send requests since the client code has already been generated by Serverpod.
We only need to import the generated client code into our Flutter app and then call the endpoints like a normal function with the necessary parameters, Sweet! right?
To demonstrate the server setup, copy the code below and then go to noteapp_flutter
and paste it into lib/main.dart
import 'package:flutter/material.dart';
import 'package:serverpod_flutter/serverpod_flutter.dart';
import 'package:noteapp_client/noteapp_client.dart';
// Sets up a singleton client object that can be used to talk to the server from
// anywhere in our app. The client is generated from your server code.
// The client is set up to connect to a Serverpod running on a local server on
// the default port. You will need to modify this to connect to staging or
// production servers.
var client = Client('http://localhost:8080/')
..connectivityMonitor = FlutterConnectivityMonitor();
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Serverpod Demo',
theme: ThemeData(
useMaterial3: true,
primarySwatch: Colors.yellow,
),
home: const MyHomePage(title: 'Serverpod Note'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
MyHomePageState createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
// This field holds error message that we've received from
// the server or null if none
String? _errorMessage;
final _textEditingController = TextEditingController();
// Calls the `createNote` method of the `note` endpoint. Will set `_errorMessage` field,
// if the call failed.
void _callNote() async {
try {
await client.note.createNote(Note(
data: _textEditingController.text,
date: DateTime.now(),
));
} catch (e) {
setState(() {
_errorMessage = '$e';
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: TextField(
controller: _textEditingController,
decoration: const InputDecoration(
hintText: 'Enter your Note',
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: ElevatedButton(
onPressed: _callNote,
child: const Text('Send to Server'),
),
),
],
),
),
);
}
}
To run the Flutter app; navigate to noteapp_flutter
and execute the command below
flutter run -v
The image below shows my Database client and the Note App. You could see the request got to the database.
Conclusion
Serverpod offers a wide range of powerful features beyond what was discussed in this article. I encourage you to visit the official documentation to explore these capabilities further and stay up-to-date on emerging features and update
In this short article; You've learned:
- What Serverpod framework is about
- How to install and setup the framework
- Resolve a particular issue that might arise while setting up Serverpod
- How to create endpoints
- How CRUD operation is structured and implemented in the framework
- How to deploy your server locally
- Resolve a common issue that might arise
- How to access your created endpoint from Flutter
In case you're wondering if Serverpod is been used in production, I am happy to say yes! some people have reported that they're using it in production. Even the official site was built with serverpod.
What next?
It's highly recommended that you keep an eye on Serverpod insight as at present, it is in the beta stage and has the potential to revolutionize logging and server metrics capabilities.
Once you've experienced the framework's versatility, it's time to flex your muscles and put your skills to the test. Create a simple app and deploy it to a live environment such as AWS or Google Cloud to take full advantage of Serverpod's capabilities.
The configurations are there in the server folder. Try exploring the folders and their contents to get a picture of how Serverpod works.
Resources
- Serverpod documentation site
- Serverpod by geekyants
- Serverpod discussion page.
Bonus
You can even access the endpoints created with Serverpod with any HTTP client of your choice.
Check this discussion to see how to handle that.
Note: I don't recommend this approach as it could be challenging to execute, but I want to make you aware that it's still a possibility
Until next time, cheers for learning a new thing today.
link to this project.
Please share your thoughts on this article with me - I welcome all suggestions and feedback. Your input helps me improve and is greatly appreciated.
Top comments (2)
Thanks for sharing! I learnt a lot from this article!
I am glad it helps.