Building Dart APIs with Google Cloud Run
Learn how to build backend applications using Dart and Google Cloud Run. By Alhassan Kamil.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Building Dart APIs with Google Cloud Run
30 mins
- Getting Started
- Running Your First Dart API Server
- Setting up a Google Cloud Project
- Creating the Project
- Creating a Service Account
- Setting up Billing
- An Overview of REST APIs
- Developing the API Endpoints
- Designing Endpoints
- Implementing the UserRoutes Endpoints
- Adding the NoteRoutes Endpoints
- Creating the AppRoutes Endpoints
- Testing the Routes
- Writing Controller Logic
- UserController
- NoteController
- Adding Middleware
- Response Headers Middleware
- Authentication Middleware
- Deploying Your Dart API on Google Cloud Run
- Installing Google Cloud CLI
- Configuring the Dockerfile
- Deploying to Cloud Run
- Accessing Your Dart REST API
- Where to Go From Here
As a Flutter developer, you have a robust framework for developing cross-platform, front-end apps. How cool would it be if you could reuse your knowledge in Dart to create backend applications?
Well, you can! In this tutorial you’re going to build MNote, a note management API that any Flutter app can consume. In the process, you’ll learn how to:
- Develop and run servers in Dart using the shelf and shelf_router packages.
- Intercept and manipulate HTTP requests and responses using middleware.
- Create a Docker image for your project.
- Deploy a Dart API on Google Cloud Run.
Getting Started
Download the project by clicking the Download Materials button at the top or bottom of this tutorial and extract it to a suitable location. This tutorial uses VS Code, but you can use any text editor/IDE.
Open the starter project; its structure should look like this:
In summary:
- bin/mnote.dart is the entrypoint that bootstraps and serves the application.
- lib/controllers/note_controller.dart contains logic for managing notes.
- lib/controllers/user_controller.dart holds user authentication logic.
- lib/helpers: Utility functions (helper.dart) and middleware (middleware.dart) are here.
- lib/models: Contains model files.
- lib/routes/app_routes.dart holds top-level app routes definitions.
- lib/routes/note_routes.dart defines note routes.
- lib/routes/user_routes.dart has definitions for user routes.
Since you now understand the project structure, you’re ready to run it.
Running Your First Dart API Server
While at the root of the starter project, open a new terminal or PowerShell window. Next, run the following to download packages:
dart pub get
Then, start the server using:
dart run
The above command runs bin/mnote.dart, which bootstraps and starts the server. Once the server is running, you’ll see an output like the one below:
That means your server is listening for connections.
Open a new terminal window and enter:
curl http://localhost:8080
curl.exe
instead of curl
on Windows. Install cURL if you get an error that it’s not installed.
Click Enter and you should see an output similar to the one below:
Congratulations on successfully running your first Dart server!
Let’s see how the output came about.
Since bin/mnote.dart is basically your server, you may want to take a little look into what’s in there to produce such result. Don’t hesitate, open it and have a look at main()
:
// 1
final app = Router();
app.get('/', (Request request) {
final aboutApp = {
'name': 'MNote',
'version': 'v1.0.0',
'description': 'A minimal note management API to take and save notes'
};
return Response.ok(jsonEncode(aboutApp));
});
// 2
final handler = const Pipeline().addMiddleware(logRequests()).addHandler(app);
// 3
final mServer = await server.serve(handler, InternetAddress.anyIPv4, 8080);
// 4
print('Server started at http://${mServer.address.host}:${mServer.port}');
There you have it! :]
This is what each part does:
- Creates a Router. A router ensures that requests entering the application get mapped to functions (correctly called handlers) that can process them. In the case above, it routes any HTTP GET requests on the path
/
to the second handler argument which basically returns a JSON response. - Constructs a Pipeline handler that adds a logging middleware and registers the router.
- Creates a server with the
handler
that listens for requests from all available addresses on port 8080. - Lastly, prints that the server is listening on the given address-port combination.
Great, you now have a basic server. But this can’t authenticate users and manage notes. In the later sections, you’ll solve that. For now, let’s set up a Google Cloud project.
Setting up a Google Cloud Project
You’ll deploy MNote on Google Cloud Run, a service which is part of the Google Cloud Platform (GCP). So you need to have an active Google Cloud account with billing enabled to proceed.
Creating the Project
You’ll use Cloud Firestore to store notes and user information. As a result, you have to create a Firebase project as that automatically creates a Google Cloud project.
So, navigate to https://console.firebase.google.com and click Create a project:
Next, enter MNote into Project name, accept the terms and click Continue:
The next page asks you to enable Google Analytics, disable it and click Create project:
After a few seconds, the project should be ready. Click Continue:
The project’s Overview page opens. Click the Web button under Get started by adding Firebase to your app:
Enter “MNote” into App nickname and click Register app:
Next, click Continue to console:
Back in the console, click Cloud Firestore under Choose a product to add to your app:
Now click Create database, select Start in production mode and click Next:
Finaly, set the database location and click Enable:
Now the project is ready to use Cloud Firestore. But you’ll need to create a service account to access it in your code.
Creating a Service Account
A service account allows automated access to Google APIs data in place of an API user. So, while in Firebase console, go ahead and click ⚙️ besides Project Overview at the top of the sidebar, then click Project settings:
The Project settings page opens. Select the Service accounts tab and click Generate new private key:
Click Generate key on the Generate new private key dialog to generate and download the service account JSON file:
Open the downloaded file in a text editor.
In bin/mnote.dart, add a getCredentials()
function above main()
with the following code:
import 'package:googleapis_auth/auth_io.dart';
ServiceAccountCredentials getCredentials() {
return ServiceAccountCredentials.fromJson({
'private_key_id': '<key ID from service account file>',
'private_key': '<Your project\'s service account private key>',
'client_email': '[something@].gserviceaccount.com',
'client_id': '<ID from service account file>',
'type': 'service_account'
});
}
Replace the following in the function:
-
with the corresponding private_key_id value from the service account file you downloaded. -
with the private_key value. - [something@].gserviceaccount.com with the client_email value.
- And
with the client_id value.
Lastly, replace the value of projectId
in lib/helpers/helper.dart with the project_id value from the service account file:
static const projectId = 'mnote-c7379';
Now you can use Cloud Firestore in your code. Set up billing for the project to finish up.