<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Roberto Huertas</title>
    <description>The latest articles on DEV Community by Roberto Huertas (@robertohuertasm).</description>
    <link>https://dev.to/robertohuertasm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F152108%2F440b5907-4824-4427-9cde-a80f62067381.jpg</url>
      <title>DEV Community: Roberto Huertas</title>
      <link>https://dev.to/robertohuertasm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/robertohuertasm"/>
    <language>en</language>
    <item>
      <title>Send the logs of your Shuttle-powered backend to Datadog</title>
      <dc:creator>Roberto Huertas</dc:creator>
      <pubDate>Fri, 29 Sep 2023 22:00:00 +0000</pubDate>
      <link>https://dev.to/robertohuertasm/send-the-logs-of-your-shuttle-powered-backend-to-datadog-156d</link>
      <guid>https://dev.to/robertohuertasm/send-the-logs-of-your-shuttle-powered-backend-to-datadog-156d</guid>
      <description>&lt;p&gt;Learn how to send logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; from your &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; powered backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some words about observability
&lt;/h2&gt;

&lt;p&gt;As we all know, being able to ‘&lt;em&gt;see&lt;/em&gt;’ what’s going on in our services can be critical in many ways. We can easily find bugs or identify undesired behaviors, and it’s certainly an invaluable tool at our disposal.&lt;/p&gt;

&lt;p&gt;Observability, in software, refers to the &lt;strong&gt;ability to understand the state of a system and its behavior&lt;/strong&gt; by collecting, analyzing, and presenting data about its various components and interactions. This enables engineers to diagnose and resolve issues and make informed decisions about system health and performance.&lt;/p&gt;

&lt;p&gt;Observability is &lt;strong&gt;critical for ensuring the reliability, scalability, and performance&lt;/strong&gt; of modern systems, and is becoming increasingly important as software continues to play a larger role in our daily lives.&lt;/p&gt;

&lt;p&gt;Fortunately, in the Rust ecosystem, we have &lt;a href="https://docs.rs/tracing/latest/tracing/" rel="noopener noreferrer"&gt;Tokio Tracing&lt;/a&gt; which is a powerful framework for &lt;strong&gt;instrumenting&lt;/strong&gt; Rust programs to collect structured, event-based diagnostic information. It provides a convenient and flexible API for collecting and viewing traces of events in your application and you can easily &lt;strong&gt;add context and structure to your traces&lt;/strong&gt;, making it easier to identify bottlenecks and debug issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shuttle logs
&lt;/h2&gt;

&lt;p&gt;A few months ago, I wrote a &lt;a href="https://dev.to/robertohuertasm/build-and-deploy-a-rust-backend-with-shuttle-5d7c"&gt;post&lt;/a&gt; about &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt;, where I explained how ridiculously easy it is to deploy a Rust backend to the cloud by using their &lt;a href="https://docs.shuttle.rs/introduction/quick-start" rel="noopener noreferrer"&gt;CLI tool&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; is still in beta, and although its observability features are not really polished yet, they offer &lt;a href="https://docs.shuttle.rs/introduction/telemetry" rel="noopener noreferrer"&gt;support&lt;/a&gt; for &lt;a href="https://docs.rs/tracing/latest/tracing/" rel="noopener noreferrer"&gt;Tokio Tracing&lt;/a&gt; and a way to &lt;a href="https://docs.shuttle.rs/introduction/telemetry#viewing-logs" rel="noopener noreferrer"&gt;view logs&lt;/a&gt; by using their CLI tool.&lt;/p&gt;

&lt;p&gt;By simply running &lt;code&gt;cargo shuttle logs --follow&lt;/code&gt;, you will be able to see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fshuttle-datadog%2Fshuttle-cli-logs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fshuttle-datadog%2Fshuttle-cli-logs.png" alt="shuttle logs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is great for simple applications, but what if you want to send your logs to a &lt;strong&gt;more powerful tool&lt;/strong&gt; like &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;? Well, in this post, &lt;strong&gt;I’ll show you how to do it&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Datadog
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; is a &lt;strong&gt;monitoring and observability platform&lt;/strong&gt; that provides a &lt;strong&gt;single pane of glass&lt;/strong&gt; for your infrastructure and applications. It is a &lt;strong&gt;cloud-based&lt;/strong&gt; service that allows you to &lt;strong&gt;collect, aggregate and analyze&lt;/strong&gt; your data, and it is &lt;strong&gt;extremely powerful&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a disclaimer, I must say that I’m currently working at &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;, so I’m a bit biased, but I’m also a huge fan of the product and I think it’s a great tool for developers 😅.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most of the time, the easiest way to send anything to the &lt;a href="https://www.datadoghq.com/observability-platform/" rel="noopener noreferrer"&gt;Datadog platform&lt;/a&gt; is by using the &lt;a href="https://docs.datadoghq.com/agent/" rel="noopener noreferrer"&gt;Datadog Agent&lt;/a&gt;, but in this case, as &lt;strong&gt;we cannot install it&lt;/strong&gt; in any way, we will use a &lt;strong&gt;small library I created for the occasion&lt;/strong&gt; called &lt;a href="https://crates.io/crates/dd-tracing-layer" rel="noopener noreferrer"&gt;dd-tracing-layer&lt;/a&gt;, which happens to be using the &lt;a href="https://docs.datadoghq.com/api/latest/logs/" rel="noopener noreferrer"&gt;Datadog HTTP API&lt;/a&gt; under the hood to send logs to the &lt;a href="https://www.datadoghq.com/observability-platform/" rel="noopener noreferrer"&gt;Datadog platform&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use tracing with Shuttle
&lt;/h2&gt;

&lt;p&gt;If we check the &lt;a href="https://docs.shuttle.rs/configuration/logs" rel="noopener noreferrer"&gt;Shuttle documentation&lt;/a&gt;, we can read this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Shuttle will record anything your application writes to stdout, e.g. a tracing or log crate configured to write to stdout, or simply println!. By default, Shuttle will set up a global tracing subscriber behind the scenes.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// [...]&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[shuttle_runtime::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;#[shuttle_shared_db::Postgres]&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PgPool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ShuttleAxum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nd"&gt;info!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Running database migration"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="nf"&gt;.execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;include_str!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../schema.sql"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;.await&lt;/span&gt;
        &lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;CustomError&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// [...]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, as you can see, it seems that the Shuttle macro is already instantiating and initializing a &lt;a href="https://docs.rs/tracing/latest/tracing/trait.Subscriber.html" rel="noopener noreferrer"&gt;tracing subscriber&lt;/a&gt; for us.&lt;/p&gt;

&lt;p&gt;This is pretty &lt;strong&gt;convenient for most of the simple cases&lt;/strong&gt;, but unfortunately, it’s not enough for our purposes.&lt;/p&gt;

&lt;p&gt;Ideally, if we had access to the underlying infrastructure, we could probably install the &lt;a href="https://docs.datadoghq.com/agent/" rel="noopener noreferrer"&gt;Datadog Agent&lt;/a&gt; and configure it to send our logs directly to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;, or even use &lt;a href="https://docs.datadoghq.com/logs/guide/send-aws-services-logs-with-the-datadog-lambda-function/?tab=awsconsole" rel="noopener noreferrer"&gt;AWS Lambda functions&lt;/a&gt; or &lt;a href="https://docs.datadoghq.com/integrations/azure/?tab=azurecliv20#log-collection" rel="noopener noreferrer"&gt;Azure Event Hub + Azure Functions&lt;/a&gt; in case we were facing some specific cloud scenarios.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can check the &lt;a href="https://docs.datadoghq.com/logs/log_collection/" rel="noopener noreferrer"&gt;Datadog docs for log collection and integrations&lt;/a&gt; if you want to learn more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those solutions are generally great because they allow us to remove the burden of sending our logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; from our application, thus becoming the &lt;strong&gt;responsibility of the platform&lt;/strong&gt; itself.&lt;/p&gt;

&lt;p&gt;If we could do something like that with &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt;, it would be great. But, as we just mentioned, in the case of &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt;, we &lt;strong&gt;don’t have access to the underlying infrastructure&lt;/strong&gt;, so we need to find a way to send our logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; from our application.&lt;/p&gt;

&lt;p&gt;And that’s what we are going to try to do in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting access to the subscriber
&lt;/h2&gt;

&lt;p&gt;So, the basic idea is to add a new &lt;a href="https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/" rel="noopener noreferrer"&gt;tracing layer&lt;/a&gt; to the subscriber which will be responsible for sending our logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But for that, we’ll need to get &lt;strong&gt;access to the subscriber instance prior to its initialization&lt;/strong&gt;, and it turns out that &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; provides a way to do that just by disabling the default features on &lt;code&gt;shuttle-runtime&lt;/code&gt; crate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;shuttle-runtime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="py"&gt;default-features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating our project
&lt;/h2&gt;

&lt;p&gt;As a walkthrough, we are going to create a new &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; project from scratch.&lt;/p&gt;

&lt;p&gt;The idea is to build a simple REST API using &lt;a href="https://docs.rs/axum/latest/axum/" rel="noopener noreferrer"&gt;Axum&lt;/a&gt; and send our logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; using the &lt;a href="https://crates.io/crates/dd-tracing-layer" rel="noopener noreferrer"&gt;dd-tracing-layer&lt;/a&gt; crate.&lt;/p&gt;

&lt;p&gt;Although I’m going to describe all the steps you need to take to make this work, you can see the &lt;strong&gt;final state of the project&lt;/strong&gt; in this &lt;a href="https://github.com/robertohuertasm/shuttle-datadog-logs" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to use it as a reference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initializing the project
&lt;/h3&gt;

&lt;p&gt;First of all, we need to create a new &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; project. You can do that by using the &lt;a href="https://docs.shuttle.rs/getting-started/cli" rel="noopener noreferrer"&gt;Shuttle CLI&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo shuttle init &lt;span class="nt"&gt;--template&lt;/span&gt; axum
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the instructions and you should have a new project ready to go. I called mine &lt;code&gt;shuttle-datadog-logs&lt;/code&gt;, but use the name you want.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding some dependencies
&lt;/h3&gt;

&lt;p&gt;In our example, we are going to be using &lt;a href="https://docs.shuttle.rs/resources/shuttle-secrets" rel="noopener noreferrer"&gt;Shuttle Secrets&lt;/a&gt;, &lt;a href="https://docs.rs/tracing/latest/tracing/" rel="noopener noreferrer"&gt;Tokio Tracing&lt;/a&gt; and &lt;a href="https://crates.io/crates/dd-tracing-layer" rel="noopener noreferrer"&gt;dd-tracing-layer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Make sure you have the following dependencies in your &lt;code&gt;Cargo.toml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;axum&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.6"&lt;/span&gt;
&lt;span class="py"&gt;shuttle-axum&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.27.0"&lt;/span&gt;
&lt;span class="py"&gt;shuttle-runtime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.27.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;default-features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;tokio&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;
&lt;span class="c"&gt;# tracing&lt;/span&gt;
&lt;span class="py"&gt;tracing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1"&lt;/span&gt;
&lt;span class="py"&gt;tracing-subscriber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"env-filter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"time"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;dd-tracing-layer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1"&lt;/span&gt;
&lt;span class="c"&gt;# secrets&lt;/span&gt;
&lt;span class="py"&gt;shuttle-secrets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.27.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Instrumenting a little bit the default project
&lt;/h3&gt;

&lt;p&gt;Now that we have our dependencies ready, we can &lt;strong&gt;start instrumenting&lt;/strong&gt; our project a little bit.&lt;/p&gt;

&lt;p&gt;Note that we have added the &lt;code&gt;#[instrument]&lt;/code&gt; macro to the &lt;code&gt;hello_world&lt;/code&gt; function and added a &lt;code&gt;tracing::info!&lt;/code&gt; and a &lt;code&gt;tracing::debug!&lt;/code&gt; log to it. We have also added an info log to the &lt;code&gt;axum&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// [...]&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[instrument]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;info!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Saying hello"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;debug!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Saying hello for debug level only"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="s"&gt;"Hello, world!"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[shuttle_runtime::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;shuttle_axum&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ShuttleAxum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;info!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting axum service"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, if you try to run the project locally by using the &lt;code&gt;shuttle run&lt;/code&gt; command, you should see none of our logs.&lt;/p&gt;

&lt;p&gt;That’s ok, as we haven’t initialized a &lt;a href="https://docs.rs/tracing/latest/tracing/trait.Subscriber.html" rel="noopener noreferrer"&gt;tracing subscriber&lt;/a&gt; yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding our tracing subscriber
&lt;/h3&gt;

&lt;p&gt;The first thing we’re going to do is to add a &lt;a href="https://docs.rs/tracing/latest/tracing/trait.Subscriber.html" rel="noopener noreferrer"&gt;tracing subscriber&lt;/a&gt; to our application.&lt;/p&gt;

&lt;p&gt;Then we will add several &lt;a href="https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/index.html" rel="noopener noreferrer"&gt;layers&lt;/a&gt; to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html" rel="noopener noreferrer"&gt;EnvFilter layer&lt;/a&gt; to set the tracing level according to a variable’s value.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/format/index.html" rel="noopener noreferrer"&gt;Format layer&lt;/a&gt; to format the logs. We will be using JSON format.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.rs/dd-tracing-layer/" rel="noopener noreferrer"&gt;Datadog Tracing layer&lt;/a&gt; to send our logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apart from that, we’re also going to add support for &lt;a href="https://docs.shuttle.rs/resources/shuttle-secrets" rel="noopener noreferrer"&gt;Shuttle Secrets&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s do it! Make sure your &lt;code&gt;axum&lt;/code&gt; function looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;routing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;dd_tracing_layer&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;DatadogOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Region&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;shuttle_secrets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SecretStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tracing_subscriber&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// version of our app to be sent to Datadog&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"version:0.1.0"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// [...]&lt;/span&gt;

&lt;span class="nd"&gt;#[shuttle_runtime::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;#[shuttle_secrets::Secrets]&lt;/span&gt; &lt;span class="n"&gt;secret_store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SecretStore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;shuttle_axum&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ShuttleAxum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// getting the Datadog Key from the secrets&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dd_api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secret_store&lt;/span&gt;
        &lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DD_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DD_API_KEY not found"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// getting the Datadog tags from the secrets&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secret_store&lt;/span&gt;
        &lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DD_TAGS"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{},{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VERSION&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="c1"&gt;// getting the log level from the secrets and defaulting to info&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;log_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secret_store&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LOG_LEVEL"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INFO"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="c1"&gt;// datadog tracing layer&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dd_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;dd_tracing_layer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nn"&gt;DatadogOptions&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="c1"&gt;// first parameter is the name of the service&lt;/span&gt;
            &lt;span class="s"&gt;"shuttle-datadog-logs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="c1"&gt;// this is the Datadog API Key&lt;/span&gt;
            &lt;span class="n"&gt;dd_api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// this is the default, so it can be omitted&lt;/span&gt;
        &lt;span class="nf"&gt;.with_region&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Region&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;US1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// adding some optional tags&lt;/span&gt;
        &lt;span class="nf"&gt;.with_tags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// filter layer&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;filter_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="nn"&gt;tracing_subscriber&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;EnvFilter&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to set log level"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// format layer&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;fmt_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;tracing_subscriber&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.with_ansi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.with_timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;tracing_subscriber&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;UtcTime&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;rfc_3339&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.flatten_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.with_target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.with_span_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// starting the tracing subscriber&lt;/span&gt;
    &lt;span class="nn"&gt;tracing_subscriber&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter_layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt_layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dd_layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// starting the server&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;info!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting axum service"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="nf"&gt;. Into&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are many things going on in this code, so take your time to go through it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secrets
&lt;/h3&gt;

&lt;p&gt;Before running our project, there's still a thing we have to deal with: &lt;strong&gt;secrets&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As you can see in the code above, we are using the &lt;a href="https://docs.shuttle.rs/resources/shuttle-secrets" rel="noopener noreferrer"&gt;Shuttle Secrets&lt;/a&gt; crate to get the &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; API key, the tags and the log level.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.shuttle.rs/resources/shuttle-secrets" rel="noopener noreferrer"&gt;Shuttle Secrets&lt;/a&gt; relies on having a &lt;code&gt;Secrets.toml&lt;/code&gt; file in the root of our project containing all the secrets, and it also supports having a &lt;code&gt;Secrets.dev.toml&lt;/code&gt; file for local development. You can learn more about this convention in the &lt;a href="https://docs.shuttle.rs/resources/shuttle-secrets#local-secrets" rel="noopener noreferrer"&gt;Shuttle Secrets documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, let's create two files in the root of our project:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Secrets.dev.toml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;DD_API_KEY&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"21695c1b35156511441c0d3ace5943f4"&lt;/span&gt;
&lt;span class="py"&gt;DD_TAGS&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"env:dev,service:shutle-datadog-logs"&lt;/span&gt;
&lt;span class="c"&gt;# setting info as the default log level, but debug for our project&lt;/span&gt;
&lt;span class="py"&gt;LOG_LEVEL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="py"&gt;"INFO,shuttle_datadog_logs&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;DEBUG&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and &lt;code&gt;Secrets.toml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;DD_API_KEY&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"21695c1b35156511441c0d3ace5943f4"&lt;/span&gt;
&lt;span class="py"&gt;DD_TAGS&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"env:prod,service:shutle-datadog-logs"&lt;/span&gt;
&lt;span class="py"&gt;LOG_LEVEL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"INFO"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Remember to add these files to your &lt;code&gt;.gitignore&lt;/code&gt; file!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Running the project
&lt;/h3&gt;

&lt;p&gt;Now, run &lt;code&gt;cargo shuttle run&lt;/code&gt; and go to &lt;code&gt;http://localhost:8000&lt;/code&gt; in your browser to see our "Hello, world!" message.&lt;/p&gt;

&lt;p&gt;Alternatively, you can also use &lt;code&gt;curl&lt;/code&gt; to test the endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://localhost:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should be able to see the logs in your terminal now.&lt;/p&gt;

&lt;p&gt;But remember... this endpoint was instrumented! So, if everything went well, we should be able to see the logs in &lt;a href="https://app.datadoghq.com/logs" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s check it out! 👀&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fshuttle-datadog%2Fdatadog-logs-local.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fshuttle-datadog%2Fdatadog-logs-local.png" alt="Datadog logs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It works! 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As you can see, it’s pretty easy to send your logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; from your &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; powered backend.&lt;/p&gt;

&lt;p&gt;Again, you can see the full code in &lt;a href="https://github.com/robertohuertasm/shuttle-datadog-logs" rel="noopener noreferrer"&gt;this GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope you’ve enjoyed it! 😁&lt;/p&gt;

</description>
      <category>rust</category>
      <category>datadog</category>
      <category>shuttle</category>
      <category>observability</category>
    </item>
    <item>
      <title>Send the logs of your Shuttle-powered backend to Datadog (outdated)</title>
      <dc:creator>Roberto Huertas</dc:creator>
      <pubDate>Tue, 31 Jan 2023 23:00:00 +0000</pubDate>
      <link>https://dev.to/robertohuertasm/send-the-logs-of-your-shuttle-powered-backend-to-datadog-3imo</link>
      <guid>https://dev.to/robertohuertasm/send-the-logs-of-your-shuttle-powered-backend-to-datadog-3imo</guid>
      <description>&lt;blockquote&gt;
&lt;h2&gt;
  
  
  IMPORTANT: This post is OUTDATED. Visit the &lt;a href="https://robertohuertas.com/2023/09/30/shuttle-datadog-logs/" rel="noopener noreferrer"&gt;reviewed version&lt;/a&gt;.
&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;Learn how to send logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; from your &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; powered backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some words about observability
&lt;/h2&gt;

&lt;p&gt;As we all know, being able to ‘&lt;em&gt;see&lt;/em&gt;’ what’s going on in our services can be critical in many ways. We can easily find bugs or identify undesired behaviors, and it’s certainly an invaluable tool at our disposal.&lt;/p&gt;

&lt;p&gt;Observability, in software, refers to the &lt;strong&gt;ability to understand the state of a system and its behavior&lt;/strong&gt; by collecting, analyzing, and presenting data about its various components and interactions. This enables engineers to diagnose and resolve issues and make informed decisions about system health and performance.&lt;/p&gt;

&lt;p&gt;Observability is &lt;strong&gt;critical for ensuring the reliability, scalability, and performance&lt;/strong&gt; of modern systems, and is becoming increasingly important as software continues to play a larger role in our daily lives.&lt;/p&gt;

&lt;p&gt;Fortunately, in the Rust ecosystem, we have &lt;a href="https://docs.rs/tracing/latest/tracing/" rel="noopener noreferrer"&gt;Tokio Tracing&lt;/a&gt; which is a powerful framework for &lt;strong&gt;instrumenting&lt;/strong&gt; Rust programs to collect structured, event-based diagnostic information. It provides a convenient and flexible API for collecting and viewing traces of events in your application and you can easily &lt;strong&gt;add context and structure to your traces&lt;/strong&gt;, making it easier to identify bottlenecks and debug issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shuttle logs
&lt;/h2&gt;

&lt;p&gt;A few weeks ago, I wrote a &lt;a href="https://dev.to/robertohuertasm/build-and-deploy-a-rust-backend-with-shuttle-5d7c"&gt;post&lt;/a&gt; about &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt;, where I explained how ridiculously easy it is to deploy a Rust backend to the cloud by using their &lt;a href="https://docs.shuttle.rs/introduction/quick-start" rel="noopener noreferrer"&gt;CLI tool&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; is still in alpha, and although its observability features are not really polished yet, they offer &lt;a href="https://docs.shuttle.rs/introduction/telemetry" rel="noopener noreferrer"&gt;support&lt;/a&gt; for &lt;a href="https://docs.rs/tracing/latest/tracing/" rel="noopener noreferrer"&gt;Tokio Tracing&lt;/a&gt; and a way to &lt;a href="https://docs.shuttle.rs/introduction/telemetry#viewing-logs" rel="noopener noreferrer"&gt;view logs&lt;/a&gt; by using their CLI tool.&lt;/p&gt;

&lt;p&gt;By simply running &lt;code&gt;cargo shuttle logs --follow&lt;/code&gt;, you will be able to see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxij0wf3wb88y615sjfmb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxij0wf3wb88y615sjfmb.png" alt="shuttle logs" width="800" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is great for simple applications, but what if you want to send your logs to a &lt;strong&gt;more powerful tool&lt;/strong&gt; like &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;? Well, in this post, &lt;strong&gt;I’ll show you how to do it&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Datadog
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; is a &lt;strong&gt;monitoring and observability platform&lt;/strong&gt; that provides a &lt;strong&gt;single pane of glass&lt;/strong&gt; for your infrastructure and applications. It is a &lt;strong&gt;cloud-based&lt;/strong&gt; service that allows you to &lt;strong&gt;collect, aggregate and analyze&lt;/strong&gt; your data, and it is &lt;strong&gt;extremely powerful&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a disclaimer, I must say that I’m currently working at &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;, so I’m a bit biased, but I’m also a huge fan of the product and I think it’s a great tool for developers 😅.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most of the time, the easiest way to send anything to the &lt;a href="https://www.datadoghq.com/observability-platform/" rel="noopener noreferrer"&gt;Datadog platform&lt;/a&gt; is by using the &lt;a href="https://docs.datadoghq.com/agent/" rel="noopener noreferrer"&gt;Datadog Agent&lt;/a&gt;, but in this case, as &lt;strong&gt;we cannot install it&lt;/strong&gt; in any way, we will use a &lt;strong&gt;small library I created for the occasion&lt;/strong&gt; called &lt;a href="https://crates.io/crates/dd-tracing-layer" rel="noopener noreferrer"&gt;dd-tracing-layer&lt;/a&gt;, which happens to be using the &lt;a href="https://docs.datadoghq.com/api/latest/logs/" rel="noopener noreferrer"&gt;Datadog HTTP API&lt;/a&gt; under the hood to send logs to the &lt;a href="https://www.datadoghq.com/observability-platform/" rel="noopener noreferrer"&gt;Datadog platform&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use tracing with Shuttle
&lt;/h2&gt;

&lt;p&gt;If we check the &lt;a href="https://docs.shuttle.rs/introduction/telemetry#tracing" rel="noopener noreferrer"&gt;Shuttle documentation&lt;/a&gt;, we can read this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When you build an app with the &lt;code&gt;#[shuttle_service::main]&lt;/code&gt; macro, a global subscriber will be created and installed behind the scenes. This means you can skip this step when implementing tracing in your application, all you have to do is add tracing as a dependency in your Cargo.toml, and you’re good to go!&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// [...]&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[shuttle_service::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;#[shuttle_shared_db::Postgres]&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PgPool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ShuttleAxum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nd"&gt;info!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Running database migration"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="nf"&gt;.execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;include_str!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../schema.sql"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;.await&lt;/span&gt;
        &lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;CustomError&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// [...]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, as you can see, it seems that the Shuttle macro is already instantiating and initializing a &lt;a href="https://docs.rs/tracing/latest/tracing/trait.Subscriber.html" rel="noopener noreferrer"&gt;tracing subscriber&lt;/a&gt; for us.&lt;/p&gt;

&lt;p&gt;This is pretty &lt;strong&gt;convenient for most of the simple cases&lt;/strong&gt; , but unfortunately, it’s not enough for our purposes.&lt;/p&gt;

&lt;p&gt;Ideally, if we had access to the underlying infrastructure, we could probably install the &lt;a href="https://docs.datadoghq.com/agent/" rel="noopener noreferrer"&gt;Datadog Agent&lt;/a&gt; and configure it to send our logs directly to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;, or even use &lt;a href="https://docs.datadoghq.com/logs/guide/send-aws-services-logs-with-the-datadog-lambda-function/?tab=awsconsole" rel="noopener noreferrer"&gt;AWS Lambda functions&lt;/a&gt; or &lt;a href="https://docs.datadoghq.com/integrations/azure/?tab=azurecliv20#log-collection" rel="noopener noreferrer"&gt;Azure Event Hub + Azure Functions&lt;/a&gt; in case we were facing some specific cloud scenarios.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can check the &lt;a href="https://docs.datadoghq.com/logs/log_collection/" rel="noopener noreferrer"&gt;Datadog docs for log collection and integrations&lt;/a&gt; if you want to learn more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those solutions are generally great because they allow us to remove the burden of sending our logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; from our application, thus becoming the &lt;strong&gt;responsibility of the platform&lt;/strong&gt; itself.&lt;/p&gt;

&lt;p&gt;If we could do something like that with &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt;, it would be great. Probably, it would be still nice to be able to &lt;strong&gt;customize the subscriber&lt;/strong&gt; before its initialization in order to filter out some logs or add some context to them, but at least we wouldn’t have to worry about sending our logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; from our application.&lt;/p&gt;

&lt;p&gt;But, as we just mentioned, in the case of &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt;, we &lt;strong&gt;don’t have access to the underlying infrastructure&lt;/strong&gt;, so we need to find a way to send our logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; from our application, and that’s what we are going to try to do in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting access to the subscriber
&lt;/h2&gt;

&lt;p&gt;So, the basic idea is to add a new &lt;a href="https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/" rel="noopener noreferrer"&gt;tracing layer&lt;/a&gt; to the subscriber which will be responsible for sending our logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But for that, we’ll need to get &lt;strong&gt;access to the subscriber instance prior to its initialization&lt;/strong&gt;, and, at the moment of writing this post, there doesn’t seem to be a way to make that possible out of the box.&lt;/p&gt;

&lt;p&gt;So… it seems that our only solution is to get rid of the &lt;code&gt;#[shuttle_service::main]&lt;/code&gt; macro and &lt;strong&gt;go macro-less&lt;/strong&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Walking on the wild side
&lt;/h2&gt;

&lt;p&gt;Fear not! It’s not as bad as it sounds. Of course, this is a workaround, and hopefully the Shuttle team will provide a better solution for this in the future, but for now, this is the only solution we have.&lt;/p&gt;

&lt;p&gt;As a walkthrough, we are going to create a new &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; project from scratch.&lt;/p&gt;

&lt;p&gt;The idea is to build a simple REST API using &lt;a href="https://docs.rs/axum/latest/axum/" rel="noopener noreferrer"&gt;Axum&lt;/a&gt; and send our logs to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; using the &lt;a href="https://crates.io/crates/dd-tracing-layer" rel="noopener noreferrer"&gt;dd-tracing-layer&lt;/a&gt; crate.&lt;/p&gt;

&lt;p&gt;This backend will also have a simple &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; database, which will be managed by using the &lt;a href="https://docs.shuttle.rs/resources/shuttle-shared-db" rel="noopener noreferrer"&gt;Shuttle Shared Database&lt;/a&gt; plugin and will also serve some static files.&lt;/p&gt;

&lt;p&gt;Although I’m going to describe all the steps you need to take to make this work, you can see the &lt;strong&gt;final state of the project&lt;/strong&gt; in this &lt;a href="https://github.com/robertohuertasm/shuttle-datadog-logs" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;. Feel free to use it as a reference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a new project
&lt;/h3&gt;

&lt;p&gt;First of all, we need to create a new &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; project. You can do that by using the &lt;a href="https://docs.shuttle.rs/getting-started/cli" rel="noopener noreferrer"&gt;Shuttle CLI&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo shuttle init &lt;span class="nt"&gt;--axum&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the instructions and you should have a new project ready to go. I called mine &lt;code&gt;shuttle-datadog-logs&lt;/code&gt; but use the name you want.&lt;/p&gt;

&lt;h3&gt;
  
  
  Replacing the Shuttle macro
&lt;/h3&gt;

&lt;p&gt;Once you have your project ready, you need to remove the &lt;code&gt;#[shuttle_service::main]&lt;/code&gt; macro.&lt;/p&gt;

&lt;p&gt;Find the &lt;code&gt;axum&lt;/code&gt; function in the &lt;code&gt;src/lib.rs&lt;/code&gt; file and &lt;strong&gt;remove&lt;/strong&gt; the &lt;code&gt;#[shuttle_service::main]&lt;/code&gt; macro from it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In case you are trying to instrument an already existing project and you’re using some of the &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; features/plugins, you’ll need to remove the macros associated to them in the &lt;code&gt;axum&lt;/code&gt; function, too.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So make sure you get rid of these macros if already present:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;#[shuttle_shared_db::Postgres]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#[shuttle_secrets::Secrets]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#[shuttle_static_folder::StaticFolder]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don’t worry, I’ll explain later how to inject those dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding some dependencies
&lt;/h3&gt;

&lt;p&gt;In our example, we are going to be using these &lt;a href="https://www.shuttle.rs/" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.shuttle.rs/resources/shuttle-shared-db" rel="noopener noreferrer"&gt;Shuttle Shared Database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.shuttle.rs/resources/shuttle-secrets" rel="noopener noreferrer"&gt;Shuttle Secrets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.shuttle.rs/resources/shuttle-static-folder" rel="noopener noreferrer"&gt;Shuttle Static Folder&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, make sure you have the following dependencies in your &lt;code&gt;Cargo.toml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# secrets&lt;/span&gt;
&lt;span class="py"&gt;shuttle-secrets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.9.0"&lt;/span&gt;
&lt;span class="c"&gt;# database&lt;/span&gt;
&lt;span class="py"&gt;shuttle-shared-db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.9.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"postgres"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;sqlx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.6.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"runtime-tokio-native-tls"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"postgres"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;# static files&lt;/span&gt;
&lt;span class="py"&gt;shuttle-static-folder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.9.0"&lt;/span&gt;
&lt;span class="py"&gt;tower-http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"fs"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note that these are optional dependencies and depending on the kind of project you’re working on you may not need them at all. I just added them to show you how to inject them in the &lt;code&gt;axum&lt;/code&gt; function in case you need them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aside from that, as we’re going to deal with &lt;strong&gt;tracing&lt;/strong&gt;, we’ll need to add the following dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;tracing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1"&lt;/span&gt;
&lt;span class="py"&gt;dd-tracing-layer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Instrumenting a little bit the default project
&lt;/h3&gt;

&lt;p&gt;Now that we have our dependencies ready, we can &lt;strong&gt;start instrumenting&lt;/strong&gt; our project a little bit.&lt;/p&gt;

&lt;p&gt;Note that we have added the &lt;code&gt;#[instrument]&lt;/code&gt; macro to the &lt;code&gt;hello_world&lt;/code&gt; function and added a &lt;code&gt;tracing::info!&lt;/code&gt; log to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;sync_wrapper&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SyncWrapper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[instrument]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;info!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Saying hello"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="s"&gt;"Hello, world!"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;_pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PgPool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_secret_store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SecretStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_static_folder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PathBuf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ShuttleAxum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sync_wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SyncWrapper&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sync_wrapper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, if you try to run the project locally by using the &lt;code&gt;shuttle run&lt;/code&gt; command, you should see the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wgdmj4f7ehwonxwq04h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wgdmj4f7ehwonxwq04h.png" alt="shuttle run" width="800" height="58"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Providing the Shuttle entrypoint
&lt;/h3&gt;

&lt;p&gt;As we have removed the &lt;code&gt;#[shuttle_service::main]&lt;/code&gt; macro, we need to provide our own entrypoint.&lt;/p&gt;

&lt;p&gt;We will be adding two new functions to our &lt;code&gt;src/lib.rs&lt;/code&gt; file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;_create_service&lt;/code&gt;: This is the &lt;strong&gt;entrypoint&lt;/strong&gt; for our application. It will be called by the Shuttle runtime and &lt;strong&gt;it needs to be called exactly like this&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;main&lt;/code&gt;: This is the function that will be called by the &lt;code&gt;_create_service&lt;/code&gt; function. It will be the one that will &lt;strong&gt;start our application and instantiate all the dependencies&lt;/strong&gt; we may need in our &lt;code&gt;axum&lt;/code&gt; function (db, secrets, static files folder, etc.).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just copy and paste the following code in the &lt;code&gt;src/lib.rs&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;todo!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Instantiate dependencies and start the axum service"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;_create_service&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Bootstrapper&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;bootstrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Bootstrapper&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;pin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="nf"&gt;.spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="nf"&gt;.bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;.await&lt;/span&gt;
                    &lt;span class="nf"&gt;.context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to bind service"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Into&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;into&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;boxed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bootstrapper&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;into_raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;boxed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we’re going to implement the &lt;code&gt;main&lt;/code&gt; function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding our tracing subscriber
&lt;/h3&gt;

&lt;p&gt;The first thing we’re going to do is to add a &lt;a href="https://docs.rs/tracing-subscriber/" rel="noopener noreferrer"&gt;tracing subscriber&lt;/a&gt; to our application.&lt;/p&gt;

&lt;p&gt;Then we will add the &lt;a href="https://docs.rs/dd-tracing-layer/" rel="noopener noreferrer"&gt;Datadog Tracing layer&lt;/a&gt; to our subscriber along with the &lt;code&gt;Shuttle Logger layer&lt;/code&gt; that we’ll get from the &lt;code&gt;main&lt;/code&gt; function arguments.&lt;/p&gt;

&lt;p&gt;Let’s do it! Add this code to the &lt;code&gt;main&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;tracing_subscriber&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;dd_tracing_layer&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;DatadogOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Region&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// datadog tracing layer&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dd_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;dd_tracing_layer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nn"&gt;DatadogOptions&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;// first parameter is the name of the service&lt;/span&gt;
        &lt;span class="s"&gt;"shuttle-datadog-logs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// this is the Datadog API Key&lt;/span&gt;
        &lt;span class="s"&gt;"21695c1b35156511441c0d3ace5943f4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// this is the default, so it can be omitted&lt;/span&gt;
    &lt;span class="nf"&gt;.with_region&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Region&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;US1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// adding some optional tags&lt;/span&gt;
    &lt;span class="nf"&gt;.with_tags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"env:dev, version:0.1.0"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// feel free to change this implementation&lt;/span&gt;
&lt;span class="c1"&gt;// this will set the tracing level according to the RUST_LOG env variable&lt;/span&gt;
&lt;span class="c1"&gt;// and will use INFO if it's not set&lt;/span&gt;
&lt;span class="c1"&gt;// NOTE that in production, this env var will be set to DEBUG by Shuttle&lt;/span&gt;
&lt;span class="c1"&gt;// so you could skip the env var part and just use the level that you want&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;filter_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;tracing_subscriber&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;EnvFilter&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_from_default_env&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.or_else&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;tracing_subscriber&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;EnvFilter&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INFO"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// starting the tracing subscriber&lt;/span&gt;
&lt;span class="n"&gt;runtime&lt;/span&gt;
    &lt;span class="nf"&gt;.spawn_blocking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;tracing_subscriber&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter_layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;// note that we added the datadog layer here&lt;/span&gt;
            &lt;span class="nf"&gt;.with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dd_layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;// and the shuttle logger layer&lt;/span&gt;
            &lt;span class="nf"&gt;.with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;.init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;.await&lt;/span&gt;
    &lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="nf"&gt;.is_panic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;mes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
                &lt;span class="nf"&gt;.into_panic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="py"&gt;.downcast_ref&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="nf"&gt;.unwrap_or_else&lt;/span&gt;&lt;span class="p"&gt;(||&lt;/span&gt; &lt;span class="s"&gt;"panicked setting logger"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;BuildPanic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Custom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;CustomError&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to set logger"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Instantiating the dependencies
&lt;/h3&gt;

&lt;p&gt;Now that we have our tracing subscriber ready, we can start instantiating our dependencies.&lt;/p&gt;

&lt;p&gt;Let’s add this piece of code to the &lt;code&gt;main&lt;/code&gt; function. As you can see, it’s pretty straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// shared database&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;shuttle_shared_db&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Postgres&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// shuttle secret store&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;secret_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;shuttle_secrets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Secrets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// shuttle static folder support&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;static_folder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;shuttle_static_folder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;StaticFolder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Starting the axum service
&lt;/h3&gt;

&lt;p&gt;Finally, let’s start our &lt;code&gt;axum&lt;/code&gt; service.&lt;/p&gt;

&lt;p&gt;This is the final part of the &lt;code&gt;main&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// starting the axum service and injecting the dependencies&lt;/span&gt;
&lt;span class="n"&gt;runtime&lt;/span&gt;
    &lt;span class="nf"&gt;.spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secret_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;static_folder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;.await&lt;/span&gt;
            &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;.await&lt;/span&gt;
    &lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="nf"&gt;.is_panic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;mes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
                &lt;span class="nf"&gt;.into_panic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="py"&gt;.downcast_ref&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="nf"&gt;.unwrap_or_else&lt;/span&gt;&lt;span class="p"&gt;(||&lt;/span&gt; &lt;span class="s"&gt;"panicked calling main"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;BuildPanic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Custom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;CustomError&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to call main"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding a static folder
&lt;/h3&gt;

&lt;p&gt;Before we run &lt;code&gt;cargo shuttle run&lt;/code&gt;, as we added the &lt;a href="https://docs.shuttle.rs/resources/shuttle-static-folder" rel="noopener noreferrer"&gt;Shuttle Static Folder plugin&lt;/a&gt;, we will need to add a &lt;code&gt;static&lt;/code&gt; folder to our project. If not, the project will fail to start.&lt;/p&gt;

&lt;p&gt;Let’s create a &lt;code&gt;static&lt;/code&gt; folder in the root of our project and add an &lt;code&gt;index.html&lt;/code&gt; file to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"IE=edge"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Shuttle Datadog logs&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    Welcome to the Shuttle Datadog logs app!
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we can add a new endpoint in our &lt;code&gt;axum&lt;/code&gt; function to serve this html.&lt;/p&gt;

&lt;p&gt;This should be the current implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;
    &lt;span class="nn"&gt;http&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nn"&gt;response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IntoResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nn"&gt;routing&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_service&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tower_http&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;services&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ServeDir&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[instrument]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;handle_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;IntoResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;error!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error serving static file"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;INTERNAL_SERVER_ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Something went wrong..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PgPool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_secret_store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SecretStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;static_folder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PathBuf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ShuttleAxum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;serve_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ServeDir&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;static_folder&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="nf"&gt;.handle_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handle_error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serve_dir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sync_wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SyncWrapper&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sync_wrapper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running the REST API
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;cargo shuttle run&lt;/code&gt; and go to &lt;code&gt;http://localhost:8080&lt;/code&gt; in your browser to see the static folder in action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wl4jhbfshfalawurywq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wl4jhbfshfalawurywq.png" alt="Static folder" width="315" height="83"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s browse to &lt;code&gt;http://localhost:8080/hello&lt;/code&gt; to see the &lt;code&gt;hello_world&lt;/code&gt; endpoint in action.&lt;/p&gt;

&lt;p&gt;Alternatively, you can also use &lt;code&gt;curl&lt;/code&gt; to test the endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://localhost:8080/hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But remember that this endpoint was instrumented! So, if everything went well, we should be able to see the logs in &lt;a href="https://app.datadoghq.com/logs" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s check it out! 👀&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmn0rcjanli6bzyuolzfa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmn0rcjanli6bzyuolzfa.png" alt="Datadog logs" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It works! 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Secrets to store the Datadog API key
&lt;/h2&gt;

&lt;p&gt;Wait a minute… we are using a hardcoded API key in our code. This is not a good practice. We &lt;strong&gt;should use a secret to store the API key&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s add a new secret to our project. Create a file called &lt;code&gt;Secrets.toml&lt;/code&gt; in the root of the project and add the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# Secrets.toml file&lt;/span&gt;
&lt;span class="py"&gt;DD_API_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"YOUR-DATADOG-API-KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt; : Don’t forget to add it to your &lt;code&gt;.gitignore&lt;/code&gt; file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, we will have to go to the &lt;code&gt;main&lt;/code&gt; function and change the order in which the dependencies were instantiated.&lt;/p&gt;

&lt;p&gt;Basically, we need to instantiate the &lt;code&gt;secret store&lt;/code&gt; before the &lt;a href="https://crates.io/crates/dd-tracing-layer" rel="noopener noreferrer"&gt;dd-tracing-layer&lt;/a&gt; is set, so we can get the &lt;code&gt;DD-API-KEY&lt;/code&gt; secret from there and pass it to the &lt;code&gt;dd-tracing-layer&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// shuttle secret store&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;secret_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;shuttle_secrets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Secrets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// getting the datadog api key from the secret store&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dd_api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secret_store&lt;/span&gt;
    &lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DD_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DD_API_KEY not found"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// datadog tracing layer&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dd_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;dd_tracing_layer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nn"&gt;DatadogOptions&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;// first parameter is the name of the service&lt;/span&gt;
        &lt;span class="s"&gt;"shuttle-datadog-logs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c1"&gt;// this is the Datadog API Key&lt;/span&gt;
        &lt;span class="n"&gt;dd_api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// this is the default, so it can be omitted&lt;/span&gt;
    &lt;span class="nf"&gt;.with_region&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Region&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;US1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// adding some optional tags&lt;/span&gt;
    &lt;span class="nf"&gt;.with_tags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"env:dev, version:0.1.0"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ... rest of the code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can test that everything works as expected by running the project again and checking the logs in &lt;a href="https://app.datadoghq.com/logs" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secrets per environment
&lt;/h3&gt;

&lt;p&gt;Let’s try to do one more thing. Wouldn’t it be nice to be able to send different &lt;code&gt;tags&lt;/code&gt; to &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; in case we were running from different environments?&lt;/p&gt;

&lt;p&gt;For example, we could add an &lt;code&gt;env&lt;/code&gt; tag to the logs in &lt;code&gt;dev&lt;/code&gt; and a &lt;code&gt;prod&lt;/code&gt; tag in &lt;code&gt;production&lt;/code&gt;. Something simple, for the sake of this exercise, and add different &lt;code&gt;secrets&lt;/code&gt; for each environment.&lt;/p&gt;

&lt;p&gt;Although, &lt;a href="https://github.com/shuttle-hq/shuttle/issues/563" rel="noopener noreferrer"&gt;this is not supported yet&lt;/a&gt;, we can implement something similar.&lt;/p&gt;

&lt;p&gt;Let’s change our &lt;code&gt;Secrets.toml&lt;/code&gt; file to look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;DD_API_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"my-datadog-api-key"&lt;/span&gt;
&lt;span class="py"&gt;DD_TAGS&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"env:production"&lt;/span&gt;
&lt;span class="py"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"INFO"&lt;/span&gt;

&lt;span class="c"&gt;# development environment&lt;/span&gt;
&lt;span class="py"&gt;DD_TAGS_DEV&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"env:dev"&lt;/span&gt;
&lt;span class="py"&gt;LOG_LEVEL_DEV&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"DEBUG"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Probably you’ve already guessed the idea. We are going to use the &lt;code&gt;_DEV&lt;/code&gt; suffix to define the &lt;code&gt;dev&lt;/code&gt; environment.&lt;/p&gt;

&lt;p&gt;Add this small function to your &lt;code&gt;lib.rs&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_secret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secret_store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;SecretStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;final_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nd"&gt;cfg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug_assertions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}_DEV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="n"&gt;secret_store&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;final_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we can use this function to get the &lt;code&gt;DD_TAGS&lt;/code&gt; and &lt;code&gt;LOG_LEVEL&lt;/code&gt; secrets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// we are adding a version constant to the file&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"version:0.1.0"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// then we're getting the secrets in the main function&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_secret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;secret_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"DD_TAGS"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{},{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VERSION&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;log_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_secret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;secret_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"LOG_LEVEL"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INFO"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// NOTE: As we're defaulting to INFO, we're also getting rid of the environment variable support,&lt;/span&gt;
&lt;span class="c1"&gt;// as Shuttle will ingore env vars in production anyway.&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;filter_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;tracing_subscriber&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;EnvFilter&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;try_new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to set log level"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it! It’s not ideal, but it works! 😄&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a database
&lt;/h2&gt;

&lt;p&gt;And finally, let’s add a database to our project. We will be using &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; for this.&lt;/p&gt;

&lt;p&gt;Let’s keep things simple, though. We will just add a &lt;code&gt;messages&lt;/code&gt; table to our database and a new endpoint to get one message from that table. Feel free to expand this example to your needs.&lt;/p&gt;

&lt;p&gt;Cool! 😊 Let’s create a file called &lt;code&gt;db.sql&lt;/code&gt; in the root of the project and add the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- schema&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;serial&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- add a message&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'hello world from Database!'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;CONFLICT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DO&lt;/span&gt; &lt;span class="k"&gt;NOTHING&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s initialize the database in our &lt;code&gt;axum&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="nf"&gt;. Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;include_str!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../db.sql"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;.await&lt;/span&gt;
    &lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;CustomError&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we’ll declare a new endpoint and share the &lt;code&gt;pool&lt;/code&gt; as &lt;code&gt;state&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
    &lt;span class="c1"&gt;// here we add the new endpoint&lt;/span&gt;
    &lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serve_dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// set the state so we can get access to our database from the endpoints&lt;/span&gt;
    &lt;span class="nf"&gt;.with_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we’ll create the &lt;code&gt;message&lt;/code&gt; endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[instrument(skip(db))]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;State&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PgPool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;info!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Getting a message from the database"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;sqlx&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;query_as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT message FROM messages LIMIT 1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.fetch_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;.await&lt;/span&gt;
        &lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;INTERNAL_SERVER_ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="na"&gt;.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;tracing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;info!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Got message from database"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done!&lt;/p&gt;

&lt;p&gt;Let’s run the project again and browse to &lt;code&gt;http://localhost:8000/message&lt;/code&gt; to see the message from the database:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdpbfmo9lmistgqoj15rr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdpbfmo9lmistgqoj15rr.png" alt="shuttle-datadog-logs" width="476" height="104"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now, let’s check the logs in &lt;a href="https://app.datadoghq.com/logs" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzgsc015948y81f3d09yy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzgsc015948y81f3d09yy.png" alt="shuttle-datadog-logs" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Well, the length of this post is getting a bit out of hand, so I’ll stop here. 😅&lt;/p&gt;

&lt;p&gt;We’ve not only covered how to add &lt;a href="https://datadoghq.com" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; support to our project, but we’ve also shown how to work with databases, secrets, and static folders with &lt;a href="https://shuttle.rs" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For the moment, it requires a little bit of manual work, but I’m sure that &lt;a href="https://shuttle.rs" rel="noopener noreferrer"&gt;Shuttle&lt;/a&gt; will improve this in the future and make this process even easier.&lt;/p&gt;

&lt;p&gt;Again, you can see the full code in &lt;a href="https://github.com/robertohuertasm/shuttle-datadog-logs" rel="noopener noreferrer"&gt;this GitHub repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you’ve enjoyed it! 😁&lt;/p&gt;

</description>
      <category>rust</category>
      <category>datadog</category>
      <category>shuttle</category>
      <category>observability</category>
    </item>
    <item>
      <title>Build and deploy a Rust backend with Shuttle</title>
      <dc:creator>Roberto Huertas</dc:creator>
      <pubDate>Sun, 08 Jan 2023 23:00:00 +0000</pubDate>
      <link>https://dev.to/robertohuertasm/build-and-deploy-a-rust-backend-with-shuttle-5d7c</link>
      <guid>https://dev.to/robertohuertasm/build-and-deploy-a-rust-backend-with-shuttle-5d7c</guid>
      <description>&lt;p&gt;Learn how to build and deploy a Rust backend with &lt;a href="https://www.shuttle.rs/"&gt;Shuttle&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Value proposition
&lt;/h2&gt;

&lt;p&gt;What if I told you that you could &lt;strong&gt;write a Rust backend and deploy it for free&lt;/strong&gt; in the cloud?&lt;/p&gt;

&lt;p&gt;What if I told you that you could &lt;strong&gt;get a Postgres database for free&lt;/strong&gt;, too?&lt;/p&gt;

&lt;p&gt;What if I told you that you &lt;strong&gt;wouldn’t have to worry about setting the whole infrastructure up&lt;/strong&gt;? Nor even have to deal with connection strings?&lt;/p&gt;

&lt;p&gt;Finally, what if I told you that you could &lt;strong&gt;use some of the most popular web frameworks available&lt;/strong&gt; in the Rust ecosystem?&lt;/p&gt;

&lt;p&gt;To be honest, I couldn’t believe it myself when I first learnt about &lt;a href="https://www.shuttle.rs/"&gt;Shuttle&lt;/a&gt;, but I can say that they live up to their promise!&lt;/p&gt;

&lt;p&gt;And on top of all that, their code is totally &lt;strong&gt;open-source&lt;/strong&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use it
&lt;/h2&gt;

&lt;p&gt;Check out this &lt;a href="https://docs.rs/axum/latest/axum/"&gt;Axum’s&lt;/a&gt; &lt;code&gt;Hello World&lt;/code&gt; example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;routing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;sync_wrapper&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SyncWrapper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[shuttle_service::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ShuttleAxum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build_router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sync_wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;SyncWrapper&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sync_wrapper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;build_router&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Router&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"Hello, world!"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, let’s compare it to the code that you would write by not using &lt;a href="https://www.shuttle.rs/"&gt;Shuttle&lt;/a&gt; at all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;routing&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nd"&gt;#[tokio::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build_router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nn"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="s"&gt;"0.0.0.0:8000"&lt;/span&gt;&lt;span class="nf"&gt;.parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="nf"&gt;.into_make_service&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;.await&lt;/span&gt;
        &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;build_router&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Router&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;hello_world&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"Hello, world!"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, both examples are &lt;strong&gt;pretty similar&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The only part of code that is different is the &lt;strong&gt;entry point&lt;/strong&gt; of your app. The rest is the same. So, you could potentially &lt;strong&gt;reuse the same code&lt;/strong&gt; to deploy it in your own infrastructure if you ever want to get away of &lt;a href="https://www.shuttle.rs/"&gt;Shuttle&lt;/a&gt;, thus avoiding the &lt;em&gt;vendor lock-in&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Postgres database
&lt;/h2&gt;

&lt;p&gt;Adding a database is a piece of cake!&lt;/p&gt;

&lt;p&gt;Forget about having to set up a user, dealing with connection strings and all that jazz. &lt;a href="https://www.shuttle.rs/"&gt;Shuttle&lt;/a&gt; will inject a &lt;a href="https://docs.rs/sqlx/latest/sqlx/type.PgPool.html"&gt;sqlx pool&lt;/a&gt; that you can use right away from your main function to work with your database.&lt;/p&gt;

&lt;p&gt;But in order for this to happen, you will have to add a couple of dependencies to your &lt;code&gt;Cargo.toml&lt;/code&gt; first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;shuttle-shared-db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.8.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;["postgres"]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;sqlx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.6.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;["runtime-tokio-native-tls","postgres"]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, go to your previous code and add a parameter to your entry point function (&lt;em&gt;note that it is annotated with a macro&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[shuttle_service::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;#[shuttle_shared_db::Postgres]&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PgPool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ShuttleAxum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it! You can now start working with &lt;a href="https://github.com/launchbadge/sqlx"&gt;sqlx&lt;/a&gt; to deal with your new Postgres database.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For the moment, &lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt; and &lt;a href="https://www.mongodb.com/"&gt;MongoDB&lt;/a&gt; are the only supported databases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Initializing the database
&lt;/h3&gt;

&lt;p&gt;Let’s say we want to create a simple table.&lt;/p&gt;

&lt;p&gt;Create a file in the root of your project called &lt;code&gt;db/schema.sql&lt;/code&gt; and add these lines to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;serial&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;txt&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s add a few lines to the &lt;code&gt;axum&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[shuttle_service::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;axum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;#[shuttle_shared_db::Postgres]&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PgPool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;shuttle_service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ShuttleAxum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="nf"&gt;.execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;include_str!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../db/schema.sql"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;.await&lt;/span&gt;
        &lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;CustomError&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, every time our service starts, it will try to create the &lt;code&gt;test&lt;/code&gt; table if it doesn’t already exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shuttle CLI
&lt;/h2&gt;

&lt;p&gt;But, wait a moment!&lt;/p&gt;

&lt;p&gt;You may be wondering: “_What if I want to connect to my database with another client (i.e. &lt;a href="https://dbeaver.io/"&gt;DBeaver&lt;/a&gt;) to inspect its contents or make a custom query?”.&lt;/p&gt;

&lt;p&gt;Well, you can. I didn’t mention so far one of the &lt;strong&gt;most important&lt;/strong&gt; &lt;a href="https://www.shuttle.rs/"&gt;Shuttle&lt;/a&gt; parts: its &lt;strong&gt;CLI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Basically, in order to run your code locally and deploy it to the cloud, you’ll need to use a CLI tool called &lt;a href="https://crates.io/crates/cargo-shuttle"&gt;cargo-shuttle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In order to install it, just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo install cargo-shuttle

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It has lots of &lt;a href="https://docs.shuttle.rs/introduction/shuttle-commands"&gt;subcommands&lt;/a&gt; to help you &lt;strong&gt;set up&lt;/strong&gt; a project from scratch and &lt;strong&gt;manage&lt;/strong&gt; it.&lt;/p&gt;

&lt;p&gt;Just by running &lt;code&gt;cargo shuttle init&lt;/code&gt;, the CLI will guide you through a set of options that will let you choose, amongst other things, the name and location of your project, and the framework that you want to use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://robertohuertas.com/assets/images/shuttle-axum/v0.8.0-interactive-init.gif"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_tFmQ-sj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/crvgy8iqwm94pn8kvskp.PNG" alt="cli" width="880" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just to name a few of the available frameworks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://actix.rs/"&gt;actix-web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://salvo.rs/"&gt;salvo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.rs/axum/latest/axum/"&gt;axum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.rs/poem/latest/poem/"&gt;poem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.rs/tide/0.16.0/tide/"&gt;tide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.rs/warp/latest/warp/"&gt;warp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.rs/tower/latest/tower/"&gt;tower&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And no, I didn’t forget about the connection string 😉. Whenever you &lt;code&gt;run&lt;/code&gt; or &lt;code&gt;deploy&lt;/code&gt; your project, if &lt;a href="https://crates.io/crates/cargo-shuttle"&gt;cargo-shuttle&lt;/a&gt; detects you are using a database, it will let you know the connection string, so you can use it on your own.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c7v3Z2f9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/shuttle-axum/shuttle-axum-db.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c7v3Z2f9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/shuttle-axum/shuttle-axum-db.png" alt="shuttle axum db" width="854" height="132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Infrastructure from Code
&lt;/h2&gt;

&lt;p&gt;This is the way they have chosen to describe how they provision all the resources for you (databases, caches, subdomains, static folder…).&lt;/p&gt;

&lt;p&gt;As you already saw, they’re using &lt;strong&gt;annotations&lt;/strong&gt; in your code to understand if you are going to need a database or not, and just depending on that, they will provision that for you.&lt;/p&gt;

&lt;p&gt;The idea is that you don’t need to define &lt;code&gt;infrastructure as code&lt;/code&gt; but that &lt;strong&gt;your code itself implicitly defines your infrastructure&lt;/strong&gt;. Pretty cool and impressive, IMHO!&lt;/p&gt;

&lt;h2&gt;
  
  
  Many more things
&lt;/h2&gt;

&lt;p&gt;There are many more things to discover.&lt;/p&gt;

&lt;p&gt;Check out their amazing &lt;a href="https://github.com/shuttle-hq/examples"&gt;set of examples&lt;/a&gt;, which will get you up to speed in a blink of an eye.&lt;/p&gt;

&lt;p&gt;On the other hand, I have prepared a &lt;a href="https://github.com/robertohuertasm/shuttle-axum"&gt;small GitHub repository&lt;/a&gt; showcasing a &lt;strong&gt;simple Axum Rest API&lt;/strong&gt; that uses a &lt;strong&gt;Postgres database&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This example is live, &lt;a href="https://shuttle-axum-2023.shuttleapp.rs/"&gt;here&lt;/a&gt;. Feel free to use &lt;a href="https://www.postman.com/"&gt;Postman&lt;/a&gt; to play with it. You have the request file available &lt;a href="https://github.com/robertohuertasm/shuttle-axum/blob/master/reqs.http"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;Note that I’m not in any way related to &lt;a href="https://www.shuttle.rs/"&gt;Shuttle&lt;/a&gt; and this is not a “marketing” post of something like that.&lt;/p&gt;

&lt;p&gt;I was so amazed when I discovered their service that I immediately felt the need to share my excitement with the rest of the world 😉&lt;/p&gt;

&lt;p&gt;In any case, bear in mind that &lt;strong&gt;they’re in &lt;a href="https://docs.shuttle.rs/community/contribute"&gt;public alpha&lt;/a&gt;&lt;/strong&gt; so the service is not really that stable, and they may change things or even disrupt the service at any time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concluding thoughts
&lt;/h2&gt;

&lt;p&gt;I think &lt;a href="https://www.shuttle.rs/"&gt;Shuttle&lt;/a&gt; is a &lt;strong&gt;great project&lt;/strong&gt; and it’s definitely &lt;strong&gt;good news&lt;/strong&gt; for the Rust community.&lt;/p&gt;

&lt;p&gt;It not only allows us to &lt;strong&gt;deploy Rust backends easily for free&lt;/strong&gt; , but also &lt;strong&gt;enables&lt;/strong&gt; lots of web developers coming from other languages to &lt;strong&gt;approach the Rust web development ecosystem&lt;/strong&gt; and realize that &lt;strong&gt;it’s not as intimidating&lt;/strong&gt; as one could think in the first place.&lt;/p&gt;

&lt;p&gt;Let’s leverage this great opportunity to &lt;a href="https://docs.shuttle.rs/community/get-involved"&gt;get involved&lt;/a&gt; and be part of this interesting project!&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>rust</category>
      <category>deployment</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Preview your VSCode extension in the marketplace</title>
      <dc:creator>Roberto Huertas</dc:creator>
      <pubDate>Fri, 28 Oct 2022 22:00:00 +0000</pubDate>
      <link>https://dev.to/robertohuertasm/preview-your-vscode-extension-in-the-marketplace-1dif</link>
      <guid>https://dev.to/robertohuertasm/preview-your-vscode-extension-in-the-marketplace-1dif</guid>
      <description>&lt;p&gt;Learn how to use the &lt;a href="https://marketplace.visualstudio.com/items?itemName=robertohuertasm.vscode-marketplace-preview"&gt;Marketplace Preview&lt;/a&gt; extension to see how your extension's manifest will look like in the &lt;a href="https://marketplace.visualstudio.com/vscode"&gt;Visual Studio Marketplace&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So, are you building a Visual Studio Code extension?
&lt;/h2&gt;

&lt;p&gt;If you're here, there's a good chance you are 😉. Then, eventually, at some point you will want to &lt;strong&gt;publish&lt;/strong&gt; it to the &lt;a href="https://marketplace.visualstudio.com/vscode"&gt;Visual Studio Marketplace&lt;/a&gt; or even to the &lt;a href="https://open-vsx.org/"&gt;Open VSX Registry&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But first, just a little &lt;strong&gt;disclaimer about myself&lt;/strong&gt;. I'm the author and main maintainer of the &lt;a href="https://marketplace.visualstudio.com/items?itemName=vscode-icons-team.vscode-icons"&gt;vscode-icons&lt;/a&gt; extension, which is about 6 years old at the moment of writing this and, back in the day, &lt;a href="https://code.visualstudio.com/blogs/2016/09/08/icon-themes#_rebellion-revolt-uprising"&gt;helped to bring icons to Visual Studio Code&lt;/a&gt; when there was no API available for that.&lt;/p&gt;

&lt;p&gt;Aside from that, and after many years of non VSCode related work, I recently joined &lt;a href="https://www.datadoghq.com/"&gt;Datadog&lt;/a&gt;'s IDE Integration team with the objective of building a great VSCode extension that can bring all the information that &lt;a href="https://www.datadoghq.com/"&gt;Datadog&lt;/a&gt; has to offer just where developers work most of the time: their code editor.&lt;/p&gt;

&lt;p&gt;With all this, I just wanted to illustrate that &lt;strong&gt;I have also faced the moment of publishing&lt;/strong&gt; to the Marketplace myself. And it's curious, because I clearly remember that the first time, I had to retouch the &lt;code&gt;readme&lt;/code&gt; file more than once after publishing. And not only the &lt;code&gt;readme&lt;/code&gt; file. The icon and the background color of the banner in the &lt;code&gt;package.json&lt;/code&gt; file, too.&lt;/p&gt;

&lt;p&gt;To be honest, I more or less suspected that modiying the icon, the background color or one of the  many other properties that we usually set in the &lt;code&gt;package.json&lt;/code&gt; file, would require to publish a new version of the extension. But I naively believed that the &lt;code&gt;readme&lt;/code&gt; changes wouldn't require such a thing and they would be consumed directly from the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reducing the chances
&lt;/h2&gt;

&lt;p&gt;The reality is that sometimes, when you're modifying your &lt;code&gt;readme&lt;/code&gt; or the settings of your &lt;code&gt;package.json&lt;/code&gt; file, &lt;strong&gt;you may not be sure of how that would look like&lt;/strong&gt; in the &lt;a href="https://marketplace.visualstudio.com/vscode"&gt;Visual Studio Marketplace&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Yes, the &lt;code&gt;readme&lt;/code&gt; is written in &lt;code&gt;markdown&lt;/code&gt;, but the way it's rendered in &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt;, for instance, may differ from the way it's presented in the &lt;a href="https://marketplace.visualstudio.com/vscode"&gt;Visual Studio Marketplace&lt;/a&gt;, and there's a chance that when you see the result of your work in there, you may not really like it and then need to ship a new version &lt;em&gt;"just"&lt;/em&gt; for that.&lt;/p&gt;

&lt;p&gt;As we were planning to do a first release of the &lt;a href="https://www.datadoghq.com/"&gt;Datadog&lt;/a&gt;'s VSCode extension soon and I had also some ideas for VSCode extensions that I wanted to explore, I thought I should find a tool to reduce the chances of having to publish again because of those unexpected aesthetic changes. And I found one! 🌟&lt;/p&gt;

&lt;h2&gt;
  
  
  Microsoft's Extension Manifest Editor
&lt;/h2&gt;

&lt;p&gt;Enter &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-devlabs.extension-manifest-editor&amp;amp;ssr=false#overview"&gt;Extension Manifest Editor&lt;/a&gt;, a VSCode extension built by &lt;a href="https://marketplace.visualstudio.com/publishers/Microsoft%20DevLabs"&gt;Microsoft DevLabs&lt;/a&gt; that lets you preview the details page for your extension from within  &lt;a href="https://code.visualstudio.com/"&gt;Visual Studio Code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I was happy! Until I tried it...&lt;/p&gt;

&lt;p&gt;Surprisingly, &lt;strong&gt;the extension didn't work&lt;/strong&gt;. The &lt;a href="https://github.com/microsoft/extension-manifest-editor"&gt;last commit&lt;/a&gt; to that extension dates back from 2017 so it kind of makes sense.&lt;/p&gt;

&lt;p&gt;Honestly, I'm not sure why Microsoft decided to discontinue the support for that extension. Especially, given that it has 11K downloads in the Marketplace, which is certainly not that much if you compare it with other extension's numbers, but anyway, it's a niche product, targeting only extension developers... so I would say that it's not such a bad number at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's build a new extension!
&lt;/h2&gt;

&lt;p&gt;Probably you already know that feeling... You're seeking for a tool, and you want to find it because it will solve your problem... but... some part of you, deep inside, wishes not to find it at all, so you can have the opportunity to build it yourself and share it with the rest of the world.&lt;/p&gt;

&lt;p&gt;And that's what happened to me! And that feeling ended up being transformed into this new &lt;a href="https://code.visualstudio.com/"&gt;Visual Studio Code&lt;/a&gt; extension called &lt;a href="https://marketplace.visualstudio.com/items?itemName=robertohuertasm.vscode-marketplace-preview"&gt;Marketplace Preview&lt;/a&gt; which &lt;strong&gt;I recently published&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's quite &lt;strong&gt;simple but it does the job&lt;/strong&gt;. And if you are building an extension yourself, I hope it can be helpful for you, too.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;If you open a &lt;code&gt;package.json&lt;/code&gt; file that happens to be a VSCode manifest, you will see this extra icon in the top right corner. Click over it to see how it would look in the &lt;a href="https://marketplace.visualstudio.com/vscode"&gt;Visual Studio Marketplace&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SlwpAC9_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/robertohuertasm/vscode-marketplace-preview/master/resources/images/docs_icon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SlwpAC9_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/robertohuertasm/vscode-marketplace-preview/master/resources/images/docs_icon.png" alt="command icon" width="226" height="32"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See how it works in the animated gif below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MmVRIuhR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://raw.githubusercontent.com/robertohuertasm/vscode-marketplace-preview/master/resources/images/demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MmVRIuhR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://raw.githubusercontent.com/robertohuertasm/vscode-marketplace-preview/master/resources/images/demo.gif" alt="demo" width="880" height="468"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you give a try, &lt;strong&gt;let me know your thoughts and ideas&lt;/strong&gt;. I'll be happy to accept contributions or suggestions in the &lt;a href="https://github.com/robertohuertasm/vscode-marketplace-preview"&gt;extension's GitHub repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Open sourcing Licensebat</title>
      <dc:creator>Roberto Huertas</dc:creator>
      <pubDate>Mon, 03 Jan 2022 23:00:00 +0000</pubDate>
      <link>https://dev.to/robertohuertasm/open-sourcing-licensebat-4ff7</link>
      <guid>https://dev.to/robertohuertasm/open-sourcing-licensebat-4ff7</guid>
      <description>&lt;p&gt;Learn why I decided to open source &lt;a href="https://licensebat.com"&gt;Licensebat&lt;/a&gt;, the software that easily helps you manage the licenses of your project's dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Licensebat?
&lt;/h2&gt;

&lt;p&gt;The idea is pretty simple, it’s just a tool written in &lt;a href="https://rust-lang.org"&gt;Rust&lt;/a&gt; that &lt;strong&gt;scans the dependencies&lt;/strong&gt; of your project and &lt;strong&gt;generates a report&lt;/strong&gt; of the different licenses that are used.&lt;/p&gt;

&lt;p&gt;Initially, it was only a &lt;strong&gt;SaaS&lt;/strong&gt; product running in the &lt;a href="https://github.com/marketplace/licensebat"&gt;GitHub Marketplace&lt;/a&gt; with several pricing tiers. One of them being a &lt;a href="https://github.com/marketplace/licensebat/plan/MLP_kgDNGqc#pricing-and-setup"&gt;free tier&lt;/a&gt; without any limitations for OSS projects and a few free requests per month for commercial projects.&lt;/p&gt;

&lt;p&gt;After some months, though, I decided to open source &lt;a href="https://licenseba.com"&gt;Licensebat&lt;/a&gt; and release it as a &lt;strong&gt;FOSS&lt;/strong&gt; project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;Although &lt;a href="https://licenseba.com"&gt;Licensebat&lt;/a&gt; as a SaaS product has access to the code hosted in &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt; it only accesses the code through the &lt;a href="https://developer.github.com/v3/"&gt;GitHub API&lt;/a&gt;. This allows us to keep the &lt;strong&gt;code private&lt;/strong&gt; and only access the dependency manifest files, like &lt;code&gt;package-lock.json&lt;/code&gt;, &lt;code&gt;Cargo.lock&lt;/code&gt; or &lt;code&gt;pubspec.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Anyway, some companies had some &lt;strong&gt;legit concerns&lt;/strong&gt; about their code being potentially exposed to a third party service. It was clear to me that I’d need some other way for these customers to be able to get the service &lt;a href="https://licensebat.com"&gt;Licensebat&lt;/a&gt; was providing without exposing their code at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Licensebat CLI
&lt;/h2&gt;

&lt;p&gt;The idea of having some sort of &lt;em&gt;binary/container/executable&lt;/em&gt; that could be used by these companies in their CI/CD pipelines immediately came up. But then, anyway, if this binary was not open source, if they couldn’t compile it themselves, how would they be sure that it was completely safe to use? How would they know that it was not scanning the code under the hood?&lt;/p&gt;

&lt;p&gt;That’s when I decided to &lt;strong&gt;open source&lt;/strong&gt; not only the &lt;a href="https://crates.io/crates/licensebat-cli"&gt;CLI&lt;/a&gt; but also &lt;a href="https://crates.io/search?q=licensebat"&gt;all the crates&lt;/a&gt; that are used in order to give support for some programming languages, which at the time I’m writing this are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://crates.io/crates/licensebat-js"&gt;JavaScript / TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crates.io/crates/licensebat-dart"&gt;Dart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crates.io/crates/licensebat-rust"&gt;Rust&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The thought was that the community would eventually be able to &lt;strong&gt;use and evolve&lt;/strong&gt; all these crates and &lt;strong&gt;support many more languages&lt;/strong&gt; in the long term.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about the SaaS?
&lt;/h2&gt;

&lt;p&gt;You may be wondering what’s the value of the SaaS service in this context where any company could just download the CLI and use it for free. And you’re totally right.&lt;/p&gt;

&lt;p&gt;To be honest, I’m not completely sure about this, but I think there will still be companies willing to use Licensebat as a GitHub integrated service.&lt;/p&gt;

&lt;p&gt;I have plans to extend that service even further by optimizing the dependency resolution and the license scanning process, and providing more value by adding features such as a history of the licenses that have been scanned, and a way to share the results with other people.&lt;/p&gt;

&lt;p&gt;Will it work? Who knows! 😁&lt;/p&gt;

&lt;p&gt;In any case, I’m happy to be able to open source &lt;a href="https://licensebat.com"&gt;Licensebat&lt;/a&gt; and hope that it will be useful to other people. That’s what matters to me more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other conveniences
&lt;/h2&gt;

&lt;p&gt;There are other cool things associated to the fact that this CLI is open source. The obvious one is that we can now leverage the fact that we can access the whole codebase without any concerns.&lt;/p&gt;

&lt;p&gt;This means that, for some languages, we can find more convenient and optimized ways to access to the dependencies’ license information, speeding up the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you want to give it a try or are just curious about the code, you can find it &lt;a href="https://github.com/licensebat/licensebat"&gt;here, hosted in GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It would be great to have you as a contributor!&lt;/p&gt;

</description>
      <category>rust</category>
      <category>opensource</category>
      <category>license</category>
      <category>compliance</category>
    </item>
    <item>
      <title>Cognito Authentication for your SvelteKit app</title>
      <dc:creator>Roberto Huertas</dc:creator>
      <pubDate>Sat, 24 Jul 2021 22:00:00 +0000</pubDate>
      <link>https://dev.to/robertohuertasm/cognito-authentication-for-your-sveltekit-app-4oai</link>
      <guid>https://dev.to/robertohuertasm/cognito-authentication-for-your-sveltekit-app-4oai</guid>
      <description>&lt;p&gt;Manage your users in your &lt;a href="https://kit.svelte.dev/"&gt;SvelteKit&lt;/a&gt; app with &lt;a href="https://aws.amazon.com/cognito/"&gt;AWS Cognito&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Cognito?
&lt;/h2&gt;

&lt;p&gt;To be honest, in my case, it’s just because we’re using &lt;a href="https://aws.amazon.com/"&gt;AWS&lt;/a&gt; at &lt;a href="https://koahealth.com/"&gt;Koa Health&lt;/a&gt; and it was the natural choice. I have many things to say about &lt;a href="https://aws.amazon.com/cognito/"&gt;AWS Cognito&lt;/a&gt;, both good and bad, but this won’t be the article covering that 😉.&lt;/p&gt;

&lt;p&gt;Well, hopefully, chances are that you may be already using &lt;a href="https://aws.amazon.com/"&gt;AWS&lt;/a&gt; as your main cloud provider and this post can help you to integrate &lt;a href="https://aws.amazon.com/cognito/"&gt;AWS Cognito&lt;/a&gt; in you &lt;a href="https://kit.svelte.dev/"&gt;SvelteKit&lt;/a&gt; app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;I’m starting with &lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; so if you have any suggestions to improve what I’ll show here, you’re more than welcome to write a comment or contact me.&lt;/p&gt;

&lt;p&gt;Alternatively, feel free to take a look at the &lt;a href="https://github.com/robertohuertasm/sveltekit-cognito-auth"&gt;GitHub repository hosting the final project&lt;/a&gt; and open an issue there if you prefer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the SvelteKit app
&lt;/h2&gt;

&lt;p&gt;We’re just going to use SvelteKit to build a simple app that will authenticate users, so let’s start with with some simple commands to create the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init svelte@next sveltekit-cognito-auth
&lt;span class="c"&gt;# I'm choosing the Skeleton project,&lt;/span&gt;
&lt;span class="c"&gt;# opting out of TypeScript for this tutorial&lt;/span&gt;
&lt;span class="c"&gt;# and using ESlint and Prettier support&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;sveltekit-cogniton-auth
npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find &lt;a href="https://kit.svelte.dev/docs"&gt;here&lt;/a&gt; more details about how to &lt;a href="https://kit.svelte.dev/docs"&gt;get started with SvelteKit&lt;/a&gt; in case you want to learn more about it.&lt;/p&gt;

&lt;p&gt;For now, let’s open the &lt;code&gt;src/index.svelte&lt;/code&gt; file, delete its content and build this spartan UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// we'll edit this later&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;svelte:head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;SvelteKit - Cognito&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svelte:head&amp;gt;&lt;/span&gt;

{#if !user}
    &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Log In with Cognito&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
{:else}
    &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Log Out&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
{/if}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea here is to have a button that will trigger the &lt;strong&gt;Cognito authentication flow&lt;/strong&gt; and another one that will &lt;strong&gt;log out&lt;/strong&gt; the user. As simple as that!&lt;/p&gt;

&lt;p&gt;For the moment, we’re going to skip all the logic to show one button or the other but we will come back to it later.&lt;/p&gt;

&lt;p&gt;Let’s check that our app is working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run dev &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--open&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully, you should see a page with a button that says &lt;code&gt;Log In with Cognito&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Cognito
&lt;/h2&gt;

&lt;p&gt;Let’s &lt;strong&gt;create and configure&lt;/strong&gt; our Cognito User Pool now.&lt;/p&gt;

&lt;p&gt;First of all, let’s introduce the pool name: &lt;code&gt;sveltekit-pool&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aNGqpds4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/01-create-cognito-pool.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aNGqpds4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/01-create-cognito-pool.png" alt="Cognito Pool Name"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this example, we’re going to use these simple settings.&lt;/p&gt;

&lt;p&gt;Remember to tick the &lt;strong&gt;email&lt;/strong&gt; checkbox in the &lt;code&gt;Attributes section&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1o8NnhiX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/02-create-cognito-pool.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1o8NnhiX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/02-create-cognito-pool.png" alt="Cognito Pool Attributes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ll also relax the &lt;strong&gt;Password Policy&lt;/strong&gt; to allow users to choose their own passwords without many hassles, so &lt;strong&gt;uncheck all the checkboxes&lt;/strong&gt; related to the password strength.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zrc7O7Zg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/03-create-cognito-pool.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zrc7O7Zg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/03-create-cognito-pool.png" alt="Cognito Pool Policy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’ press the &lt;code&gt;Next Step&lt;/code&gt; button until we arrive to the &lt;code&gt;App Clients&lt;/code&gt; section and let’s &lt;strong&gt;add one app client&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Leave it everything as it is and set the name that you want. For this example, I’m using &lt;code&gt;sveltekit&lt;/code&gt;. Fairly original, isn’t it? 😉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bUDzHj-G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/04-create-cognito-pool.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bUDzHj-G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/04-create-cognito-pool.png" alt="Cognito Pool App Client"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the App Client
&lt;/h2&gt;

&lt;p&gt;There are still a couple of things to do in our Cognito Pool. Ideally, we’d like to use the &lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-integration.html"&gt;Cognito Hosted UI&lt;/a&gt; which will simplify a lot the Sign Up and Sign In flows.&lt;/p&gt;

&lt;p&gt;For the moment, bear with me, fill the &lt;code&gt;App Client settings&lt;/code&gt; with the following values and just click &lt;code&gt;Save&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FbpxWvGH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/05-create-cognito-pool.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FbpxWvGH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/05-create-cognito-pool.png" alt="Customizing the App Client"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A couple of things to note here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The callback url will be a backend endpoint we’ll be exposing in our app.&lt;/li&gt;
&lt;li&gt;The Sign Out url is the final url to be redirected to once we’ve signed out from Cognito&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, for the &lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-integration.html"&gt;Cognito Hosted UI&lt;/a&gt; to work, we need to set up a &lt;strong&gt;domain&lt;/strong&gt;. Note that the domain you choose is subjected to availability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gMOJCZwA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/06-create-cognito-pool.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gMOJCZwA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/06-create-cognito-pool.png" alt="Setting up the domain"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s move away from Cognito for the moment and let’s focus again on our &lt;code&gt;Svelte&lt;/code&gt; app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leveraging SvelteKit Auth library
&lt;/h2&gt;

&lt;p&gt;Luckily for us, &lt;a href="https://ravianand.web.app/"&gt;RaviAnand Mohabir&lt;/a&gt; has created a super cool library called &lt;a href="https://github.com/Dan6erbond/sk-auth"&gt;SvelteKit Auth&lt;/a&gt;, based on &lt;a href="https://next-auth.js.org/"&gt;NextAuth.js&lt;/a&gt;, which will allow us to use some of the most popular identity providers, such as Google, Twitch, Facebook, Twitter and Reddit.&lt;/p&gt;

&lt;p&gt;But not only that, it also provides a &lt;strong&gt;generic OAuth2 provider&lt;/strong&gt; that we will leverage to authenticate our users with Cognito.&lt;/p&gt;

&lt;p&gt;The library handles all the OAuth2 flow for you, including the redirects, the token exchange and the user profile retrieval.&lt;/p&gt;

&lt;p&gt;Let’s add the dependency to our app before we continue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i sk-auth &lt;span class="nt"&gt;--save&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating our Cognito Provider
&lt;/h3&gt;

&lt;p&gt;Let’s create a new file called &lt;code&gt;src/lib/auth.js&lt;/code&gt; and paste the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SvelteKitAuth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Providers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sk-auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// this is the domain we set up in our Cognito Pool&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DOMAIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sveltekit.auth.eu-west-1.amazoncognito.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// these are the configuration seetings for our OAUTH2 provider&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;accessTokenUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;DOMAIN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/oauth2/token`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;profileUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;DOMAIN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/oauth2/userInfo`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;authorizationUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;DOMAIN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/oauth2/authorize`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://robertohuertas.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_CLIENT_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;openid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cognito&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// IMPORTANT: this is the id that we'll use to identify our provider&lt;/span&gt;
    &lt;span class="na"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/x-www-form-urlencoded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oauthProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Providers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OAuth2Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// exposing our auth object&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appAuth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SvelteKitAuth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;oauthProvider&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Probably, if it’s the first time you’ve seen something like &lt;code&gt;import.meta.env.VITE_whatever&lt;/code&gt;, you’ll be wondering what the hell is that.&lt;/p&gt;

&lt;p&gt;Basically, it’s the way to get some environment variables from an &lt;code&gt;.env&lt;/code&gt; file in your root.&lt;/p&gt;

&lt;p&gt;You can find more info about it &lt;a href="https://kit.svelte.dev/faq#how-do-i-use-environment-variables"&gt;in the SvelteKit FAQs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So make sure to add the following to your &lt;code&gt;.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;VITE_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your_client_id&amp;gt;
&lt;span class="nv"&gt;VITE_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your_client_secret&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exposing the Auth object endpoints
&lt;/h3&gt;

&lt;p&gt;Now, let’s create a new file called &lt;code&gt;src/routes/api/auth/[...auth].js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If that felt strange to you, you have to know that this kind of naming is a &lt;a href="https://kit.svelte.dev/docs#routing-advanced"&gt;routing convention from SvelteKit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can use this piece of code to expose the auth endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// we're importing our auth object here&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;appAuth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// and exposing the get and post method handlers&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;appAuth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using the Auth object getSession method
&lt;/h3&gt;

&lt;p&gt;The Auth object exposes a &lt;a href="https://kit.svelte.dev/docs#hooks-getsession"&gt;getSession method&lt;/a&gt; that we can use in our &lt;code&gt;hooks.js&lt;/code&gt; file in order to return a session that it’s accessible on the client.&lt;/p&gt;

&lt;p&gt;As we have used the &lt;em&gt;Skeleton&lt;/em&gt; project, we don’t have any &lt;code&gt;hooks.js&lt;/code&gt; file yet. Let’s create one in the &lt;code&gt;src&lt;/code&gt; folder and add this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;appAuth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getSession&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;appAuth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, the claims of the access token will be available on the &lt;em&gt;session&lt;/em&gt; store.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding some interaction in the UI
&lt;/h2&gt;

&lt;p&gt;We’re going to add now some actions to the buttons in our UI, so let’s open our &lt;code&gt;src/index.svelte&lt;/code&gt; file and edit it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;signOut&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;authSignOut&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sk-auth/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$app/stores&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// getting the user from the session store&lt;/span&gt;
    &lt;span class="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/auth/signin/cognito?redirect=/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;authSignOut&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;svelte:head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;SvelteKit - Cognito&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svelte:head&amp;gt;&lt;/span&gt;

{#if !user}
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;"{signIn}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Log In with Cognito&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
{:else}
    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Welcome {user.email}!&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Your username is {user.username} and your email has been verified: {user.email_verified}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;{signOut}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Log Out&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
{/if}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that we’ve added some actions to the buttons which are fairly self-explanatory.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;signIn&lt;/code&gt; action will redirect the user to our &lt;code&gt;api/auth&lt;/code&gt; endpoint (the one we set up in the previous step) with &lt;code&gt;signin&lt;/code&gt; and &lt;code&gt;cognito&lt;/code&gt; as parameters (remember that we set the id of our provider to &lt;code&gt;cognito&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;redirect&lt;/code&gt; querystring parameter will tell the endpoint to redirect the user to our &lt;code&gt;/&lt;/code&gt; route once the user is authenticated.&lt;/p&gt;

&lt;p&gt;Let’s run the app and click over the &lt;code&gt;Log In with Cognito&lt;/code&gt; button. You should see the &lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-integration.html"&gt;Cognito Hosted UI&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wnp0_LKs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/07-sign-in.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wnp0_LKs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/07-sign-in.png" alt="Cognito Hosted UI Sign In"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we don’t have any account yet, let’s click over the &lt;code&gt;Sign Up&lt;/code&gt; link and create a test user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PlNYAnh3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/08-sign-up.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PlNYAnh3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/08-sign-up.png" alt="Cognito Hosted UI Sign Up"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use a &lt;strong&gt;real email address&lt;/strong&gt; as Cognito will send you a &lt;strong&gt;verification email&lt;/strong&gt; with a code you’ll need to enter in the UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m8hZsELt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/09-confirm-email.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m8hZsELt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/09-confirm-email.png" alt="Cognito Hosted UI Confirm email"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve confirmed your email, you’ll be redirected to the &lt;code&gt;/&lt;/code&gt; route but, this time, you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nx9oBPBh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/10-logged-in.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nx9oBPBh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/10-logged-in.png" alt="Logged In"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you check your Cognito pool, you should be able to see the user you just created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lav6QTrj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/11-user-created.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lav6QTrj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/11-user-created.png" alt="User created in the pool"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that &lt;a href="https://github.com/Dan6erbond/sk-auth"&gt;SvelteKit Auth&lt;/a&gt; will set an &lt;code&gt;HttpOnly&lt;/code&gt; cookie in order to manage the session for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3rU4-kzR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/12-cookie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3rU4-kzR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/sveltekit-cognito-authentication/12-cookie.png" alt="Cookie"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As you can see, setting up an OAuth2 provider is pretty easy with &lt;a href="https://github.com/Dan6erbond/sk-auth"&gt;SvelteKit Auth&lt;/a&gt;. If you need further adjustments, check out the repository. If you take a look at the example app, you’ll see plenty of ways to adjust your flow.&lt;/p&gt;

&lt;p&gt;As a final note, I would like to mention that our &lt;code&gt;Log Out&lt;/code&gt; button is not really logging out our user from Cognito as we’re only removing the cookie from our browser. So if you try to log in again, you’ll probably be logged in without having to introduce any credentials.&lt;/p&gt;

&lt;p&gt;As a way to mitigate this, you can clear the Cognito Hosted UI domain cookies or you just can extend the log out functionality by calling the &lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/logout-endpoint.html"&gt;logout endpoint from AWS Cognito&lt;/a&gt;. Give it a try!&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
Originally published at &lt;a href="https://robertohuertas.com/2021/07/25/sveltekit-cognito-authentication/"&gt;robertohuertas.com&lt;/a&gt; on Jul 25, 2021.&lt;/p&gt;

</description>
      <category>svelte</category>
      <category>sveltekit</category>
      <category>cognito</category>
      <category>oauth2</category>
    </item>
    <item>
      <title>Deploy an IPv6 Azure VM while setting up a Nym node</title>
      <dc:creator>Roberto Huertas</dc:creator>
      <pubDate>Sun, 18 Jul 2021 22:00:00 +0000</pubDate>
      <link>https://dev.to/robertohuertasm/deploy-an-ipv6-azure-vm-while-setting-up-a-nym-node-4lpp</link>
      <guid>https://dev.to/robertohuertasm/deploy-an-ipv6-azure-vm-while-setting-up-a-nym-node-4lpp</guid>
      <description>&lt;p&gt;Learn how to deploy an Azure VM with IPv6 support while setting up a &lt;a href="https://nymtech.net/"&gt;Nym&lt;/a&gt; node.&lt;/p&gt;

&lt;h2&gt;
  
  
  A little bit of context
&lt;/h2&gt;

&lt;p&gt;I’m lately looking into cool crypto projects, mainly because most of them make an extensive use of &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt; and that’s always and extra motivation for me 😁.&lt;/p&gt;

&lt;p&gt;One that has caught my attention is &lt;a href="https://nymtech.net/"&gt;Nym&lt;/a&gt;, which promises a &lt;strong&gt;huge improvement&lt;/strong&gt; both in terms of &lt;strong&gt;privacy and security&lt;/strong&gt; while we're using the internet. &lt;a href="https://techcrunch.com/2021/07/16/nym-gets-6m-for-its-anonymous-overlay-mixnet-to-sell-privacy-as-a-service/"&gt;It has recently raised $6M&lt;/a&gt; so this not only shows that the project it's catching the attention of &lt;strong&gt;many diverse investors&lt;/strong&gt; but also speaks of its capability to start growing and increasing its development pace.&lt;/p&gt;

&lt;p&gt;Long story short, I was trying to set up a &lt;a href="https://nymtech.net/docs/run-nym-nodes/"&gt;Nym node&lt;/a&gt; - as running a node in &lt;a href="https://medium.com/nymtech/nym-v0-11-0-and-testnet-milhon-6ed9c800f889"&gt;Milhon&lt;/a&gt; (their next version of the Testnet) will only be open to those who have run a node in &lt;a href="https://medium.com/nymtech/nym-version-0-10-0-and-testnet-finney-fb696a157e02"&gt;Finney&lt;/a&gt; (their current version of the Testnet) - and thought of doing that in &lt;a href="https://azure.microsoft.com/"&gt;Azure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I read the &lt;a href="https://nymtech.net/docs/run-nym-nodes/"&gt;Nym docs&lt;/a&gt; and all seemed pretty straightforward. What could go wrong? It seems that for the &lt;code&gt;Nym&lt;/code&gt; node to work ok, &lt;a href="https://nymtech.net/docs/run-nym-nodes/troubleshooting/#no-ipv6-connectivity"&gt;it has to have an &lt;code&gt;IPv6&lt;/code&gt; address&lt;/a&gt; and &lt;a href="https://azure.microsoft.com/"&gt;Azure&lt;/a&gt; was not going to let me walk away so easily…&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Setting up &lt;code&gt;IPv6&lt;/code&gt; in an Azure VM &lt;strong&gt;cannot be done&lt;/strong&gt; by using the &lt;code&gt;Portal&lt;/code&gt;. It’s also &lt;strong&gt;impossible to set it up in an already existing VM&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here you are a &lt;a href="(https://nymtech.net/docs/run-nym-nodes/)"&gt;link to the official Azure docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The steps to create an IPv6 VM
&lt;/h2&gt;

&lt;p&gt;You could do all this via your command line but I will show you how I used the &lt;a href="https://portal.azure.com/"&gt;Azure Portal&lt;/a&gt; for everything except the VM creation.&lt;/p&gt;

&lt;p&gt;These are the different steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a couple of public IP addresses&lt;/li&gt;
&lt;li&gt;Create a Virtual Network&lt;/li&gt;
&lt;li&gt;Create a Network Interface&lt;/li&gt;
&lt;li&gt;Create a Network Security Group&lt;/li&gt;
&lt;li&gt;Create the VM&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Create a couple of public IP addresses
&lt;/h3&gt;

&lt;p&gt;Let’s create a couple of &lt;a href="https://docs.microsoft.com/en-us/azure/virtual-network/public-ip-addresses"&gt;public IP addresses&lt;/a&gt;, IPv4 and IPv6, respectively. We can create them both at the same time, which is cool as it will save us some time.&lt;/p&gt;

&lt;p&gt;Let’s select the option in the &lt;a href="https://portal.azure.com/"&gt;Azure Portal&lt;/a&gt; and just click &lt;code&gt;Create&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rJXtZZ4z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-public-ip_01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rJXtZZ4z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-public-ip_01.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select &lt;code&gt;Both&lt;/code&gt; in the first option and just fill in the names of your IPs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XcjWJGT1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-public-ip_02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XcjWJGT1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-public-ip_02.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, just click &lt;code&gt;Create&lt;/code&gt; and in a couple of seconds you’ll have your two new shiny IPs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l-xhn5fO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-public-ip_03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l-xhn5fO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-public-ip_03.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Virtual Network
&lt;/h3&gt;

&lt;p&gt;Next, we will create a &lt;a href="https://docs.microsoft.com/en-us/azure/virtual-network/virtual-networks-overview"&gt;Virtual Network&lt;/a&gt; which is the fundamental building block for your private network in Azure.&lt;/p&gt;

&lt;p&gt;Similar to what we did in the previous section, we look for the &lt;code&gt;virtual network&lt;/code&gt; option and click over the &lt;code&gt;Create&lt;/code&gt; button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dEJnSQ36--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-virtual-network_01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dEJnSQ36--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-virtual-network_01.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, we just have to go through the different tabs, setting the name of the virtual network,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PBl_NnUE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-virtual-network_02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PBl_NnUE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-virtual-network_02.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and then configuring the IP addresses in there. Be sure to select the &lt;code&gt;Add IPv6 address space&lt;/code&gt; checkbox:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qI1cCaL5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-virtual-network_03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qI1cCaL5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-virtual-network_03.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll notice there’s a warning message stating that &lt;code&gt;subnets should have at least one IPv6 address range&lt;/code&gt;. Let’s click over the &lt;code&gt;default&lt;/code&gt; subnet name and a sidebar will open.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uU09quTU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-virtual-network_04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uU09quTU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-virtual-network_04.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This time, tick the &lt;code&gt;Add IPv6 address space&lt;/code&gt; checkbox, fill the IPv6 range, and click the &lt;code&gt;Save&lt;/code&gt; button. You’ll notice that the previous warning is gone and you’ll be able to follow the process. Click &lt;code&gt;Next&lt;/code&gt; and finally &lt;code&gt;Create&lt;/code&gt;the virtual network.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Network Interface
&lt;/h3&gt;

&lt;p&gt;Now, it’s time for us to &lt;a href="https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-network-interface"&gt;create a Network Interface&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As you may probably guess by now, we’re going to look for the &lt;code&gt;network interface&lt;/code&gt; option and click over the &lt;code&gt;Create&lt;/code&gt; button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0AL6TwW_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-interface_01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0AL6TwW_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-interface_01.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll find a form that you’ll have to fill.&lt;/p&gt;

&lt;p&gt;Give a name to the &lt;code&gt;network interface&lt;/code&gt; and tick the &lt;code&gt;Private IP address (IPv6)&lt;/code&gt; checkbox before creating the resource.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ld8k6dgc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-interface_02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ld8k6dgc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-interface_02.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have created it, go the resource and select the &lt;code&gt;IP configurations&lt;/code&gt; option in the left side menu. You’ll see a screen similar to the one below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zs7GDzcV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-interface_03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zs7GDzcV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-interface_03.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s configure our IPs. Click over the &lt;code&gt;Primary&lt;/code&gt; ip configuration, and make the appropriate selections. Once you select &lt;code&gt;Associate&lt;/code&gt; in the &lt;code&gt;Public IP address&lt;/code&gt; option you’ll be able to see a list with the IPs we created before. Select the IPv4 one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--565nalyo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-interface_04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--565nalyo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-interface_04.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we will do the same for the &lt;code&gt;Secondary&lt;/code&gt; ip configuration, the IPv6 one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N8mDAKUP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-interface_05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N8mDAKUP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-interface_05.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, let’s select &lt;code&gt;Properties&lt;/code&gt; in the left side menu and copy the &lt;code&gt;Resource ID&lt;/code&gt;. We’ll need it later in order to create our VM.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yVuwWZyM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-interface_06.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yVuwWZyM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-interface_06.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Network Security Group
&lt;/h3&gt;

&lt;p&gt;You can also create a &lt;a href="https://docs.microsoft.com/en-us/azure/virtual-network/network-security-groups-overview"&gt;Network Security Group&lt;/a&gt; and set it up in the &lt;code&gt;Network Interface&lt;/code&gt; so you can filter which ports are opened to the internet.&lt;/p&gt;

&lt;p&gt;The process if fairly straightforward.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pp6dDSqu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-security-group_01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pp6dDSqu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-security-group_01.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You just have to give it a name and create it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gXpr2BVR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-security-group_02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gXpr2BVR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-security-group_02.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, go to our &lt;code&gt;Network interface&lt;/code&gt; (&lt;em&gt;nym-nic&lt;/em&gt;) and select the &lt;code&gt;Network Security Group&lt;/code&gt; option in the right side menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--osHePVmL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-security-group_03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--osHePVmL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-network-security-group_03.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the VM
&lt;/h3&gt;

&lt;p&gt;In order to create the VM we will use the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/"&gt;Azure CLI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Go to your command line and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az login

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you are logged in, we’re going to create the VM by using this instruction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az vm create &lt;span class="nt"&gt;--resource-group&lt;/span&gt; nym-node-burn &lt;span class="nt"&gt;--name&lt;/span&gt; nym &lt;span class="nt"&gt;--image&lt;/span&gt; UbuntuLTS &lt;span class="nt"&gt;--admin-username&lt;/span&gt; robertohuertasm &lt;span class="nt"&gt;--admin-password&lt;/span&gt; hZRAAJpjkwZ4KW &lt;span class="nt"&gt;--nics&lt;/span&gt; &lt;span class="s2"&gt;"/subscriptions/e3871cc7-3444-42ad-b4b8-5ee6bdbf6d54/resourceGroups/nym-node-burn/providers/Microsoft.Network/networkInterfaces/nym-nic"&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; westeurope &lt;span class="nt"&gt;--size&lt;/span&gt; &lt;span class="s2"&gt;"Standard_B1s"&lt;/span&gt; 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can change the settings as you see fit but note that the &lt;code&gt;--nics&lt;/code&gt; flag must be informed with the &lt;code&gt;Resource ID&lt;/code&gt; we copied in the previous section.&lt;/p&gt;

&lt;p&gt;And that’s it! Your VM should be up and running!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OWyuUfAW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-vm_01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OWyuUfAW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/create-vm_01.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, you just have to connect via &lt;strong&gt;ssh&lt;/strong&gt; and run a &lt;a href="https://nymtech.net/docs/run-nym-nodes/"&gt;Nym node&lt;/a&gt; 😊, but first, be sure you’ve enabled port 22 access in your &lt;code&gt;Network Security Group&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lra6onwg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/ssh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lra6onwg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/azure-ipv6-vm-nym/ssh.png" alt="Container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
Originally published at &lt;a href="https://robertohuertas.com/2021/07/19/ipv6-azure-vm-nym-node/"&gt;robertohuertas.com&lt;/a&gt; on Jul 19, 2021.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>nym</category>
      <category>vm</category>
      <category>ipv6</category>
    </item>
    <item>
      <title>Aprende Rust en español</title>
      <dc:creator>Roberto Huertas</dc:creator>
      <pubDate>Mon, 25 May 2020 22:00:00 +0000</pubDate>
      <link>https://dev.to/robertohuertasm/aprende-rust-en-espanol-1pea</link>
      <guid>https://dev.to/robertohuertasm/aprende-rust-en-espanol-1pea</guid>
      <description>&lt;p&gt;Aprende &lt;a href="https://www.rust-lang.org/es/"&gt;Rust&lt;/a&gt; en español y a tu ritmo con estos vídeos de YouTube.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivación
&lt;/h2&gt;

&lt;p&gt;Personalmente, siempre tengo la sensación de que hay pocos recursos técnicos disponibles en nuestro idioma y, aunque el inglés es algo que debemos controlar para poder avanzar en nuestra industria, no sé si por mi edad o qué, la mayoría de las veces me parece que mi cerebro gasta más &lt;em&gt;ciclos de cpu&lt;/em&gt; de los necesarios para lograr comprender ciertos conceptos cuando leo o veo cosas que están en un idioma extranjero.&lt;/p&gt;

&lt;p&gt;Así que, por solidaridad a todos aquellos que sufren de este sobrecoste a la hora de aprender, pensé que sería interesante empezar una serie de vídeos para introducir a &lt;a href="https://www.rust-lang.org/es/"&gt;Rust&lt;/a&gt; a todos aquellos interesados en aprenderlo. 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  El plan
&lt;/h2&gt;

&lt;p&gt;La idea es usar &lt;a href="https://youtube.com/c/robertohuertasm"&gt;este canal de YouTube&lt;/a&gt; para ir publicando vídeos con una cadencia semanal.&lt;/p&gt;

&lt;p&gt;Esta cadencia, lógicamente, podrá variar en función de mi logistica familiar pero mi intención es ir a buen ritmo, al menos al principio. Por el momento ya llevo 10 de unos 150 que tengo planificados.&lt;/p&gt;

&lt;p&gt;Como podéis ver, el canal todavía no tiene ningún nombre especial porque &lt;a href="https://youtube.com/c/robertohuertasm"&gt;YouTube&lt;/a&gt; se reserva ese derecho sólo para aquellos canales que tienen muchos subscriptores. ¡Así que ya podéis &lt;a href="https://youtube.com/c/robertohuertasm"&gt;suscribiros&lt;/a&gt; y pasar el enlace a todos vuestros amigos! 😊&lt;/p&gt;

&lt;h2&gt;
  
  
  Una pequeña muestra
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/KOABboz7PBs"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Estructura
&lt;/h2&gt;

&lt;p&gt;Los vídeos se van a estructurar en dos grandes grupos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Curso de Rust&lt;/li&gt;
&lt;li&gt;Sesiones prácticas&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Curso de Rust
&lt;/h3&gt;

&lt;p&gt;Este curso intentará cubrir desde lo más básico a lo más complejo y, como he avanzado anteriormente, calculo que supondrá alrededor de 150 vídeos aproximadamente de unos 10 minutos de duración como máximo.&lt;/p&gt;

&lt;p&gt;Los temas a tratar, más o menos, serían estos y cada uno de ellos tendrá una lista de reproducción asociada:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/playlist?list=PLojDVPvSO1Dh-O3Lf0QHD6SeIKJR3YalY"&gt;Introducción a Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Z9d3aZV3hA8&amp;amp;list=PLojDVPvSO1DiN6Bi8qqIknFhcstuvBX6q"&gt;Variables y tipos primitivos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Control de flujo&lt;/li&gt;
&lt;li&gt;Tipos definidos por el usuario&lt;/li&gt;
&lt;li&gt;Colecciones&lt;/li&gt;
&lt;li&gt;Manejo de memoria&lt;/li&gt;
&lt;li&gt;Packages, crates y módulos&lt;/li&gt;
&lt;li&gt;Manejo de errores&lt;/li&gt;
&lt;li&gt;Genéricos y Traits&lt;/li&gt;
&lt;li&gt;Closures&lt;/li&gt;
&lt;li&gt;Iteradores&lt;/li&gt;
&lt;li&gt;Punteros inteligentes&lt;/li&gt;
&lt;li&gt;Concurrencia&lt;/li&gt;
&lt;li&gt;Errores personalizados&lt;/li&gt;
&lt;li&gt;Tests&lt;/li&gt;
&lt;li&gt;Programación asíncrona&lt;/li&gt;
&lt;li&gt;Cargo&lt;/li&gt;
&lt;li&gt;Extendiendo Cargo&lt;/li&gt;
&lt;li&gt;Documentación&lt;/li&gt;
&lt;li&gt;Macros&lt;/li&gt;
&lt;li&gt;Rust en la web y WASM&lt;/li&gt;
&lt;li&gt;Traits útiles&lt;/li&gt;
&lt;li&gt;Trucos sobre tipos&lt;/li&gt;
&lt;li&gt;Trucos sobre el manejo de memoria&lt;/li&gt;
&lt;li&gt;Trucos sobre el compilador&lt;/li&gt;
&lt;li&gt;Benchmarking, unsafe y CI/CD&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sesiones prácticas
&lt;/h3&gt;

&lt;p&gt;Estas sesiones prácticas serán vídeos más largos en los que abordaré algún tipo de problemática concreta y daré una especie de taller para que lo podáis seguir en línea.&lt;/p&gt;

&lt;p&gt;Entre los diferentes que tengo en mente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Construir un servidor gRPC usando Tonic [&lt;a href="https://github.com/robertohuertasm/rust-practical-sessions"&gt;échale un vistazo al repo&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;Construir un servidor REST usando Actix-web&lt;/li&gt;
&lt;li&gt;Construir un pequeño CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Declaración de intenciones
&lt;/h2&gt;

&lt;p&gt;Hace ya unos años que empecé a programar con &lt;a href="https://www.rust-lang.org/es/"&gt;Rust&lt;/a&gt; y por algún motivo me atrapó este lenguaje. En seguida sentí la necesidad de contactar con más gente que compartiera la pasión por este lenguaje y en 2018 organicé el &lt;a href="https://www.meetup.com/es-ES/BcnRust/"&gt;meetup de Rust de Barcelona&lt;/a&gt; y luego, al año siguiente, fui uno de los organizadores locales del &lt;a href="https://barcelona.rustfest.eu/about/"&gt;Rustfest&lt;/a&gt; que se llevó a cabo en Barcelona, que ha sido el más grande organizado hasta la fecha.&lt;/p&gt;

&lt;p&gt;Debido a las restricciones que nos ha impuesto el COVID-19, la actividad de nuestro meetup se ha visto reducida a cero y eso, unido a mi voluntad de llevar Rust a todos aquellos que están interesados en aprender, supongo que me ha llevado a la preparación de esta serie de vídeos.&lt;/p&gt;

&lt;p&gt;No soy el mejor comunicador, ni el mejor &lt;em&gt;youtuber&lt;/em&gt; pero lo voy a intentar. 😊&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EUDZt-Ih--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-espanol/dejame_intentar.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EUDZt-Ih--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-espanol/dejame_intentar.jpg" alt="Dejame intentar" title="Dejame intentar"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Espero que os guste la iniciativa y que le deis soporte, en la medida de lo posible.&lt;/p&gt;

&lt;p&gt;¡Nos vemos pronto!&lt;/p&gt;

&lt;p&gt;Roberto&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
Originally published at &lt;a href="https://robertohuertas.com/2020/05/26/rust-en-espa%C3%B1ol/"&gt;robertohuertas.com&lt;/a&gt; on May 26, 2020.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>tutorial</category>
      <category>video</category>
    </item>
    <item>
      <title>Sync your Figma assets with your dev environment</title>
      <dc:creator>Roberto Huertas</dc:creator>
      <pubDate>Sat, 18 Apr 2020 22:00:00 +0000</pubDate>
      <link>https://dev.to/robertohuertasm/sync-your-figma-assets-with-your-dev-environment-13bd</link>
      <guid>https://dev.to/robertohuertasm/sync-your-figma-assets-with-your-dev-environment-13bd</guid>
      <description>&lt;p&gt;Learn how to use &lt;a href="https://robertohuertasm.github.io/figma-asset-downloader"&gt;Figma Asset Downloader&lt;/a&gt; CLI to work with Figma like a boss!&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Recently, the Design team at &lt;a href="https://alpha.company"&gt;Alpha&lt;/a&gt; started to use &lt;a href="https://figma.com"&gt;Figma&lt;/a&gt; in order to prepare the assets for the app I'm currently involved in, which is called &lt;a href="https://evermind.health/"&gt;Evermind&lt;/a&gt; and aims to help people to build the skills needed to manage stress and become more resilient.&lt;/p&gt;

&lt;p&gt;Our Design team is really happy with the change from &lt;a href="https://www.sketch.com/"&gt;Sketch&lt;/a&gt; to &lt;a href="https://figma.com"&gt;Figma&lt;/a&gt;, and they really seem to be more productive and enjoy a lot the collaborative work that it promotes.&lt;/p&gt;

&lt;p&gt;Suffice to say, that if they are happy, this has a direct impact in the product and, hence, also in the Development team. Although &lt;a href="https://figma.com"&gt;Figma&lt;/a&gt; has actually a &lt;a href="https://help.figma.com/hc/en-us/articles/360040028114-Getting-Started-with-Exports"&gt;way to export images directly from their tool&lt;/a&gt; it rapidly became a bottleneck for our Development team: it was a pain to be constantly exporting and reorganizing the assets in a convenient folder structure for our mobile app (2x, 3x and so on...).&lt;/p&gt;

&lt;h2&gt;
  
  
  The investigation
&lt;/h2&gt;

&lt;p&gt;First, I decided to look for a tool that could be integrated in our development flow and automatically sync the assets from &lt;a href="https://figma.com"&gt;Figma&lt;/a&gt;. Some sort of CLI that would allow us to even integrate this into our CI pipelines if we needed it. The fact is that I couldn't find any kind of tool that suited our simple needs, so I decided to build my own.&lt;/p&gt;

&lt;p&gt;As you may know if you've read some of my previous articles, I'm very fond of &lt;a href="https://rust-lang.org"&gt;Rust&lt;/a&gt; so this was also an opportunity to write something with it and help to spread its usage 😉.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;Luckily for me, &lt;a href="https://figma.com"&gt;Figma&lt;/a&gt; has a super nice &lt;a href="https://www.figma.com/plugin-docs/api/api-overview/"&gt;API&lt;/a&gt; so it was really simple to build something that could export all the assets from any &lt;code&gt;Figma Document&lt;/code&gt; I wanted with just a simple command call.&lt;/p&gt;

&lt;p&gt;I just had to focus on building a nice CLI by leveraging the amazing &lt;a href="https://crates.io/crates/structopt"&gt;StructOpt&lt;/a&gt; crate and some of the usual suspects like &lt;a href="https://crates.io/crates/tokio"&gt;Tokio&lt;/a&gt;, &lt;a href="https://crates.io/crates/reqwest"&gt;Reqwest&lt;/a&gt; and &lt;a href="https://crates.io/crates/serde"&gt;Serde&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I stuck to the plan and eventually &lt;a href="https://robertohuertasm.github.io/figma-asset-downloader"&gt;Figma Asset Downloader&lt;/a&gt; CLI came to life. It was simple, and it worked for us! 🎉&lt;/p&gt;

&lt;p&gt;Read the &lt;a href="https://robertohuertasm.github.io/figma-asset-downloader"&gt;docs&lt;/a&gt; if you want to learn more about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The improvements
&lt;/h2&gt;

&lt;p&gt;After some days of using it, although we were happy with it, we found that the images generated from &lt;a href="https://figma.com"&gt;Figma&lt;/a&gt; were not being really optimized: &lt;code&gt;jpg&lt;/code&gt; images were huge, and we felt that &lt;code&gt;png&lt;/code&gt; optimization could be improved a little bit, too.&lt;/p&gt;

&lt;p&gt;So I put some super cool crates into the mix, namely &lt;a href="https://crates.io/crates/image"&gt;image&lt;/a&gt; for &lt;code&gt;jpg&lt;/code&gt; and &lt;a href="https://crates.io/crates/oxipng"&gt;oxipng&lt;/a&gt; for &lt;code&gt;png&lt;/code&gt;, and &lt;em&gt;voilà&lt;/em&gt;, we got some cool &lt;strong&gt;image optimization&lt;/strong&gt; capabilities into the CLI, just right away! 😮&lt;/p&gt;

&lt;h2&gt;
  
  
  The roadmap
&lt;/h2&gt;

&lt;p&gt;The tool is &lt;strong&gt;open source&lt;/strong&gt; and it's been published under the &lt;a href="https://github.com/robertohuertasm/figma-asset-downloader/blob/master/LICENSE.md"&gt;MIT license&lt;/a&gt;, so feel free to use it, adapt it and extend it.&lt;/p&gt;

&lt;p&gt;Although the roadmap of this tool is mainly driven by the needs of my &lt;a href="https://evermind.health/about-our-team"&gt;current team&lt;/a&gt; at &lt;a href="https://alpha.company"&gt;Alpha Health&lt;/a&gt;, I'll be more than happy to hear other team's needs and perhaps try to implement these new features into it.&lt;/p&gt;

&lt;p&gt;For the moment, as per one of my team colleagues suggestion, I'm considering to extend it by adding some sort of manifest that could help you to identify which files have changed their name, just to avoid having missing images in your app due to some misspelling in the &lt;a href="https://figma.com"&gt;Figma&lt;/a&gt; asset.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;EDIT:&lt;/strong&gt; This feature was added on April 30th, 2020&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course, that's only an example.&lt;/p&gt;

&lt;p&gt;Not only I'm hoping that this tool will be extended by the suggestions and efforts of other teams but I'm verifying that it's also increasing the interest of my teammates in &lt;a href="https://rust-lang.org"&gt;Rust&lt;/a&gt; as a language, so, so far, it has been worth developing it.&lt;/p&gt;

&lt;p&gt;Enjoy! 😊&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
Originally published at &lt;a href="https://robertohuertas.com/2020/04/19/figma-asset-downloader/"&gt;robertohuertas.com&lt;/a&gt; on April 19, 2020.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>tools</category>
      <category>figma</category>
      <category>design</category>
    </item>
    <item>
      <title>Wallpapers for the Rust of us</title>
      <dc:creator>Roberto Huertas</dc:creator>
      <pubDate>Sat, 07 Dec 2019 23:00:00 +0000</pubDate>
      <link>https://dev.to/robertohuertasm/wallpapers-for-the-rust-of-us-33p4</link>
      <guid>https://dev.to/robertohuertasm/wallpapers-for-the-rust-of-us-33p4</guid>
      <description>&lt;p&gt;Before &lt;a href="https://barcelona.rustfest.eu/" rel="noopener noreferrer"&gt;Barcelona’s RustFest edition&lt;/a&gt;, I created some wallpapers for the occasion. It’s time to share them with the community.&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_abstract.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_abstract.png" title="Abstract" alt="Abstract"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_abstract.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/abstract_swirl_design-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Blue
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_blue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_blue.png" title="Blue" alt="Blue"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_blue.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/blurry_blue_background_2-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Broken
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_broken.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_broken.png" title="Broken" alt="Broken"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_broken.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="https://wallpaperaccess.com/download/black-metal-4k-654212" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Camouflage
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_camouflage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_camouflage.png" title="Camouflage" alt="Camouflage"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_camouflage.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/military_camouflage_patterns-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Circuits
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_circuits.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_circuits.png" title="Circuits" alt="Circuits"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_circuits.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/circuit_board_art-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Circus
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_circus.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_circus.png" title="Circus" alt="Circus"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_circus.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/brown_retro_background-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Color
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_color.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_color.png" title="Color" alt="Color"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_color.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="https://wallpaperset.com/w/full/2/0/c/30383.jpg" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fuchsia
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_fuchsia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_fuchsia.png" title="Fuchsia" alt="Fuchsia"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_fuchsia.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_fuchsia_border.png" rel="noopener noreferrer"&gt;Alt&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/fuchsia_light-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Laser
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_laser.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_laser.png" title="Laser" alt="Laser"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_laser.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/laser_beams-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Metal
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_metal_soft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_metal_soft.png" title="Metal" alt="Metal"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_metal_soft.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="https://wallpaperaccess.com/download/black-metal-4k-654287" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mondrian
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_mondrian.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_mondrian.png" title="Mondrian" alt="Mondrian"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_mondrian.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_mondrian_light.png" rel="noopener noreferrer"&gt;Alt&lt;/a&gt; / &lt;a href="https://swiatowid.org.pl/home-2/wallpaper-full-hd-1080-x-1920-smartphone-diagonal-abstract/" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  More color
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_more_color.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_more_color.png" title="More color" alt="More color"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_more_color.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="https://www.lgbtyouth.org.uk/img/footer-pattern.jpg" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Old
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_old.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_old.png" title="Old" alt="Old"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_old.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="https://www.goodfon.com/wallpaper/stimpank-oboi-chasy-stil.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Old Paper
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_old_paper.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_old_paper.png" title="Old Paper" alt="Old Paper"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_old_paper.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/old_paper_2-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Polygon
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_polygon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_polygon.png" title="Polygon" alt="Polygon"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_polygon.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_polygon_blended.png" rel="noopener noreferrer"&gt;Alt&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/red_and_black_low_poly_background-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rainbow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_rainbow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_rainbow.png" title="Rainbow" alt="Rainbow"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_rainbow.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="https://www.lgbtyouth.org.uk/img/footer-pattern.jpg" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Red Fiber
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_red_fiber.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_red_fiber.png" title="Red Fiber" alt="Red Fiber"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_red_fiber.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/geometric_fiber_wm-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rusty
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_rusty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_rusty.png" title="Rusty" alt="Rusty"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_rusty.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="https://i.pinimg.com/originals/6e/20/ba/6e20ba03e3c12bebb09a7e2f8ae70bb9.jpg" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sound
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_sound.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_sound.png" title="Sound" alt="Sound"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_sound.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/unheard_sounds-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Steam
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_steam.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_steam.png" title="Steam" alt="Steam"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_steam.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="https://shazoo.ru/2017/03/06/49650/nemnogo-realizma-nikomu-ne-povredit" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sunset
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_sunset.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_sunset.png" title="Sunset" alt="Sunset"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_sunset.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="https://steamcommunity.com/sharedfiles/filedetails/?l=turkish&amp;amp;id=1548688862" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wall
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_wall.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_wall.png" title="Wall" alt="Wall"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_wall.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/schwinn_bicycle-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wood
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_wood.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frobertohuertas.com%2Fassets%2Fimages%2Fwallpapers%2Freduced%2Frust_wood.png" title="Wood" alt="Wood"&gt;&lt;/a&gt;&lt;a href="https://robertohuertas.com/assets/images/wallpapers/original/rust_wood.png" rel="noopener noreferrer"&gt;Download&lt;/a&gt; / &lt;a href="http://wallpaperswide.com/wooden_panels_2-wallpapers.html" rel="noopener noreferrer"&gt;Original source&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Attributions
&lt;/h3&gt;

&lt;p&gt;These wallpapers were created by using some amazing wallpapers as the original background and my only contribution was to insert the &lt;code&gt;Rust&lt;/code&gt; logo on them with more or less success, so all the credit goes to the original authors. You can access to the original source where I got these primary wallpapers below the images and besides the &lt;code&gt;Download&lt;/code&gt; link.&lt;/p&gt;

&lt;p&gt;Enjoy! 😊&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
Originally published at &lt;a href="https://robertohuertas.com/2019/12/08/wallpapers-for-the-rust-of-us/" rel="noopener noreferrer"&gt;robertohuertas.com&lt;/a&gt; on December 8, 2019.&lt;/p&gt;

</description>
      <category>rust</category>
    </item>
    <item>
      <title>Rust once and share it with Android, iOS and Flutter</title>
      <dc:creator>Roberto Huertas</dc:creator>
      <pubDate>Sat, 26 Oct 2019 22:00:00 +0000</pubDate>
      <link>https://dev.to/robertohuertasm/rust-once-and-share-it-with-android-ios-and-flutter-286o</link>
      <guid>https://dev.to/robertohuertasm/rust-once-and-share-it-with-android-ios-and-flutter-286o</guid>
      <description>&lt;p&gt;What if I told you that you could use the same very performant code in &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt;, &lt;a href="https://www.apple.com/es/ios/"&gt;iOS&lt;/a&gt; or even in &lt;a href="https://flutter.dev"&gt;Flutter&lt;/a&gt;. In this article, we’ll see how to achieve this with &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  But, why would we want something like this?
&lt;/h2&gt;

&lt;p&gt;Imagine that you have a mobile app that needs to process some audio in order to get some insights about the user but you don’t want the audio to be sent to the server to be processed. You want to preserve the privacy of the user. In this kind of scenario it would make sense to avoid having to write a library for &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt; and for &lt;a href="https://www.apple.com/ios/"&gt;iOS&lt;/a&gt;. That would save us from having to maintain two different codebases and would diminish the chance to get more bugs.&lt;/p&gt;

&lt;p&gt;That’s nice, but how could we do something like this? Enter &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt;. With &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt; not only would you be able to share the same code among multiple platforms, but you could also take advantage of the boost of performance that you will get.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are we going to do
&lt;/h2&gt;

&lt;p&gt;We are going to write a simple shared &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt; library and compile it to &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt; and &lt;a href="https://www.apple.com/ios/"&gt;iOS&lt;/a&gt;, and as a bonus, we will also write a &lt;a href="https://flutter.dev"&gt;Flutter&lt;/a&gt; plugin using the very same code.&lt;/p&gt;

&lt;p&gt;As you can see, the scope of this article is quite broad so we’ll try to keep everything organized.&lt;/p&gt;

&lt;p&gt;You can also read this post while taking a look at the &lt;a href="https://github.com/robertohuertasm/rust-for-android-ios-flutter"&gt;associated GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaffolding our project
&lt;/h2&gt;

&lt;p&gt;Let’s start by creating a folder called &lt;code&gt;rust-for-android-ios-flutter&lt;/code&gt; and create four folders in it (&lt;code&gt;android&lt;/code&gt;, &lt;code&gt;ios&lt;/code&gt;, &lt;code&gt;flutter&lt;/code&gt; &amp;amp; &lt;code&gt;rust&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;rust-for-android-ios-flutter
&lt;span class="nb"&gt;cd &lt;/span&gt;rust-for-android-ios-flutter
&lt;span class="nb"&gt;mkdir &lt;/span&gt;ios android rust flutter

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have it, just &lt;code&gt;cd&lt;/code&gt; into the &lt;code&gt;rust&lt;/code&gt; folder and create a new &lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt; library called &lt;code&gt;rustylib&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;rust
cargo init &lt;span class="nt"&gt;--name&lt;/span&gt; rustylib &lt;span class="nt"&gt;--lib&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This library will have only one function that will get a &lt;code&gt;string&lt;/code&gt; as its argument and will return a new &lt;code&gt;string&lt;/code&gt;. Basically, just a &lt;code&gt;Hello, World!&lt;/code&gt;. But just think of it as a function that could work as the entry point to a more complex process completely written in &lt;a href="https://github.com/rust-lang/"&gt;Rust&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s install some targets
&lt;/h2&gt;

&lt;p&gt;In order to compile our &lt;code&gt;rustylib&lt;/code&gt; library to &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt; and &lt;a href="https://www.apple.com/ios/"&gt;iOS&lt;/a&gt; we will need to have some &lt;code&gt;targets&lt;/code&gt; installed in our machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Android targets&lt;/span&gt;
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android

&lt;span class="c"&gt;# iOS targets&lt;/span&gt;
rustup target add aarch64-apple-ios armv7-apple-ios armv7s-apple-ios x86_64-apple-ios i386-apple-ios

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tools for iOS
&lt;/h2&gt;

&lt;p&gt;For &lt;a href="https://developer.apple.com/ios"&gt;iOS&lt;/a&gt; we have to be sure that we have &lt;a href="https://developer.apple.com/xcode/"&gt;Xcode&lt;/a&gt; installed in our computer and the &lt;code&gt;Xcode build tools&lt;/code&gt; already set up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# install the Xcode build tools.&lt;/span&gt;
xcode-select &lt;span class="nt"&gt;--install&lt;/span&gt;
&lt;span class="c"&gt;# this cargo subcommand will help you create a universal library for use with iOS.&lt;/span&gt;
cargo &lt;span class="nb"&gt;install &lt;/span&gt;cargo-lipo
&lt;span class="c"&gt;# this tool will let you automatically create the C/C++11 headers of the library.&lt;/span&gt;
cargo &lt;span class="nb"&gt;install &lt;/span&gt;cbindgen

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we have also installed &lt;a href="https://github.com/TimNN/cargo-lipo"&gt;cargo-lipo&lt;/a&gt; and &lt;a href="https://github.com/eqrion/cbindgen"&gt;cbindgen&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools for Android
&lt;/h2&gt;

&lt;p&gt;For &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt;, we have to be sure that we have correctly set up the &lt;code&gt;$ANDROID_HOME&lt;/code&gt; environment variable. In &lt;code&gt;macOS&lt;/code&gt; this is tipically set to &lt;code&gt;~/Library/Android/sdk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is also recommended that you install &lt;a href="https://developer.android.com/studio"&gt;Android Studio&lt;/a&gt; and the &lt;a href="https://developer.android.com/ndk"&gt;NDK&lt;/a&gt;. Once you have everything installed, ensure that the &lt;code&gt;$NDK_HOME&lt;/code&gt; environment variable is properly set. In &lt;code&gt;macOS&lt;/code&gt; this should be tipically set to &lt;code&gt;~/Library/Android/sdk/ndk-bundle&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, we’re just going to install &lt;a href="https://github.com/bbqsrc/cargo-ndk"&gt;cargo-ndk&lt;/a&gt;, which handles finding the correct linkers and converting between the triples used in the &lt;a href="https://rust-lang.org/"&gt;Rust&lt;/a&gt; world to the triples used in the &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt; world:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;cargo-ndk

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rust library configuration
&lt;/h2&gt;

&lt;p&gt;The next step is to modify our &lt;code&gt;Cargo.toml&lt;/code&gt;. Make sure it looks similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[package]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"rustylib"&lt;/span&gt;
&lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.1.0"&lt;/span&gt;
&lt;span class="py"&gt;authors&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Roberto Huertas &amp;lt;roberto.huertas@outlook.com&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="py"&gt;edition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2018"&lt;/span&gt;

&lt;span class="c"&gt;# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html&lt;/span&gt;

&lt;span class="nn"&gt;[lib]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"rustylib"&lt;/span&gt;
&lt;span class="c"&gt;# this is needed to build for iOS and Android.&lt;/span&gt;
&lt;span class="py"&gt;crate-type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"staticlib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"cdylib"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c"&gt;# this dependency is only needed for Android.&lt;/span&gt;
&lt;span class="py"&gt;[target.'cfg(target_os&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"android"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="s"&gt;'.dependencies]&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="nn"&gt;jni&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.13.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;default-features&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  iOS project
&lt;/h2&gt;

&lt;p&gt;Now, let’s create an &lt;a href="https://www.apple.com/ios/"&gt;iOS&lt;/a&gt; project using &lt;a href="https://developer.apple.com/xcode/"&gt;Xcode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2-ZNhzQ_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/01-create-ios-project.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2-ZNhzQ_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/01-create-ios-project.png" alt="iOS project" width="880" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://www.apple.com/ios/"&gt;iOS&lt;/a&gt; you can use 2 different types of &lt;code&gt;user interface&lt;/code&gt;. As we want to show how to use both of them, let’s create two different kind of projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storyboard
&lt;/h3&gt;

&lt;p&gt;We’re choosing &lt;code&gt;Storyboard&lt;/code&gt; as our &lt;code&gt;user interface&lt;/code&gt; and we’re naming the project &lt;code&gt;rusty-ios-classic&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OZsqsVld--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/02-create-ios-project.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OZsqsVld--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/02-create-ios-project.png" alt="iOS project" width="880" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save it in the previously created &lt;code&gt;ios&lt;/code&gt; folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  SwiftUI
&lt;/h3&gt;

&lt;p&gt;Let’s create now a new &lt;code&gt;iOS&lt;/code&gt; project. But this time we’re going to select &lt;code&gt;SwiftUI&lt;/code&gt; as our &lt;code&gt;user interface&lt;/code&gt; and name it &lt;code&gt;rusty-ios&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1ttKCYin--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/03-create-ios-project.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1ttKCYin--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/03-create-ios-project.png" alt="iOS project" width="880" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save it again in the &lt;code&gt;ios&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Your treeview should look similar to this one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---hxUv7Xg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/04-treeview-ios.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---hxUv7Xg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/04-treeview-ios.png" alt="iOS treeview" width="255" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing our first Rust code
&lt;/h2&gt;

&lt;p&gt;Now, go to the &lt;code&gt;Rust&lt;/code&gt; project, open the &lt;code&gt;lib.rs&lt;/code&gt; file and make sure it looks exactly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;ffi&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;CStr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CString&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;os&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;c_char&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;c_char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="nb"&gt;c_char&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;c_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;CStr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_ptr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;recipient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="nf"&gt;.to_str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"you"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nn"&gt;CString&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from Rust: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.into_raw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;hello_release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="nb"&gt;c_char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.is_null&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nn"&gt;CString&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;#[no_mangle]&lt;/code&gt; attribute is vital here to avoid the compiler from changing the name of the function. We want the name of the function to be exported as it is.&lt;/p&gt;

&lt;p&gt;Note also that we’re using &lt;code&gt;extern "C"&lt;/code&gt;. This tells the compiler that this function will be called from outside &lt;code&gt;Rust&lt;/code&gt; and ensures that it is compiled using &lt;code&gt;C&lt;/code&gt; calling conventions.&lt;/p&gt;

&lt;p&gt;You may be wondering why on Earth we need this &lt;code&gt;hello_release&lt;/code&gt; function. The key here is to take a look at the &lt;code&gt;hello&lt;/code&gt; function. Using &lt;code&gt;CString&lt;/code&gt; and returning the raw representation keeps the string in memory and prevents it from being released at the end of the function. If the memory were to be released, the pointer provided back to the caller would now be pointing to empty memory or to something else entirely.&lt;/p&gt;

&lt;p&gt;In order to avoid a memory leak, because we have now a string that sticks around after the function has finishing executing, we have to provide the &lt;code&gt;hello_release&lt;/code&gt; function that takes a pointer to a &lt;code&gt;C string&lt;/code&gt; and frees that memory. It’s &lt;strong&gt;very important not to forget calling this function&lt;/strong&gt; from the &lt;code&gt;iOS&lt;/code&gt; code if we don’t want to get into troubles. If you look closely at this function, you’ll notice that it leverages the way memory is managed in &lt;code&gt;Rust&lt;/code&gt; by using the function’s scope in order to free the pointer.&lt;/p&gt;

&lt;p&gt;This code will be the one that we’ll use for our &lt;code&gt;iOS&lt;/code&gt; projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compiling for iOS
&lt;/h2&gt;

&lt;p&gt;Before we compile the library for &lt;a href="https://developer.apple.com/ios"&gt;iOS&lt;/a&gt; we’re going to generate a &lt;code&gt;C header&lt;/code&gt; that will work as a &lt;em&gt;bridge&lt;/em&gt; for our &lt;code&gt;Swift&lt;/code&gt; code to be able to call our &lt;code&gt;Rust&lt;/code&gt; code.&lt;/p&gt;

&lt;p&gt;We’ll be leveraging &lt;a href="https://github.com/eqrion/cbindgen"&gt;cbindgen&lt;/a&gt; for this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;rust
cbindgen src/lib.rs &lt;span class="nt"&gt;-l&lt;/span&gt; c &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; rustylib.h

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should generate a file called &lt;code&gt;rustylib.h&lt;/code&gt; containing the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdarg.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdbool.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdint.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;hello_release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that &lt;a href="https://github.com/eqrion/cbindgen"&gt;cbindgen&lt;/a&gt; has automatically generated the &lt;code&gt;C interface&lt;/code&gt; for us in a very convenient way.&lt;/p&gt;

&lt;p&gt;Now, let’s proceed to &lt;strong&gt;compile&lt;/strong&gt; our &lt;code&gt;Rust&lt;/code&gt; library so it can be consumed in any &lt;a href="https://www.apple.com/ios/"&gt;iOS&lt;/a&gt; project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# it's important to not forget the release flag.&lt;/span&gt;
cargo lipo &lt;span class="nt"&gt;--release&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out your &lt;code&gt;target/universal/release&lt;/code&gt; folder and look for a file called &lt;code&gt;librustylib.a&lt;/code&gt;. That’s the binary we’re going to use in our &lt;a href="https://www.apple.com/ios/"&gt;iOS&lt;/a&gt; projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the iOS binary
&lt;/h2&gt;

&lt;p&gt;First, we’re going to copy our &lt;code&gt;librustylib.a&lt;/code&gt; and &lt;code&gt;rustylib.h&lt;/code&gt; files into the &lt;code&gt;ios&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# we're still in the `rust` folder so...&lt;/span&gt;
&lt;span class="nv"&gt;inc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;../ios/include
&lt;span class="nv"&gt;libs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;../ios/libs

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;inc&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;libs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;cp &lt;/span&gt;rustylib.h &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;inc&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;target/universal/release/librustylib.a &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;libs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should be seeing a treeview like this one, with an &lt;code&gt;include&lt;/code&gt; and a &lt;code&gt;libs&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lWuQ7x3Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/05-copy-ios-files.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lWuQ7x3Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/05-copy-ios-files.png" alt="Copy iOS files" width="255" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can imagine, having to manually do this every time you have to compile a new version of your &lt;code&gt;Rust&lt;/code&gt; library would be very tedious. Fortunately, you can &lt;strong&gt;automate this process&lt;/strong&gt; by using a simple &lt;code&gt;bash&lt;/code&gt; script like &lt;a href="https://github.com/robertohuertasm/rust-for-android-ios-flutter/blob/master/rust/scripts/ios_build.sh"&gt;this one&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, the following is something that you will need to do &lt;strong&gt;only once&lt;/strong&gt; (twice if you have created two iOS projects as the article described).&lt;/p&gt;

&lt;p&gt;Let’s open our &lt;code&gt;rusty-ios-classic&lt;/code&gt; project in &lt;a href="https://developer.apple.com/xcode/"&gt;Xcode&lt;/a&gt; and let’s do the following:&lt;/p&gt;

&lt;p&gt;Add the &lt;code&gt;librustylib.a&lt;/code&gt; file in the &lt;code&gt;General &amp;gt; Frameworks, Libraries and Embedded Content&lt;/code&gt;. Ensure that you see the name of the library there. If it doesn’t show, try it again. I’m not sure if it’s an &lt;code&gt;Xcode&lt;/code&gt; bug but most of the times you’ll need to add it twice for it to work correctly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1OvtVKHi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/06-add-library.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1OvtVKHi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/06-add-library.png" alt="Add library" width="880" height="577"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, go to the &lt;code&gt;Build Settings&lt;/code&gt; tab, search for &lt;code&gt;search paths&lt;/code&gt; and add the &lt;code&gt;header&lt;/code&gt; and &lt;code&gt;library&lt;/code&gt; search paths. You can use relative paths or use the &lt;code&gt;$(PROJECT_DIR)&lt;/code&gt; variable to avoid hardcoding your local path.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PgK9fTuR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/07-add-search-paths.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PgK9fTuR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/07-add-search-paths.png" alt="Add header and library search paths" width="880" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, let’s add the &lt;code&gt;Objective-C Bridging header&lt;/code&gt;. Search for &lt;code&gt;bridging header&lt;/code&gt; in the &lt;code&gt;Build Settings&lt;/code&gt; tab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o7MtfEPQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/08-bridging-header.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o7MtfEPQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/08-bridging-header.png" alt="Add Objective-C bridging header" width="880" height="194"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repeat the same for our &lt;code&gt;rusty-ios&lt;/code&gt; project in case you want to try both type of &lt;a href="https://developer.apple.com/ios"&gt;iOS&lt;/a&gt; projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  In our rusty-ios project
&lt;/h3&gt;

&lt;p&gt;if you’re using the project that uses &lt;code&gt;SwiftUI&lt;/code&gt; as a user interface, then open the &lt;code&gt;ContentView.swift&lt;/code&gt; file and make it look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;SwiftUI&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ContentView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ContentView_Previews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PreviewProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;previews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;ContentView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Rob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// IMPORTANT: once we get the result we have to release the pointer.&lt;/span&gt;
    &lt;span class="nf"&gt;hello_release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UnsafeMutablePointer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;mutating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sr&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the project in &lt;a href="https://developer.apple.com/xcode/"&gt;Xcode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this case, you should be able to see &lt;code&gt;Hello from Rust: Rob&lt;/code&gt; in the emulator or device you’re using to test the app 🚀.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7E6EU_nO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/09-ios-result.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7E6EU_nO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/09-ios-result.png" alt="Show iOS result" width="300" height="659"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  In our rusty-ios-classic project
&lt;/h3&gt;

&lt;p&gt;In case you’re using a the project with a &lt;code&gt;Storyboard&lt;/code&gt; user interface, open the &lt;code&gt;ViewController.swift&lt;/code&gt; file and make it look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;UIKit&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ViewController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIViewController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;viewDidLoad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;viewDidLoad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="c1"&gt;// Do any additional setup after loading the view.&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Rob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;s_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// IMPORTANT: once we get the result we have to release the pointer.&lt;/span&gt;
        &lt;span class="nf"&gt;hello_release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UnsafeMutablePointer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;mutating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s_result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is fine, you should be able to see &lt;code&gt;Hello from Rust: Rob&lt;/code&gt; in the &lt;em&gt;output pane&lt;/em&gt;. 😉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oADcYwBN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/10-ios-classic-result.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oADcYwBN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/10-ios-classic-result.png" alt="Show iOS classic result" width="880" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Android project
&lt;/h2&gt;

&lt;p&gt;Let’s open &lt;a href="https://developer.android.com/studio"&gt;Android Studio&lt;/a&gt; and let’s create our &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt; project: &lt;code&gt;File &amp;gt; New...&amp;gt; New Project &amp;gt; Basic Activity&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6OmCuAk2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/11-create-android-project.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6OmCuAk2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/11-create-android-project.png" alt="Create Android project" width="880" height="705"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Name it &lt;code&gt;rusty-android&lt;/code&gt; and set the &lt;code&gt;package name&lt;/code&gt;. We’ll choose &lt;code&gt;Kotlin&lt;/code&gt; as our default language and &lt;code&gt;minimum API 22&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zk84z35z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/12-create-android-project.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zk84z35z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/12-create-android-project.png" alt="Create Android project" width="880" height="705"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should end up with a treeview similar to this one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t3V4AXps--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/13-android-treeview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t3V4AXps--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/13-android-treeview.png" alt="Android treeview" width="223" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  JNI
&lt;/h2&gt;

&lt;p&gt;If you remember when we discussed about how to create our &lt;a href="https://www.apple.com/ios/"&gt;iOS&lt;/a&gt; project, we needed to create a &lt;code&gt;C header&lt;/code&gt; working as a bridge. In &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt; we will leverage the &lt;code&gt;Java Native Interface&lt;/code&gt; or &lt;code&gt;JNI&lt;/code&gt; for short and we will expose our functions through it. The way that &lt;code&gt;JNI&lt;/code&gt; constructs the name of the function that will be called follows a specific convention: &lt;code&gt;Java_&amp;lt;domain&amp;gt;_&amp;lt;qualified_classname&amp;gt;_&amp;lt;methodname&amp;gt;&lt;/code&gt;. In our case, that would be &lt;code&gt;Java_com_robertohuertas_rusty_1android_MainActivity_hello&lt;/code&gt; (note that &lt;code&gt;_1&lt;/code&gt; represents underscores &lt;code&gt;_&lt;/code&gt; in the qualified class name).&lt;/p&gt;

&lt;p&gt;As you can imagine, if we have to name our functions in such a specific way, this can pose a problem if we want to reuse this very same code in other &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt; apps. We have several alternatives, though. We can use some sort of proxy class that follows the same specific domain and class naming and include it in every project or we can create an &lt;a href="https://developer.android.com/studio/projects/android-library"&gt;Android Library&lt;/a&gt; and use it everywhere.&lt;/p&gt;

&lt;p&gt;In our case, we’re going to create an &lt;a href="https://developer.android.com/studio/projects/android-library"&gt;Android Library&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Android Library
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://developer.android.com/studio/"&gt;Android Studio&lt;/a&gt;, &lt;code&gt;File &amp;gt; New &amp;gt; New Module...&lt;/code&gt;. Then choose &lt;code&gt;Android Library&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mVEv-73y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/14-create-android-library.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mVEv-73y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/14-create-android-library.png" alt="Creating the Android library" width="880" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bQv1plxF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/15-create-android-library.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bQv1plxF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/15-create-android-library.png" alt="Creating the Android library" width="880" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your &lt;a href="https://developer.android.com/studio"&gt;Android Studio&lt;/a&gt; project pane should look similar to the one below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---1b89jBs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/16-create-android-library.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---1b89jBs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/16-create-android-library.png" alt="Creating the Android library" width="627" height="649"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a little bit more Rust
&lt;/h2&gt;

&lt;p&gt;Ok, so let’s create our &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt; functions by leveraging the &lt;code&gt;JNI&lt;/code&gt; naming conventions.&lt;/p&gt;

&lt;p&gt;Let’s &lt;code&gt;cd&lt;/code&gt; into our &lt;code&gt;rust/src&lt;/code&gt; folder and create a new &lt;code&gt;android.rs&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;rust/src
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; android.rs

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have it, copy this code into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#![cfg(target_os&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"android"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="nd"&gt;#![allow(non_snake_case)]&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;jni&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;JClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JString&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;jni&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;jstring&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;jni&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;JNIEnv&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;ffi&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// NOTE: RustKt references the name rusty.kt, which will be the kotlin file exposing the functions below.&lt;/span&gt;
&lt;span class="c1"&gt;// Remember the JNI naming conventions.&lt;/span&gt;

&lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"system"&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;Java_com_robertohuertas_rusty_1android_1lib_RustyKt_helloDirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;JNIEnv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;JClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;JString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jstring&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;
    &lt;span class="nf"&gt;.get_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Couldn't get Java string!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;
    &lt;span class="nf"&gt;.new_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from Rust: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Couldn't create a Java string!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="nf"&gt;.into_inner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[allow(clippy::similar_names)]&lt;/span&gt;
&lt;span class="nd"&gt;#[no_mangle]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"system"&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;Java_com_robertohuertas_rusty_1android_1lib_RustyKt_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;JNIEnv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;JClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;JString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jstring&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;java_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="nf"&gt;.get_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Couldn't get Java string!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// we call our generic func for iOS&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;java_str_ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;java_str&lt;/span&gt;&lt;span class="nf"&gt;.as_ptr&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;java_str_ptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="c1"&gt;// freeing memory from CString in ios function&lt;/span&gt;
  &lt;span class="c1"&gt;// if we call hello_release we won't have access to the result&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result_ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nn"&gt;CString&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_raw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result_ptr&lt;/span&gt;&lt;span class="nf"&gt;.to_str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;
    &lt;span class="nf"&gt;.new_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Couldn't create a Java string!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="nf"&gt;.into_inner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait, what’s going on here? 🤔&lt;/p&gt;

&lt;p&gt;We’d better stop for a moment and explain a little bit the previous code.&lt;/p&gt;

&lt;p&gt;First of all, on the top of the file we can see two different directives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#![cfg(target_os&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"android"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="nd"&gt;#![allow(non_snake_case)]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first one will enable this code only when we’re compiling for &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt; and the second one will allow us to name our functions however we want. &lt;code&gt;Rust&lt;/code&gt; enforces &lt;code&gt;snake_case&lt;/code&gt; but we need to opt out of this in order to comply with the &lt;code&gt;JNI&lt;/code&gt; naming conventions.&lt;/p&gt;

&lt;p&gt;Ok, but then, why have you created two different functions (&lt;code&gt;helloDirect&lt;/code&gt; and &lt;code&gt;hello&lt;/code&gt;) and not just one? 🤔&lt;/p&gt;

&lt;p&gt;Well, the answer is that I wanted to show you two ways of handling the &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt; part and let you decide which one is more convenient for your kind of project.&lt;/p&gt;

&lt;p&gt;The first function uses the &lt;a href="https://github.com/jni-rs/jni-rs"&gt;jni crate&lt;/a&gt; without interacting with the &lt;code&gt;lib.rs&lt;/code&gt; code (a.k.a. iOS code) and the second one uses the same code we have in the &lt;code&gt;lib.rs&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The difference is clear. The first function is way clearer and more succint than the second one. Plus, in the second one, we have to deal with the &lt;code&gt;hello_release&lt;/code&gt; function and &lt;code&gt;unsafe&lt;/code&gt; while in the first one we don’t.&lt;/p&gt;

&lt;p&gt;So, what we should do? In my opinion, I would use the first one. This is a super simple example where we’re just building a string and returning it. Ideally, this logic should be also encapsulated in a pure &lt;code&gt;Rust&lt;/code&gt; library that would be consumed by both the &lt;code&gt;iOS&lt;/code&gt; and the &lt;code&gt;Android&lt;/code&gt; code. These pieces of code should be only concerned about providing the glue to the &lt;code&gt;iOS&lt;/code&gt; and &lt;code&gt;Android&lt;/code&gt; land via &lt;code&gt;C headers&lt;/code&gt; and &lt;code&gt;JNI&lt;/code&gt; and that’s it. So, ideally, in our example, instead of duplicating the logic in the &lt;code&gt;Java_com_robertohuertas_rusty_1android_1lib_RustyKt_helloDirect&lt;/code&gt; function we would call another library.&lt;/p&gt;

&lt;p&gt;Anyway, for the sake of knowing that you have several options, I think it’s good to explore all the approaches. 😜&lt;/p&gt;

&lt;p&gt;One more important thing. Note that we’re exporting our functions with &lt;code&gt;system&lt;/code&gt; instead of &lt;code&gt;C&lt;/code&gt;. This is just to stop &lt;a href="https://github.com/eqrion/cbindgen"&gt;cbindgen&lt;/a&gt; from generating signatures for these &lt;a href="https://www.android.com"&gt;Android&lt;/a&gt; functions.&lt;/p&gt;

&lt;p&gt;But wait, this won’t work! We haven’t exposed our &lt;code&gt;android&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;Add this to the &lt;code&gt;lib.rs&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// add it below the use declarations.&lt;/span&gt;
&lt;span class="nd"&gt;#[cfg(target_os&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"android"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;cfg&lt;/code&gt; attribute will prevent the &lt;code&gt;android&lt;/code&gt; module we just created to be compiled in case we’re not targeting &lt;a href="https://www.android.com/"&gt;Android&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compiling for Android
&lt;/h2&gt;

&lt;p&gt;Let’s get ready to compile our code for &lt;a href="https://www.android.com"&gt;Android&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;scripts&lt;/code&gt; folder inside the &lt;code&gt;rust&lt;/code&gt; folder and add a file called &lt;code&gt;android_build.sh&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# set the version to use the library&lt;/span&gt;
&lt;span class="nv"&gt;min_ver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;22
&lt;span class="c"&gt;# verify before executing this that you have the proper targets installed&lt;/span&gt;
cargo ndk &lt;span class="nt"&gt;--target&lt;/span&gt; aarch64-linux-android &lt;span class="nt"&gt;--android-platform&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;min_ver&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; build &lt;span class="nt"&gt;--release&lt;/span&gt;
cargo ndk &lt;span class="nt"&gt;--target&lt;/span&gt; armv7-linux-androideabi &lt;span class="nt"&gt;--android-platform&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;min_ver&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; build &lt;span class="nt"&gt;--release&lt;/span&gt;
cargo ndk &lt;span class="nt"&gt;--target&lt;/span&gt; i686-linux-android &lt;span class="nt"&gt;--android-platform&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;min_ver&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; build &lt;span class="nt"&gt;--release&lt;/span&gt;
cargo ndk &lt;span class="nt"&gt;--target&lt;/span&gt; x86_64-linux-android &lt;span class="nt"&gt;--android-platform&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;min_ver&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; build &lt;span class="nt"&gt;--release&lt;/span&gt;

&lt;span class="c"&gt;# moving libraries to the android project&lt;/span&gt;
&lt;span class="nv"&gt;jniLibs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;../android/rusty-android/rusty-android-lib/src/main/jniLibs
&lt;span class="nv"&gt;libName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;libdevicers.so

&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;jniLibs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;jniLibs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;jniLibs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/arm64-v8a
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;jniLibs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/armeabi-v7a
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;jniLibs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/x86
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;jniLibs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/x86_64

&lt;span class="nb"&gt;cp &lt;/span&gt;target/aarch64-linux-android/release/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;libName&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;jniLibs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/arm64-v8a/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;libName&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;target/armv7-linux-androideabi/release/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;libName&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;jniLibs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/armeabi-v7a/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;libName&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;target/i686-linux-android/release/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;libName&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;jniLibs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/x86/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;libName&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;target/x86_64-linux-android/release/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;libName&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;jniLibs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/x86_64/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;libName&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly to the &lt;a href="https://github.com/robertohuertasm/rust-for-android-ios-flutter/rust/scripts/ios_build.sh"&gt;previously suggested build script for iOS&lt;/a&gt;, this script will help us to compile and move the needed files to our previously created &lt;a href="https://developer.android.com/studio/projects/android-library"&gt;Android Library&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you execute this &lt;code&gt;bash script&lt;/code&gt;, once the compilation process ends you should be able to find a treeview similar to this one, with a newly created folder called &lt;code&gt;jniLibs&lt;/code&gt; with several subfolders in it referencing several architectures:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8FL-1GNI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/17-rust-android-treeview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8FL-1GNI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/17-rust-android-treeview.png" alt="Android Library Treeview" width="227" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing the Android Library
&lt;/h2&gt;

&lt;p&gt;Finally, we’re going to write our &lt;a href="https://developer.android.com/studio/projects/android-library"&gt;Android Library&lt;/a&gt; code and consume it from our &lt;a href="https://www.android.com"&gt;Android&lt;/a&gt; application.&lt;/p&gt;

&lt;p&gt;Let’s create a new file under &lt;code&gt;android/rusty-android-lib/src/main/java/com/robertohuertas/rusty_android_lib&lt;/code&gt; called &lt;code&gt;rusty.kt&lt;/code&gt;. Note that the name must be the same that we used when defining our &lt;code&gt;JNI&lt;/code&gt; functions in our &lt;code&gt;Rust&lt;/code&gt; library.&lt;/p&gt;

&lt;p&gt;Copy the following code in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.robertohuertas.rusty_android_lib&lt;/span&gt;

&lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;helloDirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;loadRustyLib&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadLibrary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"rustylib"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we just declared two signatures mirroring our two Rust functions (remember the name we gave them in our Rust code) and a function that will be called in order to dynamically load the library. Note that we’re not using the name of the library (&lt;em&gt;librustylib.so&lt;/em&gt;) but the name we gave to the crate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compiling the Android Library
&lt;/h2&gt;

&lt;p&gt;If you want to generate an &lt;code&gt;.aar&lt;/code&gt; file ready to be consumed by any &lt;a href="https://www.android.com"&gt;Android&lt;/a&gt; app just use the &lt;code&gt;Gradle&lt;/code&gt; tab of your &lt;a href="https://developer.android.com/studio"&gt;Android Studio&lt;/a&gt; and look for a task called &lt;code&gt;assemble&lt;/code&gt;. Right-click on it and select &lt;code&gt;Run&lt;/code&gt;. This will compile your library and you’ll be able to find it at &lt;code&gt;android/rusty-android-lib/build/outputs/aar/rusty-android-lib-release.aar&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FaJVtL6q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/18-android-library-aar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FaJVtL6q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/18-android-library-aar.png" alt="Android Library aar" width="357" height="686"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Consuming the Android Library
&lt;/h2&gt;

&lt;p&gt;In this case, we don’t need to consume the library as an &lt;code&gt;.aar&lt;/code&gt; file because we have it in the same project. In case you want to know how to consume it like that just take a look at the &lt;a href="https://developer.android.com/studio/projects/android-library"&gt;Android Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In our example, we just need to add the library as a dependency in our &lt;code&gt;android/app/build.gradle&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="nf"&gt;project&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;':rusty-android-lib'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, in our &lt;a href="https://developer.android.com/studio"&gt;Android Studio&lt;/a&gt;, choose &lt;code&gt;File &amp;gt; Sync project with Gradle files&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, open the file &lt;code&gt;content_main.xml&lt;/code&gt; located at &lt;code&gt;android/app/src/main/res/layout&lt;/code&gt; and add an &lt;code&gt;id&lt;/code&gt; to the &lt;code&gt;TextView&lt;/code&gt;, so we can reference it later and programmatically change its value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;android:id&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"@+id/txt"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, we’re going to use our &lt;a href="https://developer.android.com/studio/projects/android-library"&gt;Android Library&lt;/a&gt; from our &lt;code&gt;MainActivity.kt&lt;/code&gt; file located at &lt;code&gt;android/app/src/main/java/com/robertohuertas/rust_android&lt;/code&gt;. Open it and write this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.robertohuertas.rusty_android&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.os.Bundle&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.google.android.material.snackbar.Snackbar&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;androidx.appcompat.app.AppCompatActivity&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.view.Menu&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.view.MenuItem&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.widget.TextView&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;kotlinx.android.synthetic.main.activity_main.*&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.robertohuertas.rusty_android_lib.*&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setContentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activity_main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setSupportActionBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toolbar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;loadRustyLib&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;findViewById&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TextView&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Rob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;greeting2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;helloDirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Rob Direct"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;fab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="nc"&gt;Snackbar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;greeting2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Snackbar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LENGTH_LONG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreateOptionsMenu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Menu&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Inflate the menu; this adds items to the action bar if it is present.&lt;/span&gt;
        &lt;span class="n"&gt;menuInflater&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inflate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;menu_main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onOptionsItemSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MenuItem&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Handle action bar item clicks here. The action bar will&lt;/span&gt;
        &lt;span class="c1"&gt;// automatically handle clicks on the Home/Up button, so long&lt;/span&gt;
        &lt;span class="c1"&gt;// as you specify a parent activity in AndroidManifest.xml.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action_settings&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onOptionsItemSelected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’re done! Run it in your emulator and you should see a text in the app saying &lt;code&gt;Hello from Rust: Rob&lt;/code&gt;. Furthermore, if you click the button below, a &lt;code&gt;snackbar&lt;/code&gt; will show &lt;code&gt;Hello from Rust: Rob direct&lt;/code&gt;. As you can see, we’re using both functions, the one calling the &lt;code&gt;iOS&lt;/code&gt; function and the one using only the &lt;code&gt;jni-rs&lt;/code&gt; crate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7EVw9Xj9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/19-android-result.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7EVw9Xj9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/19-android-result.png" alt="Android App result" width="300" height="619"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Flutter Project
&lt;/h2&gt;

&lt;p&gt;And now… let’s go for the bonus points!&lt;/p&gt;

&lt;p&gt;As we already have an &lt;a href="https://developer.android.com/studio/projects/android-library"&gt;Android Library&lt;/a&gt; and a working &lt;code&gt;iOS&lt;/code&gt; project, making this work in a &lt;code&gt;Flutter&lt;/code&gt; project shouldn’t be very difficult.&lt;/p&gt;

&lt;p&gt;The basic idea is to create a &lt;a href="https://flutter.dev/docs/development/packages-and-plugins/developing-packages"&gt;Flutter plugin package&lt;/a&gt; so we can share our code in several &lt;code&gt;Flutter&lt;/code&gt; projects.&lt;/p&gt;

&lt;p&gt;So let’s start! 😀&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# let's use the flutter folder&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;flutter
&lt;span class="c"&gt;# create a plugin project, set its namespace and its name&lt;/span&gt;
flutter create &lt;span class="nt"&gt;--template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;plugin &lt;span class="nt"&gt;--org&lt;/span&gt; com.robertohuertas rusty_flutter_lib
&lt;span class="c"&gt;# now you'll have a folder called rusty_flutter_lib inside the flutter folder&lt;/span&gt;
&lt;span class="c"&gt;# for convenience, we'll move everything to the parent directory (flutter)&lt;/span&gt;
&lt;span class="c"&gt;# this last step is completely optional.&lt;/span&gt;
&lt;span class="nb"&gt;mv &lt;/span&gt;rusty_flutter_lib/&lt;span class="o"&gt;{&lt;/span&gt;.,&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; rusty_flutter_lib

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of the cool things of the &lt;a href="https://flutter.dev/docs/development/packages-and-plugins/developing-packages"&gt;Flutter plugin packages&lt;/a&gt; is that the template comes with an &lt;strong&gt;example project&lt;/strong&gt; so we can use it to test that our &lt;code&gt;plugin&lt;/code&gt; works as expected. No need to create a new project to test our &lt;code&gt;Flutter&lt;/code&gt; plugin.&lt;/p&gt;

&lt;p&gt;We’re basically going to use our previous &lt;code&gt;Android&lt;/code&gt; and &lt;code&gt;iOS&lt;/code&gt; code and use it in our &lt;code&gt;Flutter&lt;/code&gt; project. This should be very straightforward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Importing the Android library
&lt;/h3&gt;

&lt;p&gt;In order to use the &lt;a href="https://developer.android.com/studio/projects/android-library"&gt;Android Library&lt;/a&gt; that we built before we’re going to use &lt;a href="https://developer.android.com/studio"&gt;Android Studio&lt;/a&gt;. Let’s open the &lt;code&gt;flutter/android&lt;/code&gt; project.&lt;/p&gt;

&lt;p&gt;Then, in order to import the &lt;a href="https://developer.android.com/studio/projects/android-library"&gt;Android Library&lt;/a&gt;, select &lt;code&gt;File &amp;gt; New... &amp;gt; New Module&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F57j9Tyf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/20-import-android-library.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F57j9Tyf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/20-import-android-library.png" alt="Importing the Android Library" width="880" height="673"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select &lt;code&gt;import .JAR/.AAR Package&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--63oVxxJd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/21-import-android-library.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--63oVxxJd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/21-import-android-library.png" alt="Importing the Android Library" width="880" height="657"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And use the previously generated &lt;code&gt;.AAR Package&lt;/code&gt; path:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hzjMuNvm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/22-import-android-library.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hzjMuNvm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/22-import-android-library.png" alt="Importing the Android Library" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By doing this, we should see a new folder called &lt;code&gt;rusty-android-lib-release&lt;/code&gt; folder with our &lt;code&gt;.aar package&lt;/code&gt; inside along with some other files:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---kBp7kgP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/23-import-android-library.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---kBp7kgP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/23-import-android-library.png" alt="Importing the Android Library" width="504" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, open the &lt;code&gt;build.gradle&lt;/code&gt; file in the &lt;code&gt;flutter/android&lt;/code&gt; folder and add a new dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s2"&gt;"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"&lt;/span&gt;
    &lt;span class="c1"&gt;// this is the line to add including the directory holding our .aar package:&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="nf"&gt;fileTree&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;include:&lt;/span&gt; &lt;span class="s1"&gt;'*.aar'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;dir:&lt;/span&gt; &lt;span class="s1"&gt;'rusty-android-lib-release'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding the Android platform code
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;flutter/android/src/main/kotlin/com/robertohuertas/rusty_flutter_lib/RustyFlutterLibPlugin.kt&lt;/code&gt; in your favorite IDE and replace the code in it with this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.robertohuertas.rusty_flutter_lib&lt;/span&gt;

&lt;span class="c1"&gt;// importing the Android library&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.robertohuertas.rusty_android_lib.*&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.flutter.plugin.common.MethodCall&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.flutter.plugin.common.MethodChannel&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.flutter.plugin.common.MethodChannel.MethodCallHandler&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.flutter.plugin.common.MethodChannel.Result&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.flutter.plugin.common.PluginRegistry.Registrar&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RustyFlutterLibPlugin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MethodCallHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@JvmStatic&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;registerWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;registrar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Registrar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MethodChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;registrar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;messenger&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"rusty_flutter_lib"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setMethodCallHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RustyFlutterLibPlugin&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="c1"&gt;// dynamically loading the android library&lt;/span&gt;
      &lt;span class="nf"&gt;loadRustyLib&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onMethodCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MethodCall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"getPlatformVersion"&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Android ${android.os.Build.VERSION.RELEASE}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"getHello"&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;to&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argument&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No to parameter found"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// we're using the helloDirect function here&lt;/span&gt;
            &lt;span class="c1"&gt;// but you could also use the hello function, too.&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;res&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;helloDirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notImplemented&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Importing the iOS code
&lt;/h3&gt;

&lt;p&gt;Importing the iOS code is fairly easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# copy the header to the Classes folder&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; ../rust/rustylib.h ios/Classes
&lt;span class="c"&gt;# create a new libs folder&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;ios/libs
&lt;span class="c"&gt;# copy the universal library into the libs folder&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; ../rust/target/universal/release/librustylib.a ios/libs/

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open the &lt;code&gt;rusty_flutter_lib.podspec&lt;/code&gt; file and add this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;s.ios.vendored_library &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'libs/librustylib.a'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding the iOS plaform code
&lt;/h3&gt;

&lt;p&gt;Open the &lt;code&gt;flutter/ios/Classes/RustyFlutterLibPlugin.swift&lt;/code&gt; file and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Flutter&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;UIKit&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;SwiftRustyFlutterLibPlugin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;FlutterPlugin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;registrar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FlutterPluginRegistrar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FlutterMethodChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"rusty_flutter_lib"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;binaryMessenger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;registrar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;messenger&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SwiftRustyFlutterLibPlugin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;registrar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addMethodCallDelegate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;call&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FlutterMethodCall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="kt"&gt;FlutterResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"getPlatformVersion"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"iOS "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="kt"&gt;UIDevice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;systemVersion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Rob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;hello_release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UnsafeMutablePointer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;mutating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No method found"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connect the API and the platform code
&lt;/h3&gt;

&lt;p&gt;Open the &lt;code&gt;flutter/lib/rusty_flutter_lib.dart&lt;/code&gt; file and add a new &lt;code&gt;static&lt;/code&gt; method in the &lt;code&gt;RustyFlutterLib&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nl"&gt;to:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;greetings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_channel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invokeMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'hello'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'to'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;greetings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing the Flutter example app
&lt;/h3&gt;

&lt;p&gt;Let’s open the &lt;code&gt;flutter/example/lib/main.dart&lt;/code&gt; file and let’s consume our recently created &lt;code&gt;Flutter package&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:async'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/services.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:rusty_flutter_lib/rusty_flutter_lib.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApp&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;_MyAppState&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_MyAppState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_MyAppState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;_platformVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'Unknown'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;_greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;initPlatformState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Platform messages are asynchronous, so we initialize in an async method.&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;initPlatformState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;platformVersion&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Platform messages may fail, so we use a try/catch PlatformException.&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;platformVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;RustyFlutterLib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;platformVersion&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;RustyFlutterLib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;to:&lt;/span&gt; &lt;span class="s"&gt;'Rob'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kd"&gt;on&lt;/span&gt; &lt;span class="n"&gt;PlatformException&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;platformVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'Failed to get platform version.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'Failed to get hello'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// If the widget was removed from the tree while the asynchronous platform&lt;/span&gt;
    &lt;span class="c1"&gt;// message was in flight, we want to discard the reply rather than calling&lt;/span&gt;
    &lt;span class="c1"&gt;// setState to update our non-existent appearance.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;_platformVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;platformVersion&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;_greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;MaterialApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;home:&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Plugin example app'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
              &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;_greeting&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;fontSize:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="p"&gt;),&lt;/span&gt;
              &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Running on: &lt;/span&gt;&lt;span class="si"&gt;$_platformVersion&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, go to the &lt;code&gt;example/ios&lt;/code&gt; folder and execute this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pod &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, open &lt;code&gt;example/android/app/build.gradle&lt;/code&gt; and change the &lt;code&gt;minSdkVersion&lt;/code&gt; from 16 to 22, as our library was built with this setting, too.&lt;/p&gt;

&lt;p&gt;And finally, open the &lt;code&gt;example/pubspec.yaml&lt;/code&gt; file and add the line below to avoid &lt;a href="https://github.com/flutter/flutter/issues/34477"&gt;this issue&lt;/a&gt; when building the &lt;code&gt;iOS&lt;/code&gt; version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;version: 1.0.0+1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations for arriving here! 👏&lt;/p&gt;

&lt;p&gt;Let’s run the &lt;strong&gt;example app&lt;/strong&gt; and see if it’s working.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;Android&lt;/code&gt; you should see something similar to the screenshot below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lu0ZkDyX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/24-flutter-android-result.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lu0ZkDyX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/24-flutter-android-result.png" alt="Running Flutter Android" width="300" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similarly, in &lt;code&gt;iOS&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_sVUp1Q1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/25-flutter-ios-result.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_sVUp1Q1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://robertohuertas.com/assets/images/rust-for-android-ios-flutter/25-flutter-ios-result.png" alt="Running Flutter iOS" width="300" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for finishing this long reading! I hope you found it useful! 😊&lt;/p&gt;

&lt;h2&gt;
  
  
  Bibliography
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mozilla.github.io/firefox-browser-architecture/experiments/2017-09-06-rust-on-ios.html"&gt;Building and Deploying a Rust library on iOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mozilla.github.io/firefox-browser-architecture/experiments/2017-09-21-rust-on-android.html"&gt;Building and Deploying a Rust library on Android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/visly/rust-on-ios-39f799b3c1dd"&gt;Rust on iOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/visly/rust-on-android-19f34a2fb43"&gt;Rust on Android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bbqsrc/cargo-ndk"&gt;cargo-ndk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jni-rs/jni-rs"&gt;jni-rs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/training/articles/perf-jni"&gt;JNI tips&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/studio/projects/android-library"&gt;Create an Android library&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;--&lt;br&gt;
Originally published at &lt;a href="https://robertohuertas.com/2019/10/27/rust-for-android-ios-flutter/"&gt;robertohuertas.com&lt;/a&gt; on October 27, 2019.&lt;/p&gt;

</description>
      <category>android</category>
      <category>ios</category>
      <category>flutter</category>
      <category>rust</category>
    </item>
    <item>
      <title>Building an Android service that never stops running</title>
      <dc:creator>Roberto Huertas</dc:creator>
      <pubDate>Sun, 30 Jun 2019 02:59:05 +0000</pubDate>
      <link>https://dev.to/robertohuertasm/building-an-android-service-that-never-stops-running-1790</link>
      <guid>https://dev.to/robertohuertasm/building-an-android-service-that-never-stops-running-1790</guid>
      <description>&lt;p&gt;I've been struggling these days trying to find a way to run an endless service in &lt;a href="https://www.android.com/" rel="noopener noreferrer"&gt;Android&lt;/a&gt;. This is just a guide for all of you who pursue the same goal. Hope it helps! 😁&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Due to Android battery optimizations introduced in Android 8.0 (API level 26), background services have now some important &lt;a href="https://developer.android.com/about/versions/oreo/background.html#services" rel="noopener noreferrer"&gt;limitations&lt;/a&gt;. Essentially, they are killed once the app is in background for a while making them worthless for our purpose of running an always-running service.&lt;/p&gt;

&lt;p&gt;According to Android recommendations, we should be using &lt;a href="https://developer.android.com/reference/android/app/job/JobScheduler.html" rel="noopener noreferrer"&gt;JobScheduler&lt;/a&gt;, which seems to work pretty well and will handle &lt;a href="https://developer.android.com/training/scheduling/wakelock#cpu" rel="noopener noreferrer"&gt;wakelocks&lt;/a&gt; for us, keeping the phone awake while the jobs are running.&lt;/p&gt;

&lt;p&gt;Unfortunately, this won't work either. &lt;a href="https://developer.android.com/reference/android/app/job/JobScheduler.html" rel="noopener noreferrer"&gt;JobScheduler&lt;/a&gt; will run jobs at Android's discretion and, on top of that, once the phone enters in &lt;a href="https://developer.android.com/training/monitoring-device-state/doze-standby" rel="noopener noreferrer"&gt;Doze Mode&lt;/a&gt;, the frequency of these jobs being run will constantly decrease. And even worst, if you ever want to access the network -say you need to send data to your server- you won't be able to. Check out the &lt;a href="https://developer.android.com/training/monitoring-device-state/doze-standby#restrictions" rel="noopener noreferrer"&gt;list of restrictions&lt;/a&gt; Doze Mode imposes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/reference/android/app/job/JobScheduler.html" rel="noopener noreferrer"&gt;JobScheduler&lt;/a&gt; works well if you don't mind about not having access to the network and you don't care about not controlling the periodicity either. In our case, we want our service to run at a very specific frequency and never be stopped, so we'll need something else.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's all about Foreground Services
&lt;/h2&gt;

&lt;p&gt;If you've been looking over the internet for a solution to this problem it's very likely that you've eventually arrived to this &lt;a href="https://developer.android.com/guide/components/services" rel="noopener noreferrer"&gt;page from the Android's documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There, we are introduced to the different types of services that Android provides. Take a look at the &lt;code&gt;Foreground Service&lt;/code&gt; description:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A foreground service performs some operation that is noticeable to the user. For example, an audio app would use a foreground service to play an audio track. Foreground services must display a Notification. Foreground services continue running even when the user isn't interacting with the app.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It seems to be precisely what we're looking for... an it is, indeed! 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me the code
&lt;/h2&gt;

&lt;p&gt;Creating a &lt;code&gt;foreground service&lt;/code&gt; is really a straight-forward process so I will visit and explain all the steps needed to build a foreground service that never stops.&lt;/p&gt;

&lt;p&gt;As usual, I've created a &lt;a href="https://github.com/robertohuertasm/endless-service" rel="noopener noreferrer"&gt;repository with all the code&lt;/a&gt; in case you want to take a look at it and skip the rest of the post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding some dependencies
&lt;/h2&gt;

&lt;p&gt;I'm using &lt;a href="https://kotlinlang.org/" rel="noopener noreferrer"&gt;Kotlin&lt;/a&gt; for this example, so we will be leveraging &lt;a href="https://kotlinlang.org/docs/reference/coroutines-overview.html" rel="noopener noreferrer"&gt;coroutines&lt;/a&gt; and the &lt;a href="https://github.com/kittinunf/fuel" rel="noopener noreferrer"&gt;Fuel&lt;/a&gt; library for HTTP requests.&lt;/p&gt;

&lt;p&gt;In order to add these dependencies we must add them to our &lt;code&gt;build.gradle&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="nf"&gt;fileTree&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;dir:&lt;/span&gt; &lt;span class="s1"&gt;'libs'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;include:&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'*.jar'&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt;&lt;span class="s2"&gt;"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.android.support:appcompat-v7:28.0.0'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.android.support.constraint:constraint-layout:1.1.3'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.jaredrummler:android-device-names:1.1.8'&lt;/span&gt;

    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.github.kittinunf.fuel:fuel:2.1.0'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.github.kittinunf.fuel:fuel-android:2.1.0'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0-M1'&lt;/span&gt;

    &lt;span class="n"&gt;testImplementation&lt;/span&gt; &lt;span class="s1"&gt;'junit:junit:4.12'&lt;/span&gt;
    &lt;span class="n"&gt;androidTestImplementation&lt;/span&gt; &lt;span class="s1"&gt;'com.android.support.test:runner:1.0.2'&lt;/span&gt;
    &lt;span class="n"&gt;androidTestImplementation&lt;/span&gt; &lt;span class="s1"&gt;'com.android.support.test.espresso:espresso-core:3.0.2'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing our service
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Foreground Services&lt;/code&gt; need a notification to be shown so the user is aware that the app is still running. That makes sense if you think about it.&lt;/p&gt;

&lt;p&gt;Note that we will have to override some of the &lt;a href="https://developer.android.com/guide/components/services#Basics" rel="noopener noreferrer"&gt;Service callback methods&lt;/a&gt; that handle key aspects of the service lifecycle.&lt;/p&gt;

&lt;p&gt;It's also very important that we use a &lt;a href="https://developer.android.com/training/scheduling/wakelock#cpu" rel="noopener noreferrer"&gt;partial wakelock&lt;/a&gt; so our service never gets affected by &lt;a href="https://developer.android.com/training/monitoring-device-state/doze-standby" rel="noopener noreferrer"&gt;Doze Mode&lt;/a&gt;. Bear in mind that this will have an impact in the battery life of our phone so we must evaluate whether our use case can be handled by any of the other alternatives Android offers in order to run processes in the background.&lt;/p&gt;

&lt;p&gt;There are some utility function calls (&lt;code&gt;log&lt;/code&gt;, &lt;code&gt;setServiceState&lt;/code&gt;) and some custom enums (&lt;code&gt;ServiceState.STARTED&lt;/code&gt;) in the code, but don't worry too much. If you want to see where they come from, just take a look at the &lt;a href="https://github.com/robertohuertasm/endless-service" rel="noopener noreferrer"&gt;example repository&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EndlessService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;wakeLock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PowerManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WakeLock&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;isServiceStarted&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onBind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;IBinder&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Some component want to bind with the service"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// We don't provide binding, so return null&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onStartCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;startId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"onStartCommand executed with startId: $startId"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;
            &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"using an intent with action $action"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;START&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;startService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="nc"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;stopService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This should never happen. No action in the received intent"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"with a null intent. It has been probably restarted by the system."&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// by returning this we make sure the service is restarted if the system kills the service&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;START_STICKY&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The service has been created"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;notification&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createNotification&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;startForeground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The service has been destroyed"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Service destroyed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LENGTH_SHORT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;startService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isServiceStarted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting the foreground service task"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Service starting its task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LENGTH_SHORT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;isServiceStarted&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
        &lt;span class="nf"&gt;setServiceState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ServiceState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;STARTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// we need this lock so our service gets not affected by Doze Mode&lt;/span&gt;
        &lt;span class="n"&gt;wakeLock&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getSystemService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;POWER_SERVICE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;PowerManager&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;newWakeLock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PowerManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PARTIAL_WAKE_LOCK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"EndlessService::lock"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// we're starting a loop in a coroutine&lt;/span&gt;
        &lt;span class="nc"&gt;GlobalScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dispatchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isServiceStarted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dispatchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;pingFakeServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"End of the loop for the service"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;stopService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Stopping the foreground service"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Service stopping"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Toast&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LENGTH_SHORT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;wakeLock&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isHeld&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nf"&gt;stopForeground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;stopSelf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Service stopped without being started: ${e.message}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;isServiceStarted&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
        &lt;span class="nf"&gt;setServiceState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ServiceState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;STOPPED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;pingFakeServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;df&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SimpleDateFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"yyyy-MM-dd'T'HH:mm:ss.mmmZ"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;gmtTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;deviceId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Secure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contentResolver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Secure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ANDROID_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="s"&gt;"""
                {
                    "deviceId": "$deviceId",
                    "createdAt": "$gmtTime"
                }
            """&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Fuel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://jsonplaceholder.typicode.com/posts"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jsonBody&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;response&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="py"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[response bytes] ${String(bytes)}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[response error] ${error?.message}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error making the request: ${e.message}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createNotification&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;notificationChannelId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ENDLESS SERVICE CHANNEL"&lt;/span&gt;

        &lt;span class="c1"&gt;// depending on the Android API that we're dealing with we will have&lt;/span&gt;
        &lt;span class="c1"&gt;// to use a specific method to create the notification&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SDK_INT&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION_CODES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;O&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;notificationManager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getSystemService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NOTIFICATION_SERVICE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;NotificationManager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NotificationChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;notificationChannelId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"Endless Service notifications channel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;NotificationManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IMPORTANCE_HIGH&lt;/span&gt;
            &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Endless Service channel"&lt;/span&gt;
                &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableLights&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lightColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RED&lt;/span&gt;
                &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableVibration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vibrationPattern&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;longArrayOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;it&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;notificationManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNotificationChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;pendingIntent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PendingIntent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;notificationIntent&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="nc"&gt;PendingIntent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;notificationIntent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SDK_INT&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION_CODES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;O&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;notificationChannelId&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContentTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Endless Service"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContentText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This is your favorite endless service working"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContentIntent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pendingIntent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setSmallIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mipmap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ic_launcher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTicker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ticker text"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setPriority&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PRIORITY_HIGH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// for under android 26 compatibility&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Time to deal with the Android Manifest
&lt;/h2&gt;

&lt;p&gt;We will need some extra permissions for &lt;code&gt;FOREGROUND_SERVICE&lt;/code&gt;, &lt;code&gt;INTERNET&lt;/code&gt; and &lt;code&gt;WAKE_LOCK&lt;/code&gt;. Be sure you don't forget to include them because it won't work otherwise.&lt;/p&gt;

&lt;p&gt;Once we put them in place we will need to declare our service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;manifest&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt; 
          &lt;span class="na"&gt;package=&lt;/span&gt;&lt;span class="s"&gt;"com.robertohuertas.endless"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;uses-permission&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.permission.FOREGROUND_SERVICE"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/uses-permission&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;uses-permission&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.permission.INTERNET"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/uses-permission&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;uses-permission&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.permission.WAKE_LOCK"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;application&lt;/span&gt;
            &lt;span class="na"&gt;android:allowBackup=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
            &lt;span class="na"&gt;android:icon=&lt;/span&gt;&lt;span class="s"&gt;"@mipmap/ic_launcher"&lt;/span&gt;
            &lt;span class="na"&gt;android:label=&lt;/span&gt;&lt;span class="s"&gt;"@string/app_name"&lt;/span&gt;
            &lt;span class="na"&gt;android:roundIcon=&lt;/span&gt;&lt;span class="s"&gt;"@mipmap/ic_launcher_round"&lt;/span&gt;
            &lt;span class="na"&gt;android:supportsRtl=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
            &lt;span class="na"&gt;android:theme=&lt;/span&gt;&lt;span class="s"&gt;"@style/AppTheme"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;service&lt;/span&gt;
                &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".EndlessService"&lt;/span&gt;
                &lt;span class="na"&gt;android:enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
                &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/service&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".MainActivity"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.MAIN"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.LAUNCHER"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/activity&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Can you tell me how I start the service?
&lt;/h2&gt;

&lt;p&gt;Yes, you're right. You see, depending on the Android version we must start the service with a particular method.&lt;/p&gt;

&lt;p&gt;If the Android version is below API 26 we must use &lt;a href="https://developer.android.com/reference/android/content/Context.html#startService(android.content.Intent)" rel="noopener noreferrer"&gt;startService&lt;/a&gt;. In any other case, &lt;a href="https://developer.android.com/reference/android/content/Context.html#startForegroundService(android.content.Intent)" rel="noopener noreferrer"&gt;startForegroundService&lt;/a&gt; is what we must use instead.&lt;/p&gt;

&lt;p&gt;Here you can see our &lt;code&gt;MainActivity&lt;/code&gt;, just a screen with two buttons to &lt;em&gt;start&lt;/em&gt; and &lt;em&gt;stop&lt;/em&gt; the service. That's all you need to start our &lt;em&gt;endless service&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Remember that you can check out the complete code in this &lt;a href="https://github.com/robertohuertasm/endless-service" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setContentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activity_main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Endless Service"&lt;/span&gt;

        &lt;span class="n"&gt;findViewById&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;btnStartService&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"START THE FOREGROUND SERVICE ON DEMAND"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;actionOnService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;START&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;findViewById&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;btnStopService&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"STOP THE FOREGROUND SERVICE ON DEMAND"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;actionOnService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;actionOnService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getServiceState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;ServiceState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;STOPPED&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;EndlessService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;also&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SDK_INT&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION_CODES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;O&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting the service in &amp;gt;=26 Mode"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;startForegroundService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting the service in &amp;lt; 26 Mode"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;startService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bonus: Start the service on Android boot
&lt;/h2&gt;

&lt;p&gt;Ok, we now have our &lt;em&gt;endless service&lt;/em&gt; making network requests every minute as we wanted but then the user restarts the phone... and our service doesn't start again... 😞&lt;/p&gt;

&lt;p&gt;Don't worry, we can find a solution for this, too. We will create a &lt;a href="https://developer.android.com/reference/android/content/BroadcastReceiver" rel="noopener noreferrer"&gt;BroadCastReceiver&lt;/a&gt; called &lt;code&gt;StartReceiver&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StartReceiver&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BroadcastReceiver&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ACTION_BOOT_COMPLETED&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;getServiceState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;ServiceState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;STARTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;EndlessService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;also&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;START&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SDK_INT&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nc"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;VERSION_CODES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;O&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting the service in &amp;gt;=26 Mode from a BroadcastReceiver"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startForegroundService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting the service in &amp;lt; 26 Mode from a BroadcastReceiver"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we'll modify again our &lt;code&gt;Android Manifest&lt;/code&gt; and add a new permission (&lt;code&gt;RECEIVE_BOOT_COMPLETED&lt;/code&gt;) and our new &lt;a href="https://developer.android.com/reference/android/content/BroadcastReceiver" rel="noopener noreferrer"&gt;BroadCastReceiver&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;manifest&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
          &lt;span class="na"&gt;package=&lt;/span&gt;&lt;span class="s"&gt;"com.robertohuertas.endless"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;uses-permission&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.permission.FOREGROUND_SERVICE"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/uses-permission&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;uses-permission&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.permission.INTERNET"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/uses-permission&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;uses-permission&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.permission.WAKE_LOCK"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;uses-permission&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.permission.RECEIVE_BOOT_COMPLETED"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;application&lt;/span&gt;
            &lt;span class="na"&gt;android:allowBackup=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
            &lt;span class="na"&gt;android:icon=&lt;/span&gt;&lt;span class="s"&gt;"@mipmap/ic_launcher"&lt;/span&gt;
            &lt;span class="na"&gt;android:label=&lt;/span&gt;&lt;span class="s"&gt;"@string/app_name"&lt;/span&gt;
            &lt;span class="na"&gt;android:roundIcon=&lt;/span&gt;&lt;span class="s"&gt;"@mipmap/ic_launcher_round"&lt;/span&gt;
            &lt;span class="na"&gt;android:supportsRtl=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
            &lt;span class="na"&gt;android:theme=&lt;/span&gt;&lt;span class="s"&gt;"@style/AppTheme"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;service&lt;/span&gt;
                &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".EndlessService"&lt;/span&gt;
                &lt;span class="na"&gt;android:enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
                &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/service&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".MainActivity"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.MAIN"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.LAUNCHER"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/activity&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;receiver&lt;/span&gt; &lt;span class="na"&gt;android:enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".StartReceiver"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.BOOT_COMPLETED"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/receiver&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take into account that the service won't be rebooted unless it was already running. That's how we programmed it, it's not that it has to be like that.&lt;/p&gt;

&lt;p&gt;Anyway, if you want to test this, just spin up one emulator with &lt;code&gt;Google Services&lt;/code&gt; in it and be sure to be running &lt;a href="https://developer.android.com/studio/command-line/adb" rel="noopener noreferrer"&gt;adb&lt;/a&gt; in &lt;em&gt;root&lt;/em&gt; mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adb root
&lt;span class="c"&gt;# If you get an error then you're not running the proper emulator.&lt;/span&gt;
&lt;span class="c"&gt;# Be sure to stop the service&lt;/span&gt;
&lt;span class="c"&gt;# and force a system restart:&lt;/span&gt;
adb shell stop
adb shell start
&lt;span class="c"&gt;# wait for the service to be restarted!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bonus 2: Restart the service when the task is removed
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/mmaterowski" rel="noopener noreferrer"&gt;Michal Materowski&lt;/a&gt; wrote to me with this case and its solution, so kudos for him!&lt;/p&gt;

&lt;p&gt;Theoretically, according to &lt;code&gt;Android&lt;/code&gt; documentation, returning &lt;strong&gt;RETURN_STICKY&lt;/strong&gt; from the service's &lt;code&gt;onStartCommand&lt;/code&gt; method should be enough for Android to keep the foreground service running.&lt;/p&gt;

&lt;p&gt;Michal was testing all this with a &lt;em&gt;Xiaomi Note 5&lt;/em&gt; with &lt;strong&gt;Android Pie&lt;/strong&gt; and every time he swiped an app from recent apps, it worked flawlessly. Unfortunately, whenever he pressed the &lt;code&gt;Clear all recent apps&lt;/code&gt; button (&lt;a href="https://en.miui.com/" rel="noopener noreferrer"&gt;MIUI&lt;/a&gt; specific), the service was stopped and the notification was gone. The &lt;code&gt;Clear all recent apps&lt;/code&gt; button was probably doing some sort of battery life optimization by killing all processes and their associated services.&lt;/p&gt;

&lt;p&gt;He found out that &lt;code&gt;Android&lt;/code&gt; documentation states that &lt;code&gt;onTaskRemoved&lt;/code&gt; &lt;strong&gt;"is called if the service is currently running and the user has removed a task that comes from the service's application."&lt;/strong&gt;, so the plan was to leverage this to restart the service. Bear in mind, though, that &lt;code&gt;onTaskRemoved&lt;/code&gt; is not called if the application is killed in any other way (e.g. stopped from the phone settings).&lt;/p&gt;

&lt;p&gt;Add these lines to your &lt;strong&gt;service&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onTaskRemoved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rootIntent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;restartServiceIntent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;EndlessService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;also&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setPackage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packageName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;restartServicePendingIntent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PendingIntent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PendingIntent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;restartServiceIntent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PendingIntent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FLAG_ONE_SHOT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSystemService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ALARM_SERVICE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;alarmService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AlarmManager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSystemService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ALARM_SERVICE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;AlarmManager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;alarmService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AlarmManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ELAPSED_REALTIME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SystemClock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;elapsedRealtime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;restartServicePendingIntent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check out the original &lt;a href="https://github.com/robertohuertasm/endless-service/pull/4/files" rel="noopener noreferrer"&gt;Michal Materowski's PR&lt;/a&gt; with the whole code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt;: Michal had to manually set &lt;code&gt;Autostart&lt;/code&gt; permission, otherwise the &lt;strong&gt;service was not started on boot&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbyo4tirtix6mf8sbkwgv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbyo4tirtix6mf8sbkwgv.png" alt="Autostar"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to Michal, some people mentioned that setting &lt;code&gt;stopWithTask&lt;/code&gt; flag might help, but it didn't make a difference for him:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;service&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".EndlessService"&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="na"&gt;android:stopWithTask=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lots of kudos to &lt;a href="https://github.com/mmaterowski" rel="noopener noreferrer"&gt;Michal Materowski&lt;/a&gt; for his help on this case.&lt;/p&gt;

&lt;p&gt;Enjoy! ❤️&lt;/p&gt;

&lt;p&gt;--&lt;br&gt;
Originally published at &lt;a href="https://robertohuertas.com/2019/06/29/android_foreground_services" rel="noopener noreferrer"&gt;robertohuertas.com&lt;/a&gt; on June 29, 2019.&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>services</category>
    </item>
  </channel>
</rss>
