DEV Community

Cover image for Crud Operations With Serverpod: A Step-By-Step Guide for Flutter Apps
Godwin Mathias
Godwin Mathias

Posted on

Crud Operations With Serverpod: A Step-By-Step Guide for Flutter Apps

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
Enter fullscreen mode Exit fullscreen mode

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

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
Enter fullscreen mode Exit fullscreen mode

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

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.

Before editing server 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 create note.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 create note_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 ...

    After editing server folder structure


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
Enter fullscreen mode Exit fullscreen mode

noteapp_server docker container running

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

Database development flavor config

You should transfer this configurations to the database client.

Database client with configuration without password

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

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

(3). Initiate the Server

Then execute the command below to start Serverpod.

dart bin/main.dart
Enter fullscreen mode Exit fullscreen mode

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

Issues starting serverpod

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

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'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

To run the Flutter app; navigate to noteapp_flutter and execute the command below

flutter run -v
Enter fullscreen mode Exit fullscreen mode

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

Demonstrating the note app


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:

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

Serverpod metrics

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
  2. Serverpod by geekyants
  3. 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

how to use postman with serverpod



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)

Collapse
 
frank1016 profile image
Frank

Thanks for sharing! I learnt a lot from this article!

Collapse
 
mathiasgodwin profile image
Godwin Mathias

I am glad it helps.