Dart and Cloud Run
Tags: programming, computerscience, productivity, googlecloud
Published: 2021-06-04 00:36:12

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>

<!-- wp:paragraph -->
<p>We will cover briefly:</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>Writing dart server API</li><li>Deploying on Cloud Run</li></ol>
<!-- /wp:list -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Note: This article assumes the reader knows about Cloud Run, and GCP.</p></blockquote>
<!-- /wp:quote -->

{% youtube mLHP_DHgBa4 %}

<!-- wp:heading {"level":3} -->
<h3>Writing dart server&nbsp;API</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Upgrade to the latest version of <a href="https://medium.com/dartlang/announcing-dart-2-13-c6d547b57067" target="_blank" rel="noreferrer noopener">Dart 2.13</a></p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/0*cT2tk0mBdCvuD54g.png" alt=""/><figcaption>Dart version&nbsp;2.13</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>There are two ways of writing server API</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>Manually create each file, place them correctly, and fail</li><li>Use a scaffolding (a pre defined folder structure with minimum necessary files)</li></ol>
<!-- /wp:list -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p><strong>We will go with point 2</strong></p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p><a href="https://pub.dev/packages/stagehand/install" rel="noreferrer noopener" target="_blank">Introducing Stagehand</a>&nbsp;: A Dart Project Generator</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*gAlhVSCHWWD2Hn9vemtPUg.png" alt="Stagehand"/><figcaption>Stagehand</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>This will help us in getting all the necessary files packed together in a folder.</li><li>Install this via</li></ul>
<!-- /wp:list -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted"><code>dart pub global activate stagehand</code></pre>
<!-- /wp:preformatted -->

<!-- wp:list -->
<ul><li>Once installed, you have now access to following generator commands</li></ul>
<!-- /wp:list -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*H25v12PPEURVs9Ef0LuykA.png" alt="Stagehand generators"/><figcaption>Stagehand generators</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>For our case we will go with</li></ul>
<!-- /wp:list -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">stagehand server-shelf</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>and we get the folder structure as&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*FH5SCewvemFd56-YMolcsw.png" alt="Web server folder structure"/><figcaption>Web server folder structure</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>Looking into the <strong>pubspec.yaml,</strong> we have the dependencies for <a href="https://pub.dev/packages/shelf" rel="noreferrer noopener" target="_blank"><strong>shelf</strong></a> and <a href="https://pub.dev/packages/args" rel="noreferrer noopener" target="_blank"><strong>args</strong></a></li></ul>
<!-- /wp:list -->

<!-- wp:image {"align":"center"} -->
<div class="wp-block-image"><figure class="aligncenter"><img src="https://cdn-images-1.medium.com/max/1600/1*D0csRiBGwHrtq50bjZ5BuA.png" alt="pubspec"/><figcaption>pubspec</figcaption></figure></div>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>For package args:&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>It is useful for command line applications, where we supply arguments</li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":4} -->
<h4>What is&nbsp;Shelf?</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>It helps to create and compose web servers.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;

// For Google Cloud Run, set _hostname to '0.0.0.0'
const _hostname = '0.0.0.0';

void main() async {
  var handler =
      const  Pipeline().addMiddleware(logRequests()).addHandler(_echoRequest);
var server = await shelf_io.serve(handler, _hostname, 8080);
}
Response _echoRequest(Request request) =&gt;
    Response.ok('Hello world');</pre>
<!-- /wp:preformatted -->

<!-- wp:list -->
<ul><li>Package shelf is imported by default inside our <strong>server.dart</strong></li><li>We create a handler <strong>_echoRequest</strong></li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>A handler is basically something that handles a request (<a href="https://pub.dev/documentation/shelf/latest/shelf/Request-class.html" rel="noreferrer noopener" target="_blank">shelf.Request</a>) and gives back a response (<a href="https://pub.dev/documentation/shelf/latest/shelf/Response-class.html" rel="noreferrer noopener" target="_blank">shelf.Response</a>)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In our case, we return the response as <strong>“Hello World”.</strong></p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>Let’s say we want to log the requests(<strong>logRequests</strong>) to our api, we need to add another handler.</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Here comes the concept of <a href="https://pub.dev/documentation/shelf/latest/shelf/Pipeline-class.html" rel="noreferrer noopener" target="_blank">Pipeline</a></p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Pipeline is a combination of middleware and a handler.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:list -->
<ul><li>We add in the <a href="https://pub.dev/documentation/shelf/latest/shelf/logRequests.html" rel="noreferrer noopener" target="_blank"><strong>logRequests</strong></a>, which is predefined inside the shelf.</li></ul>
<!-- /wp:list -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Think of middleware as a function that takes a handler and wraps it in another handler to provide additional functionality</p></blockquote>
<!-- /wp:quote -->

<!-- wp:list -->
<ul><li>To start the server, we call in the <a href="https://pub.dev/documentation/shelf/latest/shelf_io/serve.html" rel="noreferrer noopener" target="_blank">serve</a> function.&nbsp;</li></ul>
<!-- /wp:list -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Starts an <a href="https://api.dart.dev/stable/2.13.1/dart-io/HttpServer-class.html" rel="noreferrer noopener" target="_blank">HttpServer</a> that listens on the specified <code>address</code> and <code>port</code> and sends requests to <code>handler</code>.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p><strong>handler</strong>: defined earlier</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>address</strong>: We are using 0.0.0.0 (for cloud run, see next step)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>port</strong>: 8080</p>
<!-- /wp:paragraph -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:heading {"level":3} -->
<h3>Deploying on Cloud&nbsp;Run</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>It was announced in Google I/O 2021, that Dart is now available as <a href="https://docs.docker.com/docker-hub/official_images/" rel="noreferrer noopener" target="_blank">Docker Official Images</a>.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>According to the announcement</p>
<!-- /wp:paragraph -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>“The <a href="https://hub.docker.com/_/dart" rel="noreferrer noopener" target="_blank">new Dart images</a> are tested and validated by Docker to follow best practices”.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>They also support ahead-of-time (AOT) compilation, which can dramatically reduce the size of built containers and can improve the speed of deployment in container environments — like <a href="https://cloud.google.com/run" rel="noreferrer noopener" target="_blank">Cloud Run</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:paragraph -->
<p>Let’s deploy our <strong>hello_world</strong> application now</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>Create a docker file and put the contents from <a href="https://hub.docker.com/_/dart" rel="noreferrer noopener" target="_blank">here</a></li><li>We will be building a docker image using the command</li></ul>
<!-- /wp:list -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">docker build -t hello_world .</pre>
<!-- /wp:preformatted -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Note: This requires the docker to be installed on your machine. <a href="https://docs.docker.com/get-docker/" rel="noreferrer noopener" target="_blank">Refer this</a></p></blockquote>
<!-- /wp:quote -->

<!-- wp:list -->
<ul><li>Run the image (you built from step2) locally using</li></ul>
<!-- /wp:list -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">docker run -it -p 8080:8080 \hello_world:latest</pre>
<!-- /wp:preformatted -->

<!-- wp:list -->
<ul><li>When tested, you can stop the container using</li></ul>
<!-- /wp:list -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">// For getting container id, you can use
docker ps

docker stop [YOUR CONTAINER ID]</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>Time to <strong>deploy this image</strong>(from above), to Cloud Run.</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>Make sure you have the Google Cloud SDK installed on your machine. <a href="https://cloud.google.com/sdk/docs/install" rel="noreferrer noopener" target="_blank">Refer this</a>.</li></ul>
<!-- /wp:list -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Note: You also need a GCP project with billing enabled.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:list -->
<ul><li>Authenticate your user account with the gcloud CLI using</li></ul>
<!-- /wp:list -->

<!-- wp:code -->
<pre class="wp-block-code"><code><a href="https://cloud.google.com/sdk/gcloud/reference/auth/login" rel="noreferrer noopener" target="_blank">gcloud auth login</a></code></pre>
<!-- /wp:code -->

<!-- wp:list -->
<ul><li>List your projects and set the preferred project</li></ul>
<!-- /wp:list -->

<!-- wp:code -->
<pre class="wp-block-code"><code>// List your GCP projects
gcloud projects list

// Set your project
gcloud config set project \
'YOUR PROJECT ID'</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Now we need to publish our image inside the <a href="https://cloud.google.com/container-registry" rel="noreferrer noopener" target="_blank">Google Container Registry</a> (storing our docker image in GCP) using</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>gcloud builds submit --tag gcr.io/&#91;YOUR-PROJECT-ID]/hello_world
// Replace &#91;YOUR-PROJECT-ID] with your project id</code></pre>
<!-- /wp:code -->

<!-- wp:list -->
<ul><li>Finally, we deploy this container image to Cloud Run using</li></ul>
<!-- /wp:list -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">gcloud run deploy --image gcr.io/[YOUR-PROJECT-ID]/hello_world
// Replace [YOUR-PROJECT-ID] with your project id</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p><a href="https://cloud.google.com/sdk/gcloud/reference/run/deploy" rel="noreferrer noopener" target="_blank">Reference to commands here</a></p>
<!-- /wp:paragraph -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:list -->
<ul><li>If all successful, you will see an endpoint after the previous step.</li></ul>
<!-- /wp:list -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Endpoint (for my case): <a href="https://helloworld-rahizluroq-uc.a.run.app" rel="noreferrer noopener" target="_blank">https://helloworld-rahizluroq-uc.a.run.app</a></p></blockquote>
<!-- /wp:quote -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:heading {"level":4} -->
<h4>What’s next</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Dart team is bringing the <a href="https://pub.dev/packages/functions_framework" rel="noreferrer noopener" target="_blank">Functions Framework for Dart</a>,&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>a collection of packages, tools, and examples to write Dart functions to deploy for handling HTTP requests and CloudEvents.</li></ul>
<!-- /wp:list -->

{% youtube mLHP_DHgBa4 %}

<!-- wp:paragraph -->
<a href="https://github.com/AseemWangoo/flutter_programs/blob/master/dart_on_server.zip" rel="noreferrer noopener" target="_blank">Source Code</a>
<!-- /wp:paragraph -->

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>