Crud Operations With Serverpod: A Step-By-Step Guide for Flutter Apps
Tags: flutter, dart, backend, tutorial
Published: 2023-05-07 06:23:49

> *With a matter of little effort you could become a Fullstack developer with [serverpod](https://serverpod.dev/).*


Serverpod is a complete backend framework designed for [Flutter](https://flutter.dev/) with [Dart](https://dart.dev) language. With Serverpod you can build **Endpoints**, **Authentication**, **Job Scheduler**, **Websocket**, and others, check out the list of its capabilities [here](https://docs.serverpod.dev/capabilities).


> 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](https://docs.docker.com/desktop/install) and [Flutter](https://flutter.dev/) 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
```bash
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.

![Serverpod successful installation sample terminal output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oa0csdvaxr30q4cppbvp.png)


## Creating a Project
Let's generate a sample project named `noteapp` and examine its appearance. Execute the command below to create a project.

> _Note :warning:
  > Docker must be up and running before you continue with the next step_. check [here](https://docs.serverpod.dev/#:~:text=Docker.%20Docker%20is%20used%20to%20manage%20Postgres%20and%20(optionally)%20Redis) to see why.

```bash
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.

![Serverpod create issue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p8efmxs3iw7mbehznhp9.png)

_The problem was resolved following the installation of [net-tools](https://github.com/ecki/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](https://pub.dev/packages/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](https://youtu.be/3Q2vKGacfh0) Youtube video by [CodeX](https://www.youtube.com/watch?v=3Q2vKGacfh0&list=PL3wGb9_yWsvLPOvTRl39HQ6Qp0XJwi9dB) and for further information check [here](https://docs.serverpod.dev/tutorials)



---




## 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.

![Before editing server folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bm5jstcsrwgvgbszmf27.png)

> _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 create `note.yaml` and then paste the database configuration below.
    
    ```yaml
    # 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.

    ```bash
    serverpod generate
    ```


- **endpoint**: 

    The endpoint folder as the name suggests consists of our API endpoint codes. delete `example_endpoint.dart` and create `note_endpoint.dart` and then paste the code below.


    ```dart
    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.
    ```bash
    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 ...
    
    ![After editing server folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ggghsunoklhohwyfjkas.png)

---


## 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](https://www.postgresql.org/docs/) and [Redis](https://redis.io/docs/); 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.
 
```bash
docker compose up --detach --build
```

![noteapp_server docker container running](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0pc2cnuuioc2m01njyrg.png)


(2). **Configure Database Client**


Now let's connect the database to a database client, I'm using [Postbird](https://snapcraft.io/postbird).

This is the configuration needed to establish a connection with our local database client.

![Database development flavor config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mw0d7mbmtwdq1c9gf8dw.png)


You should transfer this configurations to the database client.

![Database client with configuration without password](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2afvxnwzg7cujdba16bc.png)

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)

![Database password configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/il2seixhv86pbbqrc15i.png)


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.

![Configuring database connection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0fukidig252fvyyyd6wo.png)

(3). **Initiate the Server**

Then execute the command below to start Serverpod.

```bash
dart bin/main.dart
```

If you do not follow the instructions you might get stuck with the issue below after executing the preceding command.


![Issues starting serverpod](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fbiov9n6k1bukbk4cz1b.png)

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

![Testing server connection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/puj8ykl1iu83o4d6vhhs.png)




## 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` 

```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
```bash
flutter run -v
```

The image below shows my Database client and the  Note App. You could see the request got to the database.



![Demonstrating the note app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnvi64nla8hu6glwdcyh.png)

---


## Conclusion
Serverpod offers a wide range of powerful features beyond what was discussed in this article. I encourage you to visit the official [documentation](https://serverpod.dev) to explore these capabilities further and stay up-to-date on emerging features and update


In this short article; You've learned:
1. What Serverpod framework is  about
2. How to install and setup the framework 
   - Resolve a particular issue that might arise while setting up Serverpod
3. How to create endpoints
4. How CRUD operation is structured and implemented in the framework
5. How to deploy your server locally
   - Resolve a common issue that might arise
6. 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](https://serverpod.dev) was built with serverpod.


## What next?
It's highly recommended that you keep an eye on Serverpod [insight](https://docs.serverpod.dev/#serverpod-insights) as at present, it is in the beta stage and has the potential to revolutionize logging and server metrics capabilities.

![Serverpod metrics](https://serverpod.dev/assets/img/serverpod-screenshot.webp)

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
1. Serverpod documentation [site](https://docs.serverpod.dev/)
2. [Serverpod](https://geekyants.com/blog/serverpod/) by [geekyants](https://geekyants.com)
3. Serverpod [discussion](https://github.com/serverpod/serverpod/discussions) page.


## Bonus
You can even access the endpoints created with Serverpod with any HTTP client of your choice.

Check [this](https://github.com/serverpod/serverpod/discussions/100#discussioncomment-2447775) 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_

![how to use postman with serverpod](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/de9e0rih8pcdionpv3bs.png)





<br>
Until next time, cheers for learning a new thing today.

[link](https://github.com/mathiasgodwin/noteapp) 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._