<?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>Forem: Dan</title>
    <description>The latest articles on Forem by Dan (@dotxlem).</description>
    <link>https://forem.com/dotxlem</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%2F338425%2F75a12359-d707-4883-90cb-c2a523ade6d7.jpeg</url>
      <title>Forem: Dan</title>
      <link>https://forem.com/dotxlem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/dotxlem"/>
    <language>en</language>
    <item>
      <title>A full-stack serverless application with AssemblyLift and Next.js</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Tue, 11 Oct 2022 19:21:45 +0000</pubDate>
      <link>https://forem.com/akkoro/a-full-stack-serverless-application-with-assemblylift-and-nextjs-197g</link>
      <guid>https://forem.com/akkoro/a-full-stack-serverless-application-with-assemblylift-and-nextjs-197g</guid>
      <description>&lt;p&gt;Today we published a new demo illustrating several features of the latest AssemblyLift release!&lt;/p&gt;

&lt;p&gt;This demo deploys a simple "hello world" Next.js application to an AWS environment. Visits to the app are counted by invoking a logging function from the server function.&lt;/p&gt;

&lt;p&gt;The demo repository is &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws"&gt;on GitHub&lt;/a&gt;. You can see it live &lt;a href="https://nextjs.demos.asml.akkoro.io/"&gt;here&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Topics illustrated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serving static web assets from an AssemblyLift function&lt;/li&gt;
&lt;li&gt;Serving a private API from an AssemblyLift function&lt;/li&gt;
&lt;li&gt;Authoring AssemblyLift functions in both Rust and Ruby&lt;/li&gt;
&lt;li&gt;Sandboxed WebAssembly network access using an IO Module

&lt;ul&gt;
&lt;li&gt;Making HTTP calls to another function or to a 3rd party service&lt;/li&gt;
&lt;li&gt;Making calls to an AWS service (Secrets Manager)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Deploying a service to a custom domain name&lt;/li&gt;
&lt;li&gt;Automated TLS certificate configuration &amp;amp; provisioning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/akkoro/assemblylift"&gt;AssemblyLift&lt;/a&gt; is an open platform for cloud-native application development. AssemblyLift provides a portable, function-oriented framework and WebAssembly-based runtime which can be deployed to AWS Lambda or Kubernetes. The AssemblyLift CLI generates &lt;a href="https://terraform.io"&gt;HashiCorp Terraform&lt;/a&gt; infrastructure code from simple TOML definitions, and takes care of compiling and packaging functions and services for deployment. To make a clichéd comparison, think of it as &lt;em&gt;Infrastructure on Rails&lt;/em&gt; 😛&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org"&gt;Next.js&lt;/a&gt; by &lt;a href="https://vercel.com"&gt;Vercel&lt;/a&gt; is a popular JavaScript/TypeScript frontend framework based on &lt;a href="http://reactjs.org"&gt;React&lt;/a&gt;. Next allows us to export our React application as static HTML which we can serve with AssemblyLift.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deep dive
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Services &amp;amp; Functions
&lt;/h3&gt;

&lt;p&gt;AssemblyLift applications are composed of &lt;strong&gt;services&lt;/strong&gt;, each of which are made up of &lt;strong&gt;functions&lt;/strong&gt;. Services are stored in the &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws/blob/main/services/"&gt;&lt;code&gt;services&lt;/code&gt;&lt;/a&gt; directory. Each service is made up of a &lt;strong&gt;service manifest&lt;/strong&gt; named &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws/blob/main/services/www/service.toml"&gt;&lt;code&gt;service.toml&lt;/code&gt;&lt;/a&gt; alongside one or more functions. This demo application deploys one service named &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws/blob/main/services/www/"&gt;&lt;code&gt;www&lt;/code&gt;&lt;/a&gt; which contains two functions, &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws/blob/main/services/www/server/"&gt;&lt;code&gt;server&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws/blob/main/services/www/counter/"&gt;&lt;code&gt;counter&lt;/code&gt;&lt;/a&gt;, each of which do exactly what it says on the tin :).  &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;server&lt;/code&gt; function is our HTTP server which serves web content. The &lt;code&gt;counter&lt;/code&gt; function is a private function (protected by IAM) which is called from &lt;code&gt;server&lt;/code&gt;; this function updates a simple count of visits by IP in a &lt;a href="https://xata.io"&gt;Xata&lt;/a&gt; database.  &lt;/p&gt;

&lt;p&gt;For performance, the &lt;code&gt;server&lt;/code&gt; function is written in &lt;a href="https://rust-lang.org"&gt;Rust&lt;/a&gt;. Rust compiles natively to WebAssembly, and so has faster cold-start time as well as faster execution speed compared to Ruby -- ideal for our server! We leverage a Rust crate called &lt;code&gt;rust_embed&lt;/code&gt; which allows us to embed assets inside a compiled binary. We use this to embed the assets generated by our Next.js build inside the WebAssembly module which AssemblyLift will deploy as our Lambda function!  &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;counter&lt;/code&gt; function is written in &lt;a href="https://ruby-lang.org"&gt;Ruby&lt;/a&gt;. Since Ruby is an interpreted language, AssemblyLift deploys a customized Ruby 3.1 interpreter compiled to WebAssembly, which executes the function handler. Since the interpreter is somewhat large, the cold-start time of a Ruby function tends to be larger than that of a Rust function. Our counter is being run in the backround, so we're fine with it being a little bit laggy at times 😉.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP API
&lt;/h3&gt;

&lt;p&gt;Regardless of infrastructure provider, AssemblyLift services are placed behind some kind of API Gateway service. When deployed to AWS, each AssemblyLift service is placed behind an an&lt;a href="https://aws.amazon.com/api-gateway/"&gt; Amazon API Gateway&lt;/a&gt; endpoint. Each function may define an HTTP route which will invoke it. The &lt;code&gt;server&lt;/code&gt; function is invoked by &lt;code&gt;GET /{path+}&lt;/code&gt;; the &lt;code&gt;{path+}&lt;/code&gt; token is a path parameter where the &lt;code&gt;+&lt;/code&gt; indicates that it is a greedy parameter. This means that everything after the first &lt;code&gt;/&lt;/code&gt; is mapped to a parameter called &lt;code&gt;path&lt;/code&gt;. This allows us to map the requested path to an embedded path in our function binary. The &lt;code&gt;counter&lt;/code&gt; function is invoked by &lt;code&gt;POST /api/counter/{ip}&lt;/code&gt;, where &lt;code&gt;{ip}&lt;/code&gt; is a regular path parameter named &lt;code&gt;ip&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A function's HTTP route is defined in &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws/blob/main/services/www/service.toml#L27"&gt;&lt;code&gt;service.toml&lt;/code&gt;&lt;/a&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="nn"&gt;[[api.functions]]&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;"counter"&lt;/span&gt;
&lt;span class="py"&gt;language&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ruby"&lt;/span&gt;
&lt;span class="py"&gt;size_mb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3584&lt;/span&gt;
&lt;span class="nn"&gt;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;verb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/api/counter/{ip}"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;# This defines the HTTP route for counter&lt;/span&gt;
&lt;span class="py"&gt;authorizer_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"iam"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;counter&lt;/code&gt; function is protected by API Gateway's built-in IAM authorizer. AssemblyLift doesn't yet support defining access permissions between functions in TOML, so for this demo a small amount of Terraform is included to attach IAM policies to each function. AssemblyLift instantiates the &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws/blob/main/user_tf/"&gt;&lt;code&gt;user_tf&lt;/code&gt;&lt;/a&gt; directory (if found) as a module alongside its generated module(s).&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain name mapping
&lt;/h3&gt;

&lt;p&gt;AssemblyLift projects can specify one or more domain names to which services can be mapped using a DNS provider. At the moment, the only available DNS provider is &lt;a href="https://aws.amazon.com/route53/"&gt;Amazon Route53&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Domain names are defined as an array in &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws/blob/main/assemblylift.toml#L7"&gt;&lt;code&gt;assemblylift.toml&lt;/code&gt;&lt;/a&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="nn"&gt;[[domains]]&lt;/span&gt;
&lt;span class="py"&gt;dns_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"demos.asml.akkoro.io"&lt;/span&gt;
&lt;span class="nn"&gt;[domains.provider]&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;"route53"&lt;/span&gt;
&lt;span class="nn"&gt;[domains.provider.options]&lt;/span&gt;
&lt;span class="py"&gt;aws_region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"us-east-1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Route53, the &lt;code&gt;dns_name&lt;/code&gt; must correspond to an &lt;em&gt;existing&lt;/em&gt; Route53 Hosted Zone.&lt;/p&gt;

&lt;p&gt;By default, services are mapped to subdomains according to the pattern &lt;code&gt;service-name.project-name.domain-name.tld&lt;/code&gt;. For example, the &lt;code&gt;www&lt;/code&gt; service would be &lt;code&gt;www.nextjs.demos.asml.akkoro.io&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A service can indicate that it is the &lt;em&gt;root&lt;/em&gt; service, omitting the service subdomain from the path. For example in &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws/blob/main/services/www/service.toml#L12"&gt;&lt;code&gt;service.toml&lt;/code&gt;&lt;/a&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="nn"&gt;[api]&lt;/span&gt;
&lt;span class="py"&gt;domain_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"demos.asml.akkoro.io"&lt;/span&gt;
&lt;span class="py"&gt;is_root&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;yields the domain &lt;code&gt;nextjs.demos.asml.akkoro.io&lt;/code&gt; for the &lt;code&gt;www&lt;/code&gt; service.&lt;/p&gt;

&lt;p&gt;When deployed to AWS, AssemblyLift will provision TLS certificates for your services using &lt;a href="https://aws.amazon.com/certificate-manager/"&gt;Amazon Certificate Manager (ACM)&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  IO Modules
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;counter&lt;/code&gt; function uses a Xata database for storage, which provides a JSON-oriented HTTP API which we can access using the HTTP &lt;em&gt;IO Module&lt;/em&gt;. WebAssembly's sandboxing means that by default, functions cannot communicate over a socket or access the filesystem. AssemblyLift provides an RPC interface allowing communication with services called &lt;a href="https://docs.assemblylift.akkoro.io/learn-assemblylift/io-modules"&gt;IO Modules&lt;/a&gt; or &lt;em&gt;IOmods&lt;/em&gt;. IOmods are deployed per-service, i.e. every function in a service share the same set of IOmods. An IOmod is essentially a library of remote functions, each at an assigned &lt;em&gt;coordinate&lt;/em&gt; &lt;code&gt;organization.namespace.module.call&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, importing the standard HTTP module:&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;[[iomod.dependencies]]&lt;/span&gt;
&lt;span class="py"&gt;coordinates&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"akkoro.std.http"&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.0"&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"registry"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;exports a single function named &lt;code&gt;request&lt;/code&gt; at &lt;code&gt;akkoro.std.http.request&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next Frontend
&lt;/h3&gt;

&lt;p&gt;There is no specific convention for adding a frontend to AssemblyLift; in this project we have created the &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws/blob/main/frontend/"&gt;&lt;code&gt;frontend&lt;/code&gt;&lt;/a&gt; directory to mimic the &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws/blob/main/services/"&gt;&lt;code&gt;services&lt;/code&gt;&lt;/a&gt; directory. Here we have used &lt;code&gt;create-next-app&lt;/code&gt; to create a Next.js project called &lt;a href="https://github.com/akkoro/assemblylift-demo-nextjs-aws/blob/main/frontend/www/"&gt;&lt;code&gt;www&lt;/code&gt;&lt;/a&gt; after our service of the same name.&lt;/p&gt;

&lt;p&gt;The frontend must be exported to a static site, using &lt;code&gt;next build &amp;amp;&amp;amp; next export&lt;/code&gt;. The contents of the generated &lt;code&gt;out&lt;/code&gt; directory are copied into the server binary when it is compiled (on &lt;code&gt;asml cast&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy your own!
&lt;/h2&gt;

&lt;p&gt;You can deploy this project yourself! You will need to update it to use your own domain of course ;)&lt;/p&gt;

&lt;h3&gt;
  
  
  You will need...
&lt;/h3&gt;

&lt;p&gt;Required: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AWS account&lt;/li&gt;
&lt;li&gt;Rust &amp;amp; Cargo CLI&lt;/li&gt;
&lt;li&gt;Node &amp;amp; NPM CLI&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/akkoro/assemblylift/releases"&gt;Latest AssemblyLift CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nice to have: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A domain name in Route53&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An AssemblyLift project is built with the &lt;code&gt;asml cast&lt;/code&gt; command; &lt;em&gt;casting&lt;/em&gt; is the process of compiling WASM, transpiling TOML, building images, etc which comprises the build of an application. Artifacts and plans are serialized to the &lt;code&gt;net/&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;To deploy a project you use the command &lt;code&gt;asml bind&lt;/code&gt;, which will deploy artifacts and apply the underlying Terraform plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reach out!
&lt;/h2&gt;

&lt;p&gt;Get in touch with us &lt;a href="https://discord.gg/pVSCqYgra3"&gt;on Discord&lt;/a&gt; and follow &lt;a href="https://twitter.com/akkorocorp/"&gt;@akkorocorp&lt;/a&gt; on Twitter.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>cloud</category>
      <category>aws</category>
      <category>serverless</category>
    </item>
    <item>
      <title>AssemblyLift alpha latest: easy API Gateway for Kubernetes functions, Ruby language support 💎</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Wed, 22 Jun 2022 16:41:59 +0000</pubDate>
      <link>https://forem.com/akkoro/assemblylift-alpha-latest-easy-api-gateway-for-kubernetes-functions-ruby-language-support-1045</link>
      <guid>https://forem.com/akkoro/assemblylift-alpha-latest-easy-api-gateway-for-kubernetes-functions-ruby-language-support-1045</guid>
      <description>&lt;p&gt;Hello again y'all! 👋🏻&lt;/p&gt;

&lt;p&gt;Since our &lt;a href="https://dev.to/akkoro/assemblylift-v040-alpha-released-with-kubernetes-support-wasi-webassembly-on-k8s-5bj8"&gt;last post introducing the AssemblyLift v0.4-alpha series&lt;/a&gt;, we've had two new alpha &lt;a href="https://github.com/akkoro/assemblylift/releases"&gt;releases&lt;/a&gt; which introduced some major additions &amp;amp; improvements!&lt;/p&gt;

&lt;p&gt;In this post we'll talk about each change and what it means, and then we'll walk through a short example demonstrating the  new features. 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  Revised TOML manifest spec
&lt;/h2&gt;

&lt;p&gt;Manifests (&lt;code&gt;assemblylift.toml&lt;/code&gt; and &lt;code&gt;service.toml&lt;/code&gt;) now use arrays to describe most entries which used to be written using tables.&lt;/p&gt;

&lt;p&gt;For example, the &lt;code&gt;[services]&lt;/code&gt; table in &lt;code&gt;assemblylift.toml&lt;/code&gt; is now the &lt;code&gt;[[services]]&lt;/code&gt; array.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why?
&lt;/h3&gt;

&lt;p&gt;The primary data structures in &lt;a href="https://toml.io/en/"&gt;TOML&lt;/a&gt; are arrays and tables.&lt;/p&gt;

&lt;p&gt;Previous releases leaned heavily on &lt;em&gt;tables&lt;/em&gt;. A typical &lt;code&gt;assemblylift.toml&lt;/code&gt; for example might be:&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;[project]&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;"my-project"&lt;/span&gt;

&lt;span class="nn"&gt;[services]&lt;/span&gt;
&lt;span class="nn"&gt;my_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&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;"my-service"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;another&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&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;"another-service"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both &lt;code&gt;[project]&lt;/code&gt; and &lt;code&gt;[services]&lt;/code&gt; are tables. The &lt;code&gt;my_service&lt;/code&gt; key also points to a table. Expressing services this way (as well as functions, authorizers, etc.) is a bit verbose considering that these things are also named.&lt;/p&gt;

&lt;p&gt;By comparison, using arrays to add multiple services to &lt;code&gt;assemblylift.toml&lt;/code&gt; for example looks like:&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;[project]&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;"project"&lt;/span&gt;

&lt;span class="nn"&gt;[[services]]&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;"service1"&lt;/span&gt;

&lt;span class="nn"&gt;[[services]]&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;"service2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which avoids redundant information (the table key) and becomes easier to read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ruby language support
&lt;/h2&gt;

&lt;p&gt;AssemblyLift is now bilingual! Functions can now be written in Ruby in addition to Rust.&lt;/p&gt;

&lt;p&gt;To declare a function a Ruby function, set the &lt;code&gt;language&lt;/code&gt; parameter.&lt;/p&gt;

&lt;p&gt;For example:&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;[[api.functions]]&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;"my-ruby-func"&lt;/span&gt;
&lt;span class="py"&gt;language&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ruby"&lt;/span&gt;
&lt;span class="nn"&gt;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;verb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/my-service/my-ruby-func"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Ruby function requires &lt;code&gt;handler.rb&lt;/code&gt; to be the entrypoint. AssemblyLift ships a custom build of the Ruby runtime which includes a module for interop with the AssemblyLift platform.&lt;/p&gt;

&lt;p&gt;We'll explore this in more detail in the demo section below!&lt;/p&gt;

&lt;h3&gt;
  
  
  Why?
&lt;/h3&gt;

&lt;p&gt;We ❤️ Ruby! Most commonly associated with the Rails framework, Ruby is a powerful &amp;amp; mature scripting language suitable for many purposes. &lt;/p&gt;

&lt;p&gt;Ruby recently gained support for WebAssembly, and we almost immediately went about integrating it into AssemblyLift! 💨&lt;/p&gt;

&lt;p&gt;While you can't (yet?) lift your existing Rails app to a Function, the Ruby language is familiar to many devs. Ruby could especially be preferable in cases where performance is less of a concern, such as automation tasks for example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support for Gloo Edge API Gateway
&lt;/h2&gt;

&lt;p&gt;Another feature addition we're very excited about is HTTP API support for the new Kubernetes provider. The previous alpha release could deploy functions to a K8s cluster, but there was no practical way yet to invoke them!&lt;/p&gt;

&lt;p&gt;This release will automatically install &lt;a href="https://docs.solo.io/gloo-edge/latest/introduction/"&gt;Gloo Edge&lt;/a&gt; on the target cluster. AssemblyLift will deploy a Gateway, and set up routing for any functions running in a K8s service which define an HTTP API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why?
&lt;/h3&gt;

&lt;p&gt;An API Gateway is central to the AssemblyLift architecture. AWS Lambda has a natural pairing with Amazon API Gateway, but Kubernetes of course is open-ended.&lt;/p&gt;

&lt;p&gt;For this first iteration, Gloo Edge was chosen as it is open-source, easy to automate, and very full-featured. Being itself based on &lt;a href="https://www.envoyproxy.io/"&gt;Envoy Proxy&lt;/a&gt; we can eventually explore its support for WASM traffic filters in Gloo Edge Enterprise.&lt;/p&gt;

&lt;p&gt;A potential drawback is that Gloo may be heavier than needed for your application (our test deployment required 2vCPU per node to run Gloo + an AssemblyLift service). We'll soon look at support for other (lighter) reverse proxies. Eventually we want to support multiple API Gateway providers per backend, and also allow for cross deployment (Amazon APIGW in front of K8s, Gloo in front of Lambda).&lt;/p&gt;

&lt;h2&gt;
  
  
  A short demonstration
&lt;/h2&gt;

&lt;p&gt;Let's look at an example! If you want to try AssemblyLift yourself and follow along, you will need the prerequisites below. Otherwise if you just want the gist of things, you can skip that and keep reading 🙂&lt;/p&gt;

&lt;p&gt;In this example we'll deploy a basic Ruby function to a Kubernetes cluster that writes to the function log, and &lt;code&gt;curl&lt;/code&gt; it via an API Gateway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prereqs
&lt;/h3&gt;

&lt;p&gt;You will need a running Docker daemon on your development machine. You will also need a configured k8s config at the default &lt;code&gt;~/.kube/config&lt;/code&gt;. So far AssemblyLift has been tested against Docker Desktop Kubernetes as well as Digital Ocean Kubernetes. It isn't strictly necessary, but is recommended for testing and debugging, to have &lt;code&gt;kubectl&lt;/code&gt; installed.&lt;/p&gt;

&lt;p&gt;You will also need a Docker image registry. Right now AssemblyLift supports Docker Hub and AWS ECR, however ECR is recommended as your registries can be provisioned/destroyed automatically. Currently, AssemblyLift will attempt to use AWS credentials from your default profile in &lt;code&gt;~/.aws/credentials&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can grab AssemblyLift for macOS with&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;-O&lt;/span&gt; public.assemblylift.akkoro.io/cli/0.4.0-alpha.3/x86_64-apple-darwin/asml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or for Linux with&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;-O&lt;/span&gt; public.assemblylift.akkoro.io/cli/0.4.0-alpha.3/x86_64-linux-gnu/asml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make the binary executable by running &lt;code&gt;chmod +x asml&lt;/code&gt; and ensure it is available on your system &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If your Linux system's glibc isn't compatible with the asml binary you may need to build from source instead. The easiest way to do this is to install with &lt;code&gt;cargo&lt;/code&gt; by running &lt;code&gt;cargo install assemblylift --version 0.4.0-alpha.3&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Ruby function
&lt;/h3&gt;

&lt;p&gt;We'll create a new project with a Ruby template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;asml init &lt;span class="nt"&gt;-n&lt;/span&gt; ruby-example &lt;span class="nt"&gt;-l&lt;/span&gt; ruby
&lt;span class="nb"&gt;cd &lt;/span&gt;ruby-example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a basic Ruby function called &lt;code&gt;my-function&lt;/code&gt; inside a service &lt;code&gt;my-service&lt;/code&gt;. These can be renamed as you like, however the directory names also currently need to be updated manually to match (we'll have this sync in a future release :)).&lt;/p&gt;

&lt;p&gt;Add an HTTP route definition to the function in &lt;code&gt;service.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="nn"&gt;[[api.functions]]&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;"my-function"&lt;/span&gt;
&lt;span class="py"&gt;language&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ruby"&lt;/span&gt;
&lt;span class="py"&gt;registry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ecr"&lt;/span&gt; &lt;span class="c"&gt;# or "dockerhub" if using Docker Hub&lt;/span&gt;
&lt;span class="nn"&gt;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;verb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ALL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/my-service/my-function"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Set provider and configure container registry
&lt;/h3&gt;

&lt;p&gt;Again in &lt;code&gt;service.toml&lt;/code&gt;, add the following to use the Kubernetes backend provider:&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;[service.provider]&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;"k8s"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in &lt;code&gt;assemblylift.toml&lt;/code&gt;, configure the container registry you wish to use:&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;[[registries]]&lt;/span&gt;
&lt;span class="py"&gt;host&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ecr"&lt;/span&gt;
&lt;span class="nn"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;aws_account_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"12345890"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;aws_region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"us-east-1"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nn"&gt;[[registries]]&lt;/span&gt;
&lt;span class="py"&gt;host&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"dockerhub"&lt;/span&gt;
&lt;span class="nn"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;registry_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;name&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;username&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;password&amp;gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Write some Ruby!
&lt;/h3&gt;

&lt;p&gt;Next, let's open up the function's &lt;code&gt;handler.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'asml'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'base64'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'json'&lt;/span&gt;

&lt;span class="k"&gt;def&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;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# TODO implement your function code here!&lt;/span&gt;
    &lt;span class="no"&gt;Asml&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;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Asml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_function_input&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;asml&lt;/code&gt; module includes the &lt;code&gt;Asml&lt;/code&gt; class, which exposes basic methods for interacting with the AssemblyLift runtime environment.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;input&lt;/code&gt; object has shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;method:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;headers:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;body_encoding:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;body:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;String&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can decode the body and log it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&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;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'body_encoding'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'base64'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="no"&gt;Base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode64&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="s1"&gt;'body'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="no"&gt;Asml&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="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="no"&gt;Asml&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="s2"&gt;"OK"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build, deploy, test!
&lt;/h3&gt;

&lt;p&gt;Generate your deployment by running &lt;code&gt;asml cast&lt;/code&gt;. If there are no errors, you should see a Terraform plan in the output. &lt;/p&gt;

&lt;p&gt;Deploy your service with &lt;code&gt;asml bind&lt;/code&gt;! Once deployed successfully, your cluster should have a Gloo Edge installation in the &lt;code&gt;gloo-system&lt;/code&gt; namespace and a function deployed as &lt;code&gt;ClusterIP&lt;/code&gt;s in an &lt;code&gt;asml-*&lt;/code&gt; namespace for your service (you can check this by running &lt;code&gt;kubectl get namespaces&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The Gloo Edge Gateway will have created a LoadBalancer resource, which should be deployed by your Kubernetes host (e.g. Digital Ocean). You should be able to &lt;code&gt;curl&lt;/code&gt; the LoadBalancer public IP with your function's route!&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;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"Hello World"&lt;/span&gt; http://&amp;lt;ip&amp;gt;/my-service/my-function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reach out!
&lt;/h2&gt;

&lt;p&gt;Whether you have questions about using AssemblyLift or just want to chat, you can find us &lt;a href="https://discord.gg/pVSCqYgra3"&gt;on Discord&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>cloud</category>
      <category>webassembly</category>
      <category>ruby</category>
    </item>
    <item>
      <title>AssemblyLift v0.4.0-alpha released with Kubernetes support, WASI (WebAssembly on K8s)</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Wed, 27 Apr 2022 18:00:37 +0000</pubDate>
      <link>https://forem.com/akkoro/assemblylift-v040-alpha-released-with-kubernetes-support-wasi-webassembly-on-k8s-5bj8</link>
      <guid>https://forem.com/akkoro/assemblylift-v040-alpha-released-with-kubernetes-support-wasi-webassembly-on-k8s-5bj8</guid>
      <description>&lt;p&gt;Hello devs! 👋🏻 We're back!&lt;/p&gt;

&lt;p&gt;Today we're making available the first alpha release of &lt;a href="https://github.com/akkoro/assemblylift"&gt;AssemblyLift&lt;/a&gt; v0.4. This initial release brings a few exiting improvements to AssemblyLift including&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.wasm.builders/shravi_inamdar/what-is-wasi--4l60"&gt;WASI&lt;/a&gt; modules; Asml functions now target &lt;code&gt;wasm32-wasi&lt;/code&gt; and are compiled as executables instead of libraries&lt;/li&gt;
&lt;li&gt;Simplified Rust function boilerplate (thanks to WASI)&lt;/li&gt;
&lt;li&gt;Experimental Kubernetes backend provider&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/hyperium/hyper"&gt;Hyper&lt;/a&gt;-based HTTP function runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's take a look!&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing
&lt;/h2&gt;

&lt;p&gt;We're going to use the new k8s provider, so as a prerequisite you'll need &lt;code&gt;docker&lt;/code&gt; installed on your system as well as a configured Kubernetes cluster. Functions are written in Rust and will need &lt;code&gt;cargo&lt;/code&gt; to be available as well. Finally, as of writing the AssemblyLift runtime images are hosted on public ECR, which &lt;em&gt;may&lt;/em&gt; require authentication using the &lt;code&gt;aws&lt;/code&gt; CLI. &lt;/p&gt;

&lt;p&gt;You can grab AssemblyLift for macOS with&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;-O&lt;/span&gt; public.assemblylift.akkoro.io/cli/0.4.0-alpha.1/x86_64-apple-darwin/asml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or for Linux with&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;-O&lt;/span&gt; public.assemblylift.akkoro.io/cli/0.4.0-alpha.1/x86_64-linux-gnu/asml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can make the binary executable by running &lt;code&gt;chmod +x asml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If necessary, authenticate docker with ECR using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ecr-public get-login-password &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 | docker login &lt;span class="nt"&gt;--username&lt;/span&gt; AWS &lt;span class="nt"&gt;--password-stdin&lt;/span&gt; public.ecr.aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy a function to Kubernetes
&lt;/h2&gt;

&lt;p&gt;Let's spin up a new project to experiment with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;asml init &lt;span class="nt"&gt;-n&lt;/span&gt; asmlnetes &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;asmlnetes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, open up &lt;code&gt;service.toml&lt;/code&gt; and update our service &amp;amp; function definition to use the k8s backend.&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;[service]&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;"my-service"&lt;/span&gt;

&lt;span class="nn"&gt;[service.provider]&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;"k8s-hyper-alpine"&lt;/span&gt;
&lt;span class="nn"&gt;[service.provider.options]&lt;/span&gt;
&lt;span class="py"&gt;registry_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"my-dockerhub-registry"&lt;/span&gt;
&lt;span class="c"&gt;# ECR is also supported! Instead of registry_name use:&lt;/span&gt;
&lt;span class="c"&gt;# registry_type = "ecr"&lt;/span&gt;
&lt;span class="c"&gt;# aws_account_id = "1234567890"&lt;/span&gt;
&lt;span class="c"&gt;# aws_region = "ca-central-1"&lt;/span&gt;

&lt;span class="nn"&gt;[api.functions.my-function]&lt;/span&gt;
&lt;span class="nn"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&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;"k8s-hyper-alpine"&lt;/span&gt; &lt;span class="p"&gt;}&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;"my-function"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've also deployed the HTTP IOmod as a container which can be specified via the &lt;code&gt;iomod&lt;/code&gt; section as follows&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;[iomod.dependencies.http]&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"container"&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.2.0"&lt;/span&gt;
&lt;span class="py"&gt;coordinates&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"akkoro.std.http"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to play with the HTTP module, you'll need to add the corresponding dependency to the functions' Cargo.toml.&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;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;package&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"assemblylift-iomod-http-guest"&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.2"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our function handler used to be defined in &lt;code&gt;lib.rs&lt;/code&gt;, however with WASI support we now use a regular &lt;code&gt;main&lt;/code&gt; function in &lt;code&gt;main.rs&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;use&lt;/span&gt; &lt;span class="nn"&gt;asml_core&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="nd"&gt;#[handler]&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="nn"&gt;FunctionContext&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="k"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, world!"&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;On both Lambda and Kubernetes platforms, function input is now stored in the variable &lt;code&gt;ctx.input&lt;/code&gt;, which is injected by the handler macro.&lt;/p&gt;

&lt;p&gt;The input shape used by the Hyper runtime isn't finalized, but as of writing you deserialize function input as follows&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;collections&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BTreeMap&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;asml_core&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;serde&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[handler]&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;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HttpFunctionRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&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;ctx&lt;/span&gt;&lt;span class="py"&gt;.input&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;// The event body is encoded as Z85; in this case we assume it's a string, but it could be binary!&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&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;str&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_utf8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;z85&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="py"&gt;.body&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;.unwrap&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="nn"&gt;FunctionContext&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Body = {:?}&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="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Deserialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;HttpFunctionEvent&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="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BTreeMap&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="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="n"&gt;body&lt;/span&gt;&lt;span class="p"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IOmods are called as they have been in previous versions, but the new version of the HTTP module guest includes a handy request builder to make things a little easier 🙂&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;collections&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BTreeMap&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;asml_core&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;serde&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Deserialize&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;http&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;HttpRequestBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[handler]&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;http_req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;HttpRequestBuilder&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;.method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.host&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"akkoro.io"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.path&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;.build&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;http_res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;http&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http_req&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="nn"&gt;FunctionContext&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="k"&gt;log&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;"HTTP status: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http_res&lt;/span&gt;&lt;span class="py"&gt;.code&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nn"&gt;FunctionContext&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Body = {:?}&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="n"&gt;http_res&lt;/span&gt;&lt;span class="py"&gt;.body&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Deserialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;HttpFunctionEvent&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="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BTreeMap&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="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="n"&gt;body&lt;/span&gt;&lt;span class="p"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;asml cast&lt;/code&gt; should compile the function and generate a Terraform plan, which if everything is defined correctly should create some Kubernetes resources in a namespace (asml-{project_name}-{service_name}).&lt;/p&gt;

&lt;p&gt;This &lt;em&gt;should&lt;/em&gt; work against whatever cluster is defined in &lt;code&gt;~/.kube/config&lt;/code&gt;, however at the moment only a &lt;code&gt;NodePort&lt;/code&gt; service is created for each function -- &lt;code&gt;LoadBalancer&lt;/code&gt; support for cloud deployments on AKS and such will come in a later update.&lt;/p&gt;

&lt;p&gt;After running &lt;code&gt;asml bind&lt;/code&gt; to deploy your service(s), you'll be able to find the function pods for example with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; asml-asmlnetes-my-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're running on a local K8s cluster (I use the distro provided by Docker Desktop personally), you can cURL requests to &lt;code&gt;localhost&lt;/code&gt; on the exposed NodePorts for each function.&lt;/p&gt;

&lt;p&gt;Find the port by listing the function services&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get services &lt;span class="nt"&gt;-n&lt;/span&gt; asml-asmlnetes-my-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;The 0.4.0-alpha.x series will iterate on the above compute platform enhancements, concentrating mainly on k8s support.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://dev.to/akkoro/whats-next-for-assemblylift-data-oriented-cloud-dev-through-webassembly-and-capability-based-security-fn3"&gt;data model we wrote about&lt;/a&gt; a while ago is still going through more of a design phase. The plan is to introduce that functionality in a 0.4.0-beta series, and iterate on that up to the final 0.4 release.&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>kubernetes</category>
      <category>cloud</category>
      <category>rust</category>
    </item>
    <item>
      <title>What's next for AssemblyLift? Data-oriented cloud dev through WebAssembly and capability-based security</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Tue, 19 Oct 2021 16:07:45 +0000</pubDate>
      <link>https://forem.com/akkoro/whats-next-for-assemblylift-data-oriented-cloud-dev-through-webassembly-and-capability-based-security-fn3</link>
      <guid>https://forem.com/akkoro/whats-next-for-assemblylift-data-oriented-cloud-dev-through-webassembly-and-capability-based-security-fn3</guid>
      <description>&lt;p&gt;After nearly two years in part-time development, &lt;a href="https://assemblylift.akkoro.io"&gt;AssemblyLift&lt;/a&gt; has been through three major revisions, sitting now at v0.3.2.&lt;/p&gt;

&lt;p&gt;The focus up to now has been on creating a low-friction environment for building applications with functions and APIs, and on the core functionality of the WebAssembly runtime. Using a simple TOML definition, AssemblyLift makes it easy to deploy Rust functions to AWS Lambda fronted by API Gateway. TL;DR it's a nifty little API-oriented compute framework!&lt;/p&gt;

&lt;p&gt;Conspicuously missing from this framework however is any notion of &lt;em&gt;data&lt;/em&gt;. Where do we store it? Who is allowed to access it? I've personally never written a dynamic web service that didn't need to interact with a data store in some way or another!&lt;/p&gt;

&lt;p&gt;It's common to pair serverless compute like Lambda with a serverless database like DynamoDB. This pairing requires the Lambda function to have an attached IAM policy granting it the necessary access to DynamoDB resources. With AssemblyLift currently, attaching IAM policies is done either via the AWS Console or by including your own Terraform code with the AssemblyLift project (this process is covered in &lt;a href="https://dev.to/akkoro/lambda-function-http-authorization-with-auth0-and-assemblylift-webassembly-lambda-api-gateway-rust-4fl8"&gt;another blog post&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This service-to-service permissions model is common among cloud providers, and is usually implemented as Role-Based Access Control or &lt;em&gt;RBAC&lt;/em&gt;. In our example above, a Lambda function is assigned an &lt;em&gt;execution role&lt;/em&gt; which has one or more policies attached. If the function is allowed to assume the role, and if the attached policies allow it the function can access DynamoDB. Or more accurately, it can access whichever DDB resources are specified in the policy &lt;code&gt;resources&lt;/code&gt; list. AWS policies also allow you to specify a list of &lt;em&gt;conditions&lt;/em&gt; on the data which can be accessed, for example by only allowing &lt;code&gt;GetItem&lt;/code&gt; for items with a particular prefix on the primary key. &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/access-control-overview.html"&gt;The official AWS docs&lt;/a&gt; contain more details on DynamoDB access management.&lt;/p&gt;

&lt;p&gt;In a serverless context, this model of access control can create some problems. To maintain the &lt;a href="https://www.upguard.com/blog/principle-of-least-privilege"&gt;Principle of Least Privilege&lt;/a&gt; it is recommended to keep a one-to-one relationship between functions and roles, i.e. functions should not share roles. At scale you may have hundreds of functions, for each of which a unique access policy is maintained. This means that changes to access policy for any data potentially has to be replicated many times. This complexity increases the risk of having misconfigured and/or inconsistent access policies, even if they are represented as code. Using policy conditions to restrict data access is problematic, as your database "schema" (the format of your keys) is then hard-coded separately from the function code.&lt;/p&gt;

&lt;p&gt;We didn't want to expose this complexity in AssemblyLift. It's the kind of "plumbing" code nobody enjoys writing, and it's also the kind that tends to get glossed over simply because it's hard to get right. Fortunately, it is now 2021 and we have some new tools at our disposal!&lt;/p&gt;

&lt;h2&gt;
  
  
  Entity-Capability Data Access Control
&lt;/h2&gt;

&lt;p&gt;Entity-Capability Data Access Control (ECDAC) is the tentative name for the data access model being developed for AssemblyLift (as a kind of nod to the &lt;a href="https://en.wikipedia.org/wiki/Entity_component_system"&gt;Entity-Component-System&lt;/a&gt; architecture which inspired it). The model is intended to alleviate the issues with policy definition described above. It is also meant to address issues with maintaining &amp;amp; communicating entity/object schema definitions between many functions and services, which will be discussed below.&lt;/p&gt;

&lt;p&gt;In this scheme there are (as you might have guessed) two essential components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entities&lt;/li&gt;
&lt;li&gt;Capabilities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When we talk about an &lt;em&gt;Entity&lt;/em&gt;, we mean an object of some kind with a unique ID (e.g. Person, Account, Post, Comment, etc). This is the same sort of entity concept which is often used in database design, including &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-modeling-nosql-B.html"&gt;DynamoDB "single-table" design&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Capabilities&lt;/em&gt; refers to capabilities in the capability-based computing/security sense. Connor Hicks at Suborbital &lt;a href="https://blog.suborbital.dev/reorienting-around-capability-based-computing"&gt;wrote an excellent blog post&lt;/a&gt; which discusses the details and benefits of the capability-based model better than I probably can here. In short, capabilities define what an application component &lt;em&gt;can do&lt;/em&gt;. A Capability is typically some kind of unforgeable token or object, which embeds a set of access rights.&lt;/p&gt;

&lt;p&gt;An important distinction between access rights encoded as a Capability, and access rights encoded in an RBAC policy, is that &lt;em&gt;&lt;strong&gt;Capabilities can be transmitted and shared&lt;/strong&gt;&lt;/em&gt; and &lt;em&gt;&lt;strong&gt;possessing a valid Capability implies valid access&lt;/strong&gt;&lt;/em&gt;. By possessing a valid Capability, application code can verify that it is allowed to perform an action. In an RBAC system on the other hand the entire function must assume a role (effectively pretending to be a "user"), and in turn take on the union of all permissions provided by the attached policies. Access is validated independently of the function code (after the code has already executed) by an authorization service and rejected if the policy doesn't allow the action.&lt;/p&gt;

&lt;p&gt;In our ECDAC model, an entity is composed of a unique ID, a &lt;em&gt;shape&lt;/em&gt; describing any necessary schema, and a set of &lt;em&gt;capabilities&lt;/em&gt; defining how data described by this entity can be accessed. This inversion of control -- keeping access control with the data rather than the service -- is made possible by using WebAssembly modules to implement our Entities!&lt;/p&gt;

&lt;p&gt;The implementation details are still being worked out, but the central idea is that our data Capability is compiled as an executable WASM module, which is an Entity insofar as it implements the Entity ABI. An Entity is a Capability as a WASM module.&lt;/p&gt;

&lt;p&gt;A service defines an Entity as a kind of dependency. This means the service possesses an Entity, which in turn means possessing a Capability. An AssemblyLift guest will interact with Entities through a high-level API, which delegates to the Entity module to verify the Capability, and operate on data in a particular location according to the Entity shape/schema. The Entity module is self-verifying and needs no outside processes to validate the requested action. &lt;em&gt;If&lt;/em&gt; we want Entities to &lt;em&gt;perform&lt;/em&gt; database operations on behalf of the guest, they will need either an &lt;a href="https://docs.assemblylift.akkoro.io/learn-assemblylift/io-modules"&gt;IOmod&lt;/a&gt; or WASI environment. Otherwise it will return back to the AssemblyLift host to complete the action (I'm personally torn on what the best choice here is 🙃).&lt;/p&gt;

&lt;p&gt;An example Entity definition for an AssemblyLift project might look like the following:&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;[entity]&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;"user"&lt;/span&gt;

&lt;span class="nn"&gt;[[fields]]&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;"name"&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"string"&lt;/span&gt;
&lt;span class="py"&gt;attributes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;["searchable"]&lt;/span&gt; &lt;span class="c"&gt;# Optional&lt;/span&gt;

&lt;span class="nn"&gt;[[fields]]&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;"email"&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"string"&lt;/span&gt;
&lt;span class="py"&gt;attributes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"unique"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"primary"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c"&gt;# Optional&lt;/span&gt;

&lt;span class="nn"&gt;[[actions]]&lt;/span&gt;
&lt;span class="py"&gt;action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"load"&lt;/span&gt;
&lt;span class="nn"&gt;[actions.cap]&lt;/span&gt;
&lt;span class="py"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"asml/service/service-name/*"&lt;/span&gt;
&lt;span class="py"&gt;effect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"allow"&lt;/span&gt;

&lt;span class="nn"&gt;[[actions]]&lt;/span&gt;
&lt;span class="py"&gt;action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"store"&lt;/span&gt;
&lt;span class="nn"&gt;[actions.cap]&lt;/span&gt;
&lt;span class="py"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"dynamodb/region/table-name"&lt;/span&gt;
&lt;span class="py"&gt;effect&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"allow"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example we have an Entity representing a &lt;em&gt;user&lt;/em&gt; which has defined a &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;email&lt;/code&gt; field. The entity specifies two actions &lt;code&gt;load&lt;/code&gt; and &lt;code&gt;store&lt;/code&gt;, each of which have an associated Capability. The &lt;code&gt;load&lt;/code&gt; action specifies a &lt;code&gt;location&lt;/code&gt;, which is a unique identifier specifying a resource which can perform the action on the Entity (i.e. the Entity says "who can retrieve me?"). Similarly the &lt;code&gt;store&lt;/code&gt; action specifies a &lt;code&gt;location&lt;/code&gt; indicating where it can be stored (i.e. the Entity says "who can receive me?").&lt;/p&gt;

&lt;p&gt;From within our function code, we can interact with an API which abstracts the low-level Entity system 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;let&lt;/span&gt; &lt;span class="n"&gt;user_prototype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Entity&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="s"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;user_prototype&lt;/span&gt;&lt;span class="nf"&gt;.query_all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="err"&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 see a number of benefits over traditional RBAC/IAM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduced policy complexity&lt;/strong&gt;: by defining access in terms of database entities, we eliminate the need to maintain unique policies for each function in an application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified access definition&lt;/strong&gt;: data-oriented access control decouples resource access from data access, and lets us reduce the surface area of the policy language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved data access transparency&lt;/strong&gt;: "who can access this data?" is answered by the data's Entity definition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent entity schema&lt;/strong&gt;: the shape of an Entity is stored in the module, distributing schema rules to every function which has the Entity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When is this coming?
&lt;/h2&gt;

&lt;p&gt;Development is in progress now, and the plan as of writing is to get a version of this introduced in v0.4.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.sciencedirect.com/science/article/pii/S089571771300054X"&gt;Gusmeroli et al. published a paper in 2013&lt;/a&gt; describing many of these limitations of RBAC in the context of the Internet of Things (IoT). Role management for a large fleet of devices and for a large fleet of services &amp;amp; functions has many parallels.&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>rust</category>
      <category>serverless</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>Lambda function HTTP authorization with Auth0 and AssemblyLift (WebAssembly + Lambda + API Gateway + Rust)</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Sat, 09 Oct 2021 13:34:06 +0000</pubDate>
      <link>https://forem.com/akkoro/lambda-function-http-authorization-with-auth0-and-assemblylift-webassembly-lambda-api-gateway-rust-4fl8</link>
      <guid>https://forem.com/akkoro/lambda-function-http-authorization-with-auth0-and-assemblylift-webassembly-lambda-api-gateway-rust-4fl8</guid>
      <description>&lt;p&gt;Oh, hello! Sorry, I didn't see you there.&lt;/p&gt;

&lt;p&gt;Since you're here, let's talk about &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;Lambda&lt;/a&gt; function authorization!&lt;/p&gt;

&lt;p&gt;By itself, the only way a Lambda function has to reject an invocation is with an IAM policy. This will let you prevent another service from &lt;em&gt;programmatically&lt;/em&gt; invoking the function via the AWS SDK. In most cases however it's considered bad practice to directly invoke a function in this way, due to the coupling it can introduce between two services.&lt;/p&gt;

&lt;p&gt;A better approach is to invoke the function via HTTP &lt;a href="https://aws.amazon.com/api-gateway/" rel="noopener noreferrer"&gt;API Gateway&lt;/a&gt;, and make the underlying function an implementation detail. In addition to decoupling, with an API Gateway we can now use HTTP authorization schemes such as OAuth to protect our functions!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://auth0.com/" rel="noopener noreferrer"&gt;Auth0&lt;/a&gt; offers a highly-regarded (and easy to use, personally speaking) authentication platform, which we can use to provide an OAuth authorizer for our API. Auth0 offers a free plan supporting up to 7000 users!&lt;/p&gt;

&lt;p&gt;In this guide we'll use &lt;a href="https://assemblylift.akkoro.io" rel="noopener noreferrer"&gt;AssemblyLift&lt;/a&gt; to deploy our Lambda function, and define our API and an authorizer. AssemblyLift is an open platform which allows you to quickly develop high-performance serverless applications. Service functions are written in the Rust programming language and compiled to WebAssembly. The AssemblyLift CLI takes care of compiling and deploying your code, as well as building and deploying all the needed infrastructure!&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation &amp;amp; assumed knowledge
&lt;/h2&gt;

&lt;p&gt;To follow this guide you will need an &lt;a href="https://portal.aws.amazon.com/billing/signup#/start" rel="noopener noreferrer"&gt;AWS account&lt;/a&gt; if you do not have one already.&lt;/p&gt;

&lt;p&gt;You will also need the &lt;a href="https://rustup.rs/" rel="noopener noreferrer"&gt;Rust toolchain&lt;/a&gt; and &lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;NPM&lt;/a&gt; installed. The Rust toolchain is installed using the &lt;code&gt;rustup&lt;/code&gt; interactive installer. The default options during installation should be fine. After installation you will need to install the &lt;code&gt;wasm32-unknown-unknown&lt;/code&gt; build target for the Rust toolchain (&lt;code&gt;rustup toolchain install wasm32-unknown-unknown&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Once you have these prerequisites you can install AssemblyLift with &lt;code&gt;cargo install assemblylift-cli&lt;/code&gt;. Run &lt;code&gt;asml help&lt;/code&gt; to verify the installation.&lt;/p&gt;

&lt;p&gt;⚠️&lt;strong&gt;NOTE&lt;/strong&gt;⚠️: if you have previously installed AssemblyLift, please make sure you are on the latest version before you begin! Version &lt;code&gt;0.3.2&lt;/code&gt; contains bugfixes affecting this guide. 🙂&lt;/p&gt;

&lt;h3&gt;
  
  
  Assumed knowledge
&lt;/h3&gt;

&lt;p&gt;We are going to write a simple function in &lt;a href="https://rust-lang.org" rel="noopener noreferrer"&gt;Rust&lt;/a&gt; which writes an item to a &lt;a href="https://aws.amazon.com/dynamodb/" rel="noopener noreferrer"&gt;DynamoDB&lt;/a&gt; table, so you should be familiar with Rust (our usage of DynamoDB will be very basic). In particular, you should be comfortable with &lt;a href="https://dev.to/dotxlem/async-rust-but-less-intimidating-2c13"&gt;async/await in Rust&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While this guide should be fairly straightforward, we will be using some &lt;em&gt;slightly&lt;/em&gt; more advanced features of AssemblyLift. If this is your first time using AssemblyLift, consider taking a look &lt;a href="https://dev.to/akkoro/deploy-an-ultra-fast-blog-in-minutes-with-eleventy-and-assemblylift-webassembly-lambda-api-gateway-rust-568l"&gt;this post on deploying an Eleventy static site with AssemblyLift&lt;/a&gt; which is a little simpler.&lt;/p&gt;

&lt;p&gt;You should also be familiar with AWS IAM, as we will need to add permissions to our function enabling access to DynamoDB. Optionally if you know some &lt;a href="https://terraform.io" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;, we will also demonstrate how you can set these permissions from within the project code. 😀&lt;/p&gt;

&lt;h2&gt;
  
  
  Project setup
&lt;/h2&gt;

&lt;p&gt;In your favourite &lt;em&gt;projects&lt;/em&gt; directory, create a new AssemblyLift application and change to that directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ asml init -n auth-tutorial
$ cd auth-tutorial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's start by adding a &lt;code&gt;data&lt;/code&gt; service, in which we will have a &lt;code&gt;put&lt;/code&gt; function that allows us to add a new item to a DynamoDB table.&lt;/p&gt;

&lt;p&gt;Generate the new service &amp;amp; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ asml make service data
$ asml make function data.put
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order for AssemblyLift to recognize the new service, it must be added to the project manifest &lt;code&gt;assemblylift.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="nn"&gt;[project]&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;"auth0-tutorial"&lt;/span&gt;

&lt;span class="nn"&gt;[services]&lt;/span&gt;
&lt;span class="py"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&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;"data"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you like, you can delete the &lt;code&gt;default&lt;/code&gt; service from the manifest as well as remove its directory under &lt;code&gt;services/&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an Auth0 API
&lt;/h3&gt;

&lt;p&gt;With the base of our AssemblyLift project set up, now would be a good time to create a new API in Auth0. This will provide JWT authorization to our &lt;code&gt;data.put&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;In your Auth0 dashboard, navigate to &lt;em&gt;Applications &amp;gt; APIs&lt;/em&gt; and hit &lt;em&gt;Create API&lt;/em&gt;.&lt;br&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%2Fuploads%2Farticles%2Fltiqrtqjaihwiavrhswo.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%2Fuploads%2Farticles%2Fltiqrtqjaihwiavrhswo.png" alt="A screenshot of the "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Leave the signing algorithm as RS256, and give your API a name. The &lt;em&gt;identifier&lt;/em&gt; is a unique string which is used within OAuth 2.0 to identify the authorization server which issued a token. It is recommended to use the URL of the endpoint which will be associated with this authorizer, however you are free to use whichever naming scheme you like!&lt;/p&gt;
&lt;h2&gt;
  
  
  Configure the &lt;code&gt;data&lt;/code&gt; service
&lt;/h2&gt;

&lt;p&gt;Next let's open up the data service manifest &lt;code&gt;services/data/service.toml&lt;/code&gt;, and replace the default configuration with the following:&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;# data/service.toml&lt;/span&gt;
&lt;span class="nn"&gt;[service]&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;"data"&lt;/span&gt;

&lt;span class="nn"&gt;[api.functions.put]&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;"put"&lt;/span&gt;
&lt;span class="py"&gt;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;verb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"PUT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/put"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="py"&gt;authorizer_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"auth0"&lt;/span&gt;

&lt;span class="nn"&gt;[api.authorizers.auth0]&lt;/span&gt;
&lt;span class="py"&gt;auth_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"JWT"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure the authorizer
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;JWT&lt;/code&gt; authorizer at minimum requires &lt;code&gt;audience&lt;/code&gt; and &lt;code&gt;issuer&lt;/code&gt; parameters. The &lt;em&gt;audience&lt;/em&gt; is the &lt;em&gt;identifer&lt;/em&gt; you chose for your API in the Auth0 console. The &lt;em&gt;issuer&lt;/em&gt; is going to be a URL of the form &lt;code&gt;https://&amp;lt;tenant-id&amp;gt;.&amp;lt;region&amp;gt;.auth0.com&lt;/code&gt;. You can find your tenant ID and region on the &lt;em&gt;settings&lt;/em&gt; tab of the Auth0 console.&lt;/p&gt;

&lt;p&gt;Add the parameters to the &lt;code&gt;auth0&lt;/code&gt; definition:&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;# data/service.toml&lt;/span&gt;
&lt;span class="nn"&gt;[api.authorizers.auth0]&lt;/span&gt;
&lt;span class="py"&gt;auth_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"JWT"&lt;/span&gt;
&lt;span class="py"&gt;audience&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"your-identifier-here"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="py"&gt;issuer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://&amp;lt;tenant-id&amp;gt;.&amp;lt;region&amp;gt;.auth0.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing data with the &lt;code&gt;put&lt;/code&gt; function
&lt;/h2&gt;

&lt;p&gt;This will be a relatively simple function which writes some data to a DynamoDB table, as an example of an operation that really ought to be protected by an authorizer 😜&lt;/p&gt;

&lt;p&gt;We will need to add a dependency to the DynamoDB &lt;a href="https://docs.assemblylift.akkoro.io/learn-assemblylift/io-modules/registry" rel="noopener noreferrer"&gt;IOmod&lt;/a&gt;. IOmod dependencies are defined in &lt;code&gt;service.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="c"&gt;# data/service.toml&lt;/span&gt;
&lt;span class="nn"&gt;[iomod.dependencies.dynamodb]&lt;/span&gt;
&lt;span class="py"&gt;coordinates&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"akkoro.aws.dynamodb"&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.5"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will also need to add a Cargo dependency to our &lt;code&gt;put&lt;/code&gt; function. IOmod dependencies are paired with "guest crates" which provide an API to the IOmod. If you are familiar with the C or C++ programming language, you can think of this as analogous to a header 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;# Cargo.toml&lt;/span&gt;
&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;assemblylift-iomod-dynamodb-guest&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;p&gt;Next let's look at the function code. Find &lt;code&gt;put/src/lib.rs&lt;/code&gt; and update it with the following:&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;// data/put/src/lib.rs&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt; &lt;span class="n"&gt;asml_awslambda&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;asml_core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GuestCore&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;asml_awslambda&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;assemblylift_iomod_dynamodb_guest&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;put_item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;structs&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="nd"&gt;handler!&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="n"&gt;LambdaContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiGatewayEvent&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;async&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;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="py"&gt;.event.request_context&lt;/span&gt;
                &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="py"&gt;.authorizer&lt;/span&gt;
                &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="py"&gt;.claims&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;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sub"&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;.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="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;PutItemInput&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.table_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"auth0-tutorial"&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;// Change this to the name of your own DynamoDB table!&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;PutItemInputAttributeMap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;pk_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;AttributeValue&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;pk_value&lt;/span&gt;&lt;span class="py"&gt;.s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;AttributeName&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pk"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;pk_value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nf"&gt;put_item&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="k"&gt;.await&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;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;http_ok!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;http_error!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function calls the DynamoDB &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html" rel="noopener noreferrer"&gt;&lt;code&gt;PutItem&lt;/code&gt;&lt;/a&gt; action, to write the authenticated user's ID to a table called &lt;code&gt;auth0-tutorial&lt;/code&gt; with a primary key named &lt;code&gt;pk&lt;/code&gt;. The user ID is written as the primary key, as you might if this were a real table tracking user data.&lt;/p&gt;

&lt;p&gt;All IOmod calls in Rust return a type implementing &lt;code&gt;Future&lt;/code&gt;, giving us support for &lt;code&gt;await&lt;/code&gt; syntax! The action is called with the &lt;code&gt;input&lt;/code&gt; struct we built, and an HTTP response is returned when the action is resolved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Function permissions
&lt;/h3&gt;

&lt;p&gt;In order for our function to access DynamoDB, we will have to attach an IAM policy to the function's execution role which allows access.&lt;/p&gt;

&lt;p&gt;Unfortunately this is not handled in the AssemblyLift TOML directly at the moment (we are taking our time sorting out how permissions will be modelled in AssemblyLift 🙂). Your options are to find the role in the &lt;a href="https://console.aws.amazon.com/iamv2/home?#/roles" rel="noopener noreferrer"&gt;AWS IAM console&lt;/a&gt; and add the policy there, or you can use a feature of AssemblyLift which lets you include your own Terraform code with the code generated by the CLI!&lt;/p&gt;

&lt;p&gt;AssemblyLift generates IAM roles for functions named in a particular format; &lt;code&gt;asml-{project name}-{service name}-{function name}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Your own Terraform can be included with the AssemblyLift project by adding a Terraform module inside a directory named &lt;code&gt;user_tf&lt;/code&gt; at the project root (next to &lt;code&gt;assemblylift.toml&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;An example of such a module is below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;provider&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="nx"&gt;aws_caller_identity&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="nx"&gt;aws_region&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="nx"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;account_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_caller_identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account_id&lt;/span&gt;
    &lt;span class="nx"&gt;region&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_region&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;

    &lt;span class="nx"&gt;prefix&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"asml-auth0-tutorial"&lt;/span&gt;
    &lt;span class="nx"&gt;table&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"auth0-tutorial"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt; &lt;span class="nx"&gt;data-put&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-data-put"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_policy_document&lt;/span&gt; &lt;span class="nx"&gt;allow-dynamodb-put&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;actions&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"dynamodb:PutItem"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="nx"&gt;effect&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
      &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:dynamodb:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;account_id&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:table/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&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;resource&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_policy&lt;/span&gt; &lt;span class="nx"&gt;data-put-policy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data-put&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-dynamodb"&lt;/span&gt;
    &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_policy_document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allow-dynamodb-put&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role_policy_attachment&lt;/span&gt; &lt;span class="nx"&gt;data-put-policy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;role&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data-put&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data-put-policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Terraform's &lt;code&gt;data&lt;/code&gt; lookup feature is used to import the role AssemblyLift created for you. A caveat here is that you must have run &lt;code&gt;asml bind&lt;/code&gt; at least once prior to adding this lookup, in order for it to be found! See the next section below on building &amp;amp; deploying!&lt;/p&gt;

&lt;h2&gt;
  
  
  Build &amp;amp; deploy the &lt;code&gt;data&lt;/code&gt; service!
&lt;/h2&gt;

&lt;p&gt;This part is quite easy with AssemblyLift! ☺️&lt;/p&gt;

&lt;p&gt;Use the &lt;code&gt;cast&lt;/code&gt; command to compile your function code, and generate a Terraform plan. Then use the &lt;code&gt;bind&lt;/code&gt; command to deploy the serialized code &amp;amp; infra to AWS!&lt;/p&gt;

&lt;p&gt;Before running &lt;code&gt;bind&lt;/code&gt;, check the output of all the processes executed during &lt;code&gt;cast&lt;/code&gt; to verify that the function compiled OK and that the infrastructure changes reported by Terraform aren't unexpected.&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;$ &lt;/span&gt;asml cast
&lt;span class="nv"&gt;$ &lt;/span&gt;asml &lt;span class="nb"&gt;bind&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing our function authorizer
&lt;/h2&gt;

&lt;p&gt;The easiest way to test the authorizer is to use the &lt;code&gt;curl&lt;/code&gt; commands generated for you in the Auth0 dashboard! Navigate to the &lt;em&gt;test&lt;/em&gt; tab of your API in the dashboard. The command you are looking for is of the form:&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;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; http://path_to_your_api/ &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'authorization: Bearer &amp;lt;TOKEN&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your API endpoint URL can be found in the &lt;a href="https://console.aws.amazon.com/apigateway/main/apis" rel="noopener noreferrer"&gt;AWS API Gateway console&lt;/a&gt;. This endpoint corresponds to the &lt;code&gt;data&lt;/code&gt; service. Our &lt;code&gt;put&lt;/code&gt; function is at the path (and verb) we defined in the service definition TOML:&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;--request&lt;/span&gt; PUT &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; https://&amp;lt;api-id&amp;gt;.execute-api.&amp;lt;region&amp;gt;.amazonaws.com/put &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'authorization: Bearer &amp;lt;TOKEN&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calling the endpoint &lt;strong&gt;without&lt;/strong&gt; the authorization header should return an HTTP Forbidden error. Otherwise it should return HTTP OK with an empty JSON object &lt;code&gt;{}&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;Open the &lt;a href="https://console.aws.amazon.com/dynamodbv2/home" rel="noopener noreferrer"&gt;DynamoDB web console&lt;/a&gt; and verify that the PutItem call worked; there should be an item with your Auth0 user ID!&lt;/p&gt;

&lt;h2&gt;
  
  
  That's all, folks!
&lt;/h2&gt;

&lt;p&gt;If you have any questions, please don't hesitate to reach out in the comments below or &lt;a href="https://github.com/akkoro/assemblylift/discussions" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
      <category>rust</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Deploy an ultra-fast blog in minutes with Eleventy and AssemblyLift (WebAssembly + Lambda + API Gateway + Rust)</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Tue, 28 Sep 2021 20:49:55 +0000</pubDate>
      <link>https://forem.com/akkoro/deploy-an-ultra-fast-blog-in-minutes-with-eleventy-and-assemblylift-webassembly-lambda-api-gateway-rust-568l</link>
      <guid>https://forem.com/akkoro/deploy-an-ultra-fast-blog-in-minutes-with-eleventy-and-assemblylift-webassembly-lambda-api-gateway-rust-568l</guid>
      <description>&lt;p&gt;Hello fellow developers! 😊&lt;/p&gt;

&lt;p&gt;Let's talk about static site generators for a minute. Static Site Generators (SSGs) are popular these days for lots of applications, not least of all personal blogs. Static sites offer quick response times owing to easy caching by CDNs. They also have the advantage of not needing access to a database for content. Perhaps best of all, they can often be hosted for free using a simple S3 bucket or a SaaS such as &lt;a href="https://netlify.com"&gt;Netlify&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An alternative approach is a serverless backend with AWS Lambda and API Gateway. This would allow our "static" file server to do some processing before serving the final HTML if we like. With Lambda, we can control our "server" performance by adjusting the function's memory/CPU allocation. Using API Gateway allows us to monitor and secure our routes (among other things). Lots of benefits while still being cheap, if not free, and high-performance!&lt;/p&gt;

&lt;p&gt;Normally what we've described above would be a pretty complicated set up (and a much longer article 😜). Luckily we can use &lt;a href="https://assemblylift.akkoro.io"&gt;AssemblyLift&lt;/a&gt; to do all the heavy work for us!&lt;/p&gt;

&lt;p&gt;AssemblyLift is an open platform which allows you to quickly develop high-performance serverless applications. Service functions are written in the Rust programming language and compiled to WebAssembly. The AssemblyLift CLI takes care of compiling and deploying your code, as well as building and deploying all the needed infrastructure!&lt;/p&gt;

&lt;p&gt;In this walkthrough we're going to build a blog using &lt;a href="https://11ty.dev"&gt;Eleventy&lt;/a&gt; (11ty), a JavaScript SSG. While I was preparing to write this I started putting together my own blog; the source of which you can &lt;a href="https://github.com/dotxlem/xlem-blog"&gt;take a look at on GitHub&lt;/a&gt; if you'd like to see approximately what we'll be building (your's will undoubtedly be prettier than mine).&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation &amp;amp; assumed knowledge
&lt;/h2&gt;

&lt;p&gt;To follow this guide you will need an &lt;a href="https://portal.aws.amazon.com/billing/signup#/start"&gt;AWS account&lt;/a&gt; if you do not have one already.&lt;/p&gt;

&lt;p&gt;You will also need the &lt;a href="https://rustup.rs/"&gt;Rust toolchain&lt;/a&gt; and &lt;a href="https://nodejs.org"&gt;NPM&lt;/a&gt; installed. The Rust toolchain is installed using the &lt;code&gt;rustup&lt;/code&gt; interactive installer. The default options during installation should be fine. After installation you will need to install the &lt;code&gt;wasm32-unknown-unknown&lt;/code&gt; build target for the Rust toolchain (&lt;code&gt;rustup toolchain install wasm32-unknown-unknown&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Once you have these prerequisites you can install AssemblyLift with &lt;code&gt;cargo install assemblylift-cli&lt;/code&gt;. Run &lt;code&gt;asml help&lt;/code&gt; to verify the installation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assumed knowledge
&lt;/h3&gt;

&lt;p&gt;AssemblyLift functions are written in Rust, so it will be helpful to have a working knowledge of Rust. That said if you are only interested in getting your site deployed, you can safely smile and nod at the Rust code and skip ahead 🙃. Eleventy is a JavaScript framework, however the only JS you &lt;em&gt;need&lt;/em&gt; is its configuration in &lt;code&gt;.eleventy.js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project setup
&lt;/h2&gt;

&lt;p&gt;In your favourite &lt;em&gt;projects&lt;/em&gt; directory, create a new AssemblyLift application for your blog and change to that directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ asml init -n my-blog
$ cd my-blog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we can configure our Eleventy front-end, we'll need to set up our AssemblyLift backend and create our web service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure the default project
&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;asml init&lt;/code&gt; a new AssemblyLift project is generated with the bare minimum needed to build and deploy an application; a single service containing a single function.&lt;/p&gt;

&lt;p&gt;First let's take a look at the &lt;em&gt;application manifest&lt;/em&gt;, &lt;code&gt;assemblylift.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="c"&gt;# Generated with assemblylift-cli&lt;/span&gt;

&lt;span class="nn"&gt;[project]&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;"my-blog"&lt;/span&gt;

&lt;span class="nn"&gt;[services]&lt;/span&gt;
&lt;span class="nn"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&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;"my-service"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need a service which will serve our site assets, so we can start by renaming the default service. Update the &lt;em&gt;services&lt;/em&gt; table and name the service something relevant:&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;# assemblylift.toml&lt;/span&gt;
&lt;span class="nn"&gt;[services]&lt;/span&gt;
&lt;span class="nn"&gt;web&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&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;"web"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will also need to rename the service's directory:&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;$ &lt;/span&gt;&lt;span class="nb"&gt;mv &lt;/span&gt;services/my-service services/web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next let's open up the &lt;code&gt;web&lt;/code&gt; service manifest, &lt;code&gt;services/web/service.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="c"&gt;# Generated with assemblylift-cli&lt;/span&gt;

&lt;span class="nn"&gt;[service]&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;"my-service"&lt;/span&gt;

&lt;span class="nn"&gt;[api.functions.my-function]&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;"my-function"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rename the service to &lt;code&gt;web&lt;/code&gt;. Then as with our service in the project manifest, we should rename the default function in the service manifest to something relevant:&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;# web/service.toml&lt;/span&gt;
&lt;span class="nn"&gt;[service]&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;"web"&lt;/span&gt;

&lt;span class="nn"&gt;[api.functions.server]&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;"server"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And rename the function directory:&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;$ &lt;/span&gt;&lt;span class="nb"&gt;mv &lt;/span&gt;services/web/my-function services/web/server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we'll need to rename the function inside &lt;code&gt;web/server/Cargo.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="c"&gt;# server/Cargo.toml&lt;/span&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;"server"&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.0.0"&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The server function
&lt;/h2&gt;

&lt;p&gt;Let's take another look inside the service manifest, at the &lt;em&gt;api.functions&lt;/em&gt; table.&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;# web/service.toml&lt;/span&gt;
&lt;span class="nn"&gt;[api.functions.server]&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;"server"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty sparse right? As is, this will deploy a lambda function without any sort of API (though it can still be invoked like any other function via the AWS SDK!). Let's add an HTTP route to our function so we can invoke it from our browser:&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;# web/service.toml&lt;/span&gt;
&lt;span class="nn"&gt;[api.functions.server]&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;"server"&lt;/span&gt;
&lt;span class="nn"&gt;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;verb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/{path+}"&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;http&lt;/code&gt; block has a &lt;code&gt;verb&lt;/code&gt; and a &lt;code&gt;path&lt;/code&gt;. The verb is the HTTP method the function is invoked with (e.g. GET, POST, PUT, etc.). The path (or "route" in some frameworks) is the HTTP path which is mapped to our function. In this case we are using a feature of API Gateway called a &lt;em&gt;proxy path&lt;/em&gt;. This is the &lt;code&gt;{path+}&lt;/code&gt; variable, which globs the entire path as a single variable called &lt;code&gt;path&lt;/code&gt; inside our function code.&lt;/p&gt;

&lt;h3&gt;
  
  
  The function code
&lt;/h3&gt;

&lt;p&gt;So far we've got our infrastructure defined, but the default function code doesn't do much of anything.&lt;/p&gt;

&lt;p&gt;Open up &lt;code&gt;web/server/src/lib.rs&lt;/code&gt;, and overwrite it with the following:&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="c"&gt;// lib.rs&lt;/span&gt;
&lt;span class="c"&gt;// www/server&lt;/span&gt;

&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="n"&gt;crate&lt;/span&gt; &lt;span class="n"&gt;asml_awslambda&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;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Write&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;base64&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;encode&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;flate2&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;write&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GzEncoder&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;flate2&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Compression&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;mime_guess&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;rust_embed&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RustEmbed&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;asml_awslambda&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;asml_core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GuestCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;handler!&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="n"&gt;LambdaContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiGatewayEvent&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;async&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;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="py"&gt;.event.path&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;path&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;path&lt;/span&gt;&lt;span class="nf"&gt;.ends_with&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="p"&gt;{&lt;/span&gt;
        &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="k"&gt;=&amp;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;"{}index.html"&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;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()]),&lt;/span&gt;
        &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&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;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()]),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nn"&gt;AwsLambdaClient&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;console_log&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;"Serving {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;

    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nn"&gt;PublicAssets&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&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="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;gzip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;GzEncoder&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="nn"&gt;Vec&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="nn"&gt;Compression&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&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;mime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nn"&gt;mime_guess&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                    &lt;span class="nf"&gt;.first_or_octet_stream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asset&lt;/span&gt;&lt;span class="py"&gt;.data&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;gzip&lt;/span&gt;&lt;span class="nf"&gt;.write_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gzip&lt;/span&gt;&lt;span class="nf"&gt;.finish&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="nd"&gt;http_ok!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// true, true: we always gzip &amp;amp; encode base64&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;None&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;http_not_found!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.clone&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;#[derive(RustEmbed)]&lt;/span&gt;
&lt;span class="nd"&gt;#[folder&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"../../../www/_site"&lt;/span&gt;&lt;span class="nd"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;PublicAssets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function uses the &lt;a href="https://crates.io/crates/rust-embed"&gt;&lt;code&gt;rust-embed&lt;/code&gt;&lt;/a&gt; crate, which embeds the contents of a directory inside the compiled binary. We use this to store the site generated by Eleventy inside the function!&lt;/p&gt;

&lt;p&gt;We can then use the &lt;code&gt;path&lt;/code&gt; variable passed to the function via the function input (remember our path parameter, &lt;code&gt;{path+}&lt;/code&gt;?) to select which resource to return as our function output. A &lt;code&gt;match&lt;/code&gt; block is used to detect if we have a path ending in a forward slash, indicating that we should default to serving &lt;code&gt;index.html&lt;/code&gt; from that path.&lt;/p&gt;

&lt;p&gt;Other crates are imported as well, to handle Gzip &amp;amp; Base 64 encoding and as well as guessing MIME types for our response headers. In all, you should have the following dependencies in your &lt;code&gt;Cargo.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="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;base64&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.13"&lt;/span&gt;
&lt;span class="py"&gt;direct-executor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.3.0"&lt;/span&gt;
&lt;span class="py"&gt;flate2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;
&lt;span class="py"&gt;mime_guess&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2"&lt;/span&gt;
&lt;span class="py"&gt;rust-embed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"6"&lt;/span&gt;
&lt;span class="py"&gt;serde&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;
&lt;span class="py"&gt;serde_json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;
&lt;span class="nn"&gt;asml_core&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.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;package&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"assemblylift-core-guest"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;assemblylift_core_io_guest&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;package&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"assemblylift-core-io-guest"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;asml_awslambda&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;package&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"assemblylift-awslambda-guest"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing Eleventy
&lt;/h2&gt;

&lt;p&gt;As of now our base infrastructure is ready, but compiling our function will fail because our &lt;code&gt;www&lt;/code&gt; directory doesn't exist yet! Let's fix that; first by creating the directory in our project root:&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;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;www
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;www
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new package in this directory with &lt;code&gt;npm&lt;/code&gt; and then install Eleventy:&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;$ &lt;/span&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @11ty/eleventy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, it will be helpful to take a look at the &lt;a href="https://github.com/11ty/eleventy-base-blog"&gt;Eleventy base blog repo&lt;/a&gt; on GitHub. I recommend copying &lt;code&gt;.eleventy.js&lt;/code&gt; into &lt;code&gt;www&lt;/code&gt; and installing these additional packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev @11ty/eleventy-navigation @11ty/eleventy-plugin-rss @11ty/eleventy-plugin-syntaxhighlight luxon markdown-it markdown-it-anchor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there the structure of your site is really up to you! Look at examples and determine what you like best. &lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;npx @11ty/eleventy&lt;/code&gt; will generate the static site from any template files it finds in the current directory, and by default write the output to &lt;code&gt;_site/&lt;/code&gt;. You will at least need &lt;code&gt;index.*&lt;/code&gt; in order to generate an &lt;code&gt;index.html&lt;/code&gt; to serve.&lt;/p&gt;

&lt;p&gt;A powerful feature of Eleventy is &lt;a href="https://www.11ty.dev/docs/collections/"&gt;collections&lt;/a&gt;. Pages with the same tag are grouped into a collection by the same name, and made available inside our templates. In the base blog repo for example, all posts are placed in a directory and a single JSON file specifies the tags assigned to everything in the directory. Now adding a post to your blog is as easy as adding a new file to your &lt;code&gt;posts&lt;/code&gt; directory!&lt;/p&gt;

&lt;h2&gt;
  
  
  Build &amp;amp; deploy our new site
&lt;/h2&gt;

&lt;p&gt;Once you have something which builds without error in &lt;code&gt;www/_site&lt;/code&gt;, you should have everything necessary to build our application and deploy!&lt;/p&gt;

&lt;p&gt;AssemblyLift applications are built with the &lt;code&gt;cast&lt;/code&gt; command, inside the project root (the directory where &lt;code&gt;assemblylift.toml&lt;/code&gt; is found):&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;$ &lt;/span&gt;asml cast
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will compile our web service &amp;amp; server function, and generate a Terraform infrastructure plan. All build artifacts are serialized in the &lt;code&gt;net/&lt;/code&gt; directory. When our Rust function is compiled, our static site assets are bundled with the resulting WebAssembly binary!&lt;/p&gt;

&lt;p&gt;To deploy our new service, simply run:&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;$ &lt;/span&gt;asml &lt;span class="nb"&gt;bind&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing the web service
&lt;/h3&gt;

&lt;p&gt;If everything in the &lt;code&gt;bind&lt;/code&gt; command completed without error, you should now be able to find a new API Gateway endpoint inside the AWS console. The API will be named &lt;code&gt;asml-{projectName}-{serviceName}&lt;/code&gt;. Navigate to your API details, where you should find an endpoint listed for the &lt;code&gt;$default&lt;/code&gt; stage. Opening this URL in a browser should render your new statically generated blog!&lt;/p&gt;

&lt;h2&gt;
  
  
  Further enhancements
&lt;/h2&gt;

&lt;p&gt;For production use, you will probably want to create a CloudFront distribution using your web server service as the distribution source. The API Gateway service also supports custom domain names, as the generated APIGW/CloudFront URLs are quite ugly 😁.&lt;/p&gt;

&lt;p&gt;If in the future you want to expand your blog with dynamic content, you can create additional services &amp;amp; functions. Note however that if you intend on using CloudFront or other CDN, the &lt;code&gt;web&lt;/code&gt; service should &lt;strong&gt;only&lt;/strong&gt; contain the &lt;code&gt;server&lt;/code&gt; function and all other functionality should reside in other services. This is because the server function uses a proxy path; no other functions in the service would receive invocations!&lt;/p&gt;

&lt;p&gt;In AssemblyLift a new service is created by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ asml make service my-service-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then add a new function to the service with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ asml make function my-service-name.my-function-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any new functions you make which you don't want to be publicly accessible should attach an authorizer. Take a look at &lt;a href="https://dev.to/akkoro/lambda-function-http-authorization-with-auth0-and-assemblylift-webassembly-lambda-api-gateway-rust-4fl8"&gt;this post on using Auth0 with AssemblyLift&lt;/a&gt; for an in-depth guide!&lt;/p&gt;

&lt;h2&gt;
  
  
  That's all, folks!
&lt;/h2&gt;

&lt;p&gt;If you have any questions, don't hesitate to reach out in the comments below or &lt;a href="https://github.com/akkoro/assemblylift/discussions"&gt;on GitHub&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;For more details on AssemblyLift, please see the &lt;a href="https://docs.assemblylift.akkoro.io"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>jamstack</category>
      <category>rust</category>
      <category>webdev</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Deploy a Jamstack site on AWS Lambda with API Gateway in 10 minutes or less 💨</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Thu, 12 Aug 2021 16:48:53 +0000</pubDate>
      <link>https://forem.com/akkoro/deploy-a-jamstack-site-on-aws-lambda-with-api-gateway-in-10-minutes-or-less-kb0</link>
      <guid>https://forem.com/akkoro/deploy-a-jamstack-site-on-aws-lambda-with-api-gateway-in-10-minutes-or-less-kb0</guid>
      <description>&lt;p&gt;&lt;a href="https://jamstack.org" rel="noopener noreferrer"&gt;Jamstack&lt;/a&gt; architecture is all the rage these days, owing to its focus on high performance and scalability. With an emphasis on serving pre-generated content, for some it may feel a little bit like a return to the old days. The underlying infrastructure however is anything but!&lt;/p&gt;

&lt;p&gt;This article will walk through building and deploying a simple static site, served using &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt; and &lt;a href="https://aws.amazon.com/api-gateway/" rel="noopener noreferrer"&gt;API Gateway&lt;/a&gt;. To accomplish this we will use &lt;a href="https://assemblylift.akkoro.io" rel="noopener noreferrer"&gt;AssemblyLift&lt;/a&gt;, an open-source platform designed to quickly &amp;amp; easily accomplish such a task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;You will need an &lt;a href="https://portal.aws.amazon.com/billing/signup#/start" rel="noopener noreferrer"&gt;AWS account&lt;/a&gt; if you do not have one already. The small application you will build here fits comfortably in the free tier. 🙂&lt;/p&gt;

&lt;p&gt;You will also need the &lt;a href="https://rustup.rs/" rel="noopener noreferrer"&gt;Rust toolchain&lt;/a&gt; and &lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;NPM&lt;/a&gt; installed. In addition you will need to install the &lt;code&gt;wasm32-unknown-unknown&lt;/code&gt; build target for the Rust toolchain (&lt;code&gt;rustup toolchain install wasm32-unknown-unknown&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Once you have these prerequisites you can install AssemblyLift with &lt;code&gt;cargo install assemblylift-cli&lt;/code&gt;. Run &lt;code&gt;asml help&lt;/code&gt; to verify the installation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Jamstack project
&lt;/h2&gt;

&lt;p&gt;We will base our application on the AssemblyLift project template available &lt;a href="https://github.com/akkoro/assemblylift-template-jamstack" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;. You can clone this, or click the "use this template" button to create a new repo in your account from the template.&lt;/p&gt;

&lt;p&gt;The template project includes a simple static site that we will build with Webpack. It also includes an AssemblyLift service called &lt;code&gt;www&lt;/code&gt; which implements our server function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project structure
&lt;/h3&gt;

&lt;p&gt;Let's take a closer look at the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── README.md
├── assemblylift.toml
├── babel.config.json
├── package-lock.json
├── package.json
├── services
│   └── www
│       ├── server
│       │   ├── Cargo.lock
│       │   ├── Cargo.toml
│       │   └── src
│       │       └── lib.rs
│       └── service.toml
├── web
│   ├── images
│   │   └── AssemblyLift_logo_with_text.png
│   ├── main.js
│   ├── style
│   │   └── main.css
│   └── views
│       └── index.ejs
└── webpack.config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project root contains configuration files for AssemblyLift, Babel, NPM, and Webpack. There is also the AssemblyLift &lt;code&gt;services&lt;/code&gt; directory, and a directory called &lt;code&gt;web&lt;/code&gt; which we've chosen for our frontend code. Feel free to rename the &lt;code&gt;web&lt;/code&gt; directory if you like, just don't forget to update the Webpack config accordingly!&lt;/p&gt;

&lt;p&gt;This project has one service &lt;code&gt;www&lt;/code&gt; containing one function &lt;code&gt;server&lt;/code&gt; (sometimes written &lt;code&gt;www/server&lt;/code&gt; or &lt;code&gt;www.server&lt;/code&gt;). The server function is a Rust crate containing the function handler.&lt;/p&gt;

&lt;h2&gt;
  
  
  A closer look
&lt;/h2&gt;

&lt;p&gt;Next let's look at the handler function in &lt;code&gt;www/server&lt;/code&gt;. You won't need to change it for this walkthrough, but it will be helpful to understand how it works if you want to expand on it yourself 🙂.&lt;/p&gt;

&lt;h3&gt;
  
  
  The code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt; &lt;span class="n"&gt;asml_awslambda&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;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Write&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;base64&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;encode&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;flate2&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;write&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GzEncoder&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;flate2&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Compression&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;mime_guess&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;rust_embed&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RustEmbed&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;asml_awslambda&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;asml_core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GuestCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;handler!&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="n"&gt;LambdaContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiGatewayEvent&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;async&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;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="py"&gt;.event.path&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;path&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;path&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="kc"&gt;true&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"index.html"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&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;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()]),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nn"&gt;AwsLambdaClient&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;console_log&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;"Serving {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;

    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nn"&gt;PublicAssets&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&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="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;gzip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;GzEncoder&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="nn"&gt;Vec&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="nn"&gt;Compression&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&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;mime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nn"&gt;mime_guess&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                    &lt;span class="nf"&gt;.first_or_octet_stream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asset&lt;/span&gt;&lt;span class="py"&gt;.data&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;gzip&lt;/span&gt;&lt;span class="nf"&gt;.write_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gzip&lt;/span&gt;&lt;span class="nf"&gt;.finish&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="nd"&gt;http_ok!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// true, true: we always gzip &amp;amp; encode base64&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;None&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;http_not_found!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="nf"&gt;.clone&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;#[derive(RustEmbed)]&lt;/span&gt;
&lt;span class="nd"&gt;#[folder&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"../../../dist/"&lt;/span&gt;&lt;span class="nd"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;PublicAssets&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How does it work?
&lt;/h3&gt;

&lt;p&gt;Most of the heavy lifting in this function is done by &lt;a href="https://crates.io/crates/rust-embed" rel="noopener noreferrer"&gt;&lt;code&gt;rust-embed&lt;/code&gt;&lt;/a&gt;, which embeds the contents of &lt;code&gt;dist&lt;/code&gt; (our Webpack output directory) in the compiled binary. This allows our static assets to be deployed to Lambda bundled inside the function code, as long as the resulting binary is less than 50MB.&lt;/p&gt;

&lt;p&gt;The rest of the function code deals mainly with API Gateway. The &lt;code&gt;path&lt;/code&gt; received by the function is matched against the embedded assets; if one is found, it is gzipped and then encoded base64 as required by API Gateway to serve binary content. The &lt;code&gt;content-type&lt;/code&gt; header is set using the &lt;code&gt;mime_guess&lt;/code&gt; crate, defaulting to &lt;code&gt;application/octet-stream&lt;/code&gt; if type cannot be guessed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure, build, deploy
&lt;/h2&gt;

&lt;p&gt;Technically you can deploy the template as-is without any configuration, but you will likely want to at least rename the project. To do this look at &lt;code&gt;assemblylift.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="nn"&gt;[project]&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;"assemblylift-template-jamstack"&lt;/span&gt;

&lt;span class="c"&gt;# In production you should configure an S3 bucket &amp;amp; DynamoDB table for terraform state&lt;/span&gt;
&lt;span class="c"&gt;#[terraform]&lt;/span&gt;
&lt;span class="c"&gt;#state_bucket_name = "my-tf-state"&lt;/span&gt;
&lt;span class="c"&gt;#lock_table_name = "my-tf-lock"&lt;/span&gt;

&lt;span class="nn"&gt;[services]&lt;/span&gt;
&lt;span class="py"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&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;"www"&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 learn more about the AssemblyLift TOML documents on the &lt;a href="https://docs.assemblylift.akkoro.io/learn-assemblylift/services" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;, however this is where you would set the name of the project (included in the names of the created AWS resources) as well as add more services if you want. There is also a block for configuring Terraform remote state storage, which is highly recommended for use in production!&lt;/p&gt;

&lt;p&gt;To build an AssemblyLift application you use the &lt;code&gt;asml cast&lt;/code&gt; command; this will compile everything which needs to be deployed and store it immutably in the &lt;code&gt;net&lt;/code&gt; directory. &lt;/p&gt;

&lt;p&gt;If you haven't built the Webpack project however, you will get an error! Build your web assets first with &lt;code&gt;npm run build&lt;/code&gt;. Once they are available in &lt;code&gt;dist&lt;/code&gt;, your function code should build no problem.&lt;/p&gt;

&lt;p&gt;Finally to deploy our service! AssemblyLift applications are deployed with &lt;code&gt;asml bind&lt;/code&gt;. This process delegates to Terraform and will require appropriate AWS credentials to be available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the server function
&lt;/h2&gt;

&lt;p&gt;Unfortunately you'll have to leave the command line for the next part, as we'll need to access the AWS console to find our new service URL. Ideally in a future release the Asml command line will do more of this for you :).&lt;/p&gt;

&lt;p&gt;First navigate to the API Gateway section of the AWS Console. You should see an API by the name you gave above listed here.&lt;br&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%2Fuploads%2Farticles%2Frq37i0iwt2dkwetcih5q.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%2Fuploads%2Farticles%2Frq37i0iwt2dkwetcih5q.png" alt="A screenshot of the API Gateway console showing a single API listed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the listed API to view more details.&lt;br&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%2Fuploads%2Farticles%2F2fczwzdaavs8sdtu2ow7.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%2Fuploads%2Farticles%2F2fczwzdaavs8sdtu2ow7.png" alt="A screenshot of the API Gateway console showing the listed API stages"&gt;&lt;/a&gt;&lt;br&gt;
This is where each API &lt;em&gt;stage&lt;/em&gt; is listed; AssemblyLift always uses the default stage. The URL is the endpoint used to invoke your API.&lt;/p&gt;

&lt;p&gt;Our API defines only one route, &lt;code&gt;/{path+}&lt;/code&gt; which is called a &lt;em&gt;proxy path&lt;/em&gt;. This instructs API Gateway to take the entire path as a variable called &lt;code&gt;path&lt;/code&gt;. Our server function will map the path &lt;code&gt;/&lt;/code&gt; to &lt;code&gt;/index.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you click on the URL, you should get a very simple static site with the AssemblyLift logo returned back to you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;The first thing you'll want to do of course is replace the template site with your own. You can start by just replacing the content, but you're not obligated to keep using Webpack! This function should be compatible with any framework or site generator that ends with a directory of static assets. &lt;/p&gt;

&lt;p&gt;If you paid attention to the function code above, it might have occurred to you that the assets we serve don't have to be completely static. For example we could instead embed a handlebars template or similar &amp;amp; render it with the &lt;a href="https://crates.io/crates/handlebars" rel="noopener noreferrer"&gt;&lt;code&gt;handlebars&lt;/code&gt;&lt;/a&gt; crate, allowing us "semi-dynamic" content for lack of a better name.&lt;/p&gt;

&lt;p&gt;You may also want to create a CloudFront distribution for your API. I have found performance adequate without a CDN, however it will likely improve with one. Putting a CDN in front of the function should also help hide or smooth out latency due to cold start time, if the function is not invoked regularly. CloudFront is not expensive, however whether it is worth it will be up to you 🙂.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More
&lt;/h2&gt;

&lt;p&gt;The best way to learn about AssemblyLift right now is by visiting the &lt;a href="https://docs.assemblylift.akkoro.io" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also reach out to us on &lt;a href="https://twitter.com/akkorocorp" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, via &lt;a href="https://element.io" rel="noopener noreferrer"&gt;Element&lt;/a&gt; at #assemblylift:matrix.org, or in the comments below!&lt;/p&gt;

</description>
      <category>jamstack</category>
      <category>aws</category>
      <category>rust</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>AssemblyLift v0.3 Released</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Wed, 04 Aug 2021 16:42:45 +0000</pubDate>
      <link>https://forem.com/akkoro/assemblylift-v0-3-released-3p3</link>
      <guid>https://forem.com/akkoro/assemblylift-v0-3-released-3p3</guid>
      <description>&lt;p&gt;After several months in development, AssemblyLift v0.3 has been released and made available via Cargo! 🥳&lt;/p&gt;

&lt;p&gt;If you've never heard of it or just need a reminder, &lt;a href="https://assemblylift.akkoro.io"&gt;AssemblyLift&lt;/a&gt; is an open platform for developing cloud-native applications. At its core are the AssemblyLift Runtime and the AssemblyLift CLI. The runtime provides an environment for executing compiled WebAssembly (WASM) on infrastructure such as AWS Lambda, and is one of the more unique aspects of the platform which we'll dig into more below. &lt;/p&gt;

&lt;p&gt;If you'd like to install the CLI and explore the things being discussed in this post, get started by running&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 assemblylift-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the CLI is currently supported on Linux and macOS only.&lt;/p&gt;

&lt;h2&gt;
  
  
  State of the World
&lt;/h2&gt;

&lt;p&gt;There's an adage I can't remember the origin of, which states that something must be built three times in order to get it right. On the first pass you are learning what you wish to build. On the second, you are learning how to build it. Then on the third, you build it for real.&lt;/p&gt;

&lt;p&gt;It's never quite that simple of course (the road to 1.0 is long), but much of the work that has gone into the v0.3 release is "beneath the surface", making this a rather foundational release so to speak. Lots of key areas were reworked or completely rewritten based on the lessons of v0.1 &amp;amp; v0.2, which make implementing new features easier now and in the future.&lt;/p&gt;

&lt;p&gt;That said, there are also many user-facing improvements which make this the most "complete" offering of AssemblyLift to date!&lt;/p&gt;

&lt;p&gt;Below we'll highlight the major changes between v0.2 and v0.3, and walk through each in more detail in the following sections. Towards the end, I'll discuss a little more about where the project is headed next. 🙂&lt;/p&gt;

&lt;h3&gt;
  
  
  Change List
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Support multiple infrastructure providers for services &amp;amp; functions

&lt;ul&gt;
&lt;li&gt;Experimental Lambda runtime based on Alpine Linux&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;New TOML-&amp;gt;HCL transpiler pipeline&lt;/li&gt;
&lt;li&gt;Support for arbitrarily large data buffers which can be paged into WASM memory (function input and IOmod responses)&lt;/li&gt;
&lt;li&gt;Deployment of &amp;amp; support for the IO Module Registry&lt;/li&gt;
&lt;li&gt;Bump critical dependencies to latest versions! In particular, Tokio 1.x is now used throughout the Asml crate ecosystem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Changes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Infrastructure Providers
&lt;/h3&gt;

&lt;p&gt;I'll be honest; this is the change which took the most work and is easily the least visible 😂&lt;/p&gt;

&lt;p&gt;But! That doesn't mean it wasn't important.&lt;/p&gt;

&lt;p&gt;While AWS Lambda is still the de facto provider, a goal of the project has always been to support deployment to a variety of kinds of infrastructure.&lt;/p&gt;

&lt;p&gt;To accomplish this, most of the code which translated your AssemblyLift TOML into Terraform HCL needed to be thrown away and rewritten. This resulted in the new transpiler mentioned above!&lt;/p&gt;

&lt;p&gt;The new provider implementation was tested with an experimental provider for Lambda based on Alpine Linux. The original purpose for this provider was to support faster, LLVM-compiled WASM binaries which are incompatible with the default Lambda OS. Unfortunately, despite the tiny image size I discovered that cold-start time a for Docker-based Lambda is much too high to be worth it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Buffers &amp;amp; Memory Management
&lt;/h3&gt;

&lt;p&gt;A well-published feature of WebAssembly is its memory model, which is a sandboxed linear memory. This essentially means that WASM code has a large array of bytes to work with inside the sandbox, but there are no pointers or other means of escaping elsewhere. A side-effect of this is that to get new data into WebAssembly from the host, the host must &lt;em&gt;write into&lt;/em&gt; a known region of the linear memory.&lt;/p&gt;

&lt;p&gt;In previous versions, AssemblyLift did not buffer data on the host before passing it to the WASM guest. If the data could not all fit in the defined region within the guest, tough luck!&lt;/p&gt;

&lt;p&gt;Clearly that's no good. So there are now host-side buffers which can reach arbitrary size, and then be paged into a location in WASM via ABI calls as needed. This change shows up both on function input, as well as in IOmod memory management as responses are buffered and handled by the guest.&lt;/p&gt;

&lt;h3&gt;
  
  
  IO Module Registry
&lt;/h3&gt;

&lt;p&gt;Another biggin' that has been in-progress for an age.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.assemblylift.akkoro.io/learn-assemblylift/io-modules"&gt;IO Modules&lt;/a&gt; or &lt;em&gt;IOmods&lt;/em&gt; are a unique feature of AssemblyLift which are used to provide the WASM guest with access to outside functionality.&lt;/p&gt;

&lt;p&gt;As of v0.3 the CLI can fetch IOmod dependencies from the new public IOmod Registry, while IOmods themselves are now shipped in Zip-archived packages. As of writing, the &lt;a href="https://docs.assemblylift.akkoro.io/learn-assemblylift/io-modules/registry"&gt;modules available on the registry&lt;/a&gt; are limited, but more are planned (including modules for all remaining AWS services).&lt;/p&gt;

&lt;h2&gt;
  
  
  Upcoming Improvements
&lt;/h2&gt;

&lt;p&gt;The next point release will focus on improving quality &amp;amp; error handling in a few areas of the code, as well as improving the DX* around the API Gateway/HTTP macros. At the moment for example, the &lt;code&gt;http_ok!&lt;/code&gt; macro expects your response to be JSON. This suits API applications fine, but we would like to be more flexible and to support returning HTML from our functions. This opens us up to full-stack development with AssemblyLift in the future! 😎&lt;/p&gt;

&lt;p&gt;In the longer term, we'll be expanding what can be managed by AssemblyLift directly. For example function permissions and/or IAM policies can not be set in the service TOML at the moment, which is a major usability issue that should be addressed. &lt;/p&gt;

&lt;p&gt;We'll also be evaluating additional providers to support in addition to AWS Lambda.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;* Developer eXperience&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More
&lt;/h2&gt;

&lt;p&gt;The best way to learn about AssemblyLift right now is by visiting the &lt;a href="https://docs.assemblylift.akkoro.io"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also reach out to us on &lt;a href="https://twitter.com/akkorocorp"&gt;Twitter&lt;/a&gt;, via &lt;a href="https://element.io"&gt;Element&lt;/a&gt; at #assemblylift:matrix.org, or in the comments below!&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>rust</category>
      <category>webassembly</category>
      <category>aws</category>
    </item>
    <item>
      <title>AssemblyLift v0.2.9: BIG performance boost + new features! 🚀</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Wed, 10 Feb 2021 04:35:07 +0000</pubDate>
      <link>https://forem.com/dotxlem/assemblylift-v0-2-9-big-performance-boost-new-features-93a</link>
      <guid>https://forem.com/dotxlem/assemblylift-v0-2-9-big-performance-boost-new-features-93a</guid>
      <description>&lt;p&gt;So many updates, so little time!&lt;/p&gt;

&lt;p&gt;As usual I've been neglecting to write stuff down, but I've still been busy. :)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://assemblylift.akkoro.io"&gt;AssemblyLift&lt;/a&gt; has been quietly updated several times recently (mostly in December), iteratively adding features that I needed while building the IOmod registry infrastructure.&lt;/p&gt;

&lt;p&gt;The most recent update, 0.2.9, was just published the other day and includes an upgrade to &lt;a href="https://wasmer.io"&gt;Wasmer&lt;/a&gt; 1.0 inside the AssemblyLift Lambda runtime. The latest build of Wasmer gives us significant gains, so I thought now would be a good time to document all the recent changes! 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Changes for Rust guest code
&lt;/h2&gt;

&lt;p&gt;Guest-facing changes were relatively minor, but offer a lot more flexibility on function input.&lt;/p&gt;

&lt;p&gt;The only breaking change, introduced via 0.2.8, is a change which adds a type parameter to to &lt;code&gt;LambdaContext&lt;/code&gt;. This is the type of the incoming lambda event.&lt;/p&gt;

&lt;p&gt;For a function invoked via HTTP for 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="nd"&gt;handler!&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="n"&gt;LambdaContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiGatewayEvent&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;async&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;The &lt;code&gt;ApiGatewayEvent&lt;/code&gt; struct itself also now deserializes the &lt;code&gt;request_context&lt;/code&gt; field, which gives access to authorization information (such as user ID), among other things.&lt;/p&gt;

&lt;p&gt;For 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="c"&gt;// "sub" is the UUID of the authorized user&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="py"&gt;.request_context&lt;/span&gt;
                &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="py"&gt;.authorizer&lt;/span&gt;
                &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="py"&gt;.claims&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;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sub"&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;.to_string&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Changes to service &amp;amp; function definitions
&lt;/h2&gt;

&lt;p&gt;Service TOML definitions now support specifying authorizers by ID for each function. These map to API Gateway authorizers; currently only IAM and JWT are supported. See the &lt;a href="https://github.com/akkoro/assemblylift/pull/33"&gt;pull request for examples&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The fields &lt;code&gt;timeout&lt;/code&gt; and &lt;code&gt;size&lt;/code&gt; are now recognized optional parameters for function definition. Timeout refers to the function timeout in seconds; the duration after which the function will terminate. Size specifies the function size in megabytes, defaulting to 1024Mb.&lt;/p&gt;

&lt;p&gt;Finally, it is now possible to include custom &lt;a href="https://terraform.io"&gt;Terraform&lt;/a&gt; code in your AssemblyLift app. This code is placed in a directory which &lt;em&gt;must&lt;/em&gt; be called &lt;code&gt;user_tf&lt;/code&gt;. This directory will be interpreted as a Terraform module and injected in the HCL code which is generated by &lt;code&gt;asml&lt;/code&gt; during &lt;code&gt;cast&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changes to core &amp;amp; runtime
&lt;/h2&gt;

&lt;p&gt;As mentioned, the big news here is the upgrade to Wasmer 1.0. Wasmer is the WebAssembly runtime AssemblyLift uses internally to execute compiled WASM code.&lt;/p&gt;

&lt;p&gt;Internally there were many enhancements &amp;amp; fixes to the AssemblyLift runtime, which includes the removal of nearly all Rust code marked &lt;code&gt;unsafe&lt;/code&gt;! In particular the ABI code was simplified a &lt;em&gt;bunch&lt;/em&gt;, with 447 additions and 848 deletions! 🙂&lt;/p&gt;

&lt;h3&gt;
  
  
  Pre-compiled WASM
&lt;/h3&gt;

&lt;p&gt;Previously, WASM modules were loaded &amp;amp; compiled to native binary by Cranelift during Lambda initialization. For simple modules this wasn't so bad, but for real-world use the cold-start times (i.e. the time to start the Lambda runtime) were high -- around 1 second in my usage.&lt;/p&gt;

&lt;p&gt;Wasmer 1.0 supports cross-compiling WASM to native binary and serializing the result, to be loaded later by the runtime. We use this in AssemblyLift, by adding this compilation step to &lt;code&gt;asml cast&lt;/code&gt;. After compiling Rust to WASM, &lt;code&gt;asml&lt;/code&gt; will invoke Cranelift and compile the WASM bytes to Amazon Linux-compatible binary. This brings our cold-start times down to around 200ms! I should disclaim though that this is an anecdotal benchmark; I'll need time to do something more formal.&lt;/p&gt;

&lt;p&gt;Execution speed appears to be faster overall, though I will need to test this further as well. FWIW I can say that a function I have, which performs a batch-write to DynamoDB and then invokes &lt;strong&gt;another&lt;/strong&gt; service function to perform a PUT to S3, has a warm execution time which is usually sub-300ms.&lt;/p&gt;

&lt;p&gt;It is also possible, but not yet supported, to use LLVM in place of Cranelift. This should result even faster execution speed once we get it implemented!&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting Started
&lt;/h1&gt;

&lt;p&gt;If you're coming across AssemblyLift for the first time, you can install it via cargo with:&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;assemblylift-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the &lt;a href="https://assemblylift.akkoro.io"&gt;landing page&lt;/a&gt; for links to resources! Unfortunately, said resources are a tad scarce at the moment, but I assure you it's being worked on. 🙃&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oXjCfyYV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/namgx9nvr79gt5waz7k4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oXjCfyYV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/namgx9nvr79gt5waz7k4.jpg" alt="A screenshot from the movie Clerks, in which Dante hangs the sign which reads &amp;quot;I assure you we're open&amp;quot;"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for looking!&lt;/p&gt;

</description>
      <category>rust</category>
      <category>showdev</category>
      <category>webassembly</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Build a  "todo list" backend with AssemblyLift 🚀🔒</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Sat, 24 Oct 2020 14:43:38 +0000</pubDate>
      <link>https://forem.com/dotxlem/build-a-todo-list-backend-with-assemblylift-1ak3</link>
      <guid>https://forem.com/dotxlem/build-a-todo-list-backend-with-assemblylift-1ak3</guid>
      <description>&lt;p&gt;I don't think it's possible to publish a new framework without demonstrating the classic &lt;em&gt;todo app&lt;/em&gt; with it. Definitely frowned upon. Maybe even illegal (check your local laws).&lt;/p&gt;

&lt;p&gt;Fermenting &lt;a href="https://assemblylift.akkoro.io"&gt;AssemblyLift&lt;/a&gt; to the point that it could run the "hello world" of web &amp;amp; cloud frameworks was the first usability milestone I wanted to hit, and here we are! 🎉 &lt;/p&gt;

&lt;p&gt;This post will introduce some AssemblyLift concepts, and walk you through writing and deploying a backend for a simple todo list app.&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting Started
&lt;/h1&gt;

&lt;p&gt;The AssemblyLift CLI is available via Cargo with &lt;code&gt;cargo install assemblylift-cli&lt;/code&gt;. At least Rust 1.39 is required for &lt;code&gt;async&lt;/code&gt; support, however I haven't confirmed if there are any other features used that would require a higher version. For reference, I've been working with 1.45.&lt;/p&gt;

&lt;p&gt;As of writing, the CLI is compatible with macOS and Linux.&lt;/p&gt;

&lt;p&gt;You will also need an Amazon AWS account, as AssemblyLift deploys to AWS Lambda &amp;amp; API Gateway (with support for other clouds planned!). Additionally, this guide uses AWS DynamoDB as a database. If you don't have an account already, note that each of these services offer a free tier which should be plenty to experiment with 🙂.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️&lt;br&gt;
Please reach out if these services are not offered in your region! I can’t do much short-term, but I’d like to be aware of blind spots :)&lt;/p&gt;

&lt;p&gt;⚠️&lt;br&gt;
For this article I am assuming some familiarity with both AWS and Rust.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Creating a New Project
&lt;/h3&gt;

&lt;p&gt;The AssemblyLift CLI installs itself as &lt;code&gt;asml&lt;/code&gt;. Run &lt;code&gt;asml help&lt;/code&gt; to see a list of commands, as well as the version. This guide is current for version &lt;strong&gt;0.2.5&lt;/strong&gt; (but I'll try to keep it updated :)).&lt;/p&gt;

&lt;p&gt;Create your project by running &lt;code&gt;asml init -n todo&lt;/code&gt;. This will create a project named &lt;code&gt;todo&lt;/code&gt; in &lt;code&gt;./todo&lt;/code&gt;. Then &lt;code&gt;cd&lt;/code&gt; into the directory, as the remaining commands should be run from the project root (the location of &lt;code&gt;assemblylift.toml&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The CLI should have generated a basic project skeleton including a default service, itself including a default function.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔎&lt;br&gt;
A &lt;em&gt;project&lt;/em&gt; in the AssemblyLift sense is essentially a collection of &lt;em&gt;services&lt;/em&gt;. What that collection represents is up to you. For example a project may be a collection of services consumed by an application (like our todo app), or a group of related services that are consumed by other services and/or apps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's take a look first at &lt;code&gt;assemblylift.toml&lt;/code&gt;. The one generated for you should like something 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="nn"&gt;[project]&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;"examples"&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="nn"&gt;[services]&lt;/span&gt;
&lt;span class="nn"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&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;"my-service"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the moment this configuration file defines only some brief info about the project, and the services it contains. It may be expanded with options for project-wide configuration in future releases.&lt;/p&gt;

&lt;p&gt;Let's update the generated values with something specific to our todo project.&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;[project]&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;"todo-app"&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="nn"&gt;[services]&lt;/span&gt;
&lt;span class="nn"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&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;"todo-service"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will also need to rename the service's directory via &lt;code&gt;mv ./services/my-service ./services/todo-service&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Your First Service
&lt;/h1&gt;

&lt;p&gt;Next, let's open up the &lt;code&gt;service.toml&lt;/code&gt; file for &lt;code&gt;todo-service&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="nn"&gt;[service]&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;"my-service"&lt;/span&gt;

&lt;span class="nn"&gt;[api]&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;"my-service-api"&lt;/span&gt;

&lt;span class="nn"&gt;[api.functions.my-function]&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;"my-function"&lt;/span&gt;
&lt;span class="py"&gt;handler_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"handler"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start by editing the names to match the ones we gave in &lt;code&gt;assemblylift.toml&lt;/code&gt; above. We'll also update the default function name to the first function we'll demonstrate here, the "create todo" function. Like with the service, you should rename the function's directory with &lt;code&gt;mv ./services/todo-service/my-function/ ./services/todo-service/create/&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="nn"&gt;[service]&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;"todo-service"&lt;/span&gt;

&lt;span class="nn"&gt;[api]&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;"todo-service-api"&lt;/span&gt;

&lt;span class="nn"&gt;[api.functions.create]&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;"create"&lt;/span&gt;
&lt;span class="py"&gt;handler_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"handler"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;handler_name&lt;/code&gt; field should generally be left alone (and will probably be elided in a future release); you should only change it if you know what you're doing! 🤓&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔎&lt;br&gt;
A &lt;em&gt;service&lt;/em&gt; at its core is a collection of &lt;em&gt;functions&lt;/em&gt;. A service may optionally declare an HTTP API, mapping (verb,path) pairs to functions. Services are required to have at least one function (otherwise there's not much point, right? 😆).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we're here, let's also define the HTTP API for our create function.&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;[api.functions.create]&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;"create"&lt;/span&gt;
&lt;span class="py"&gt;handler_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"handler"&lt;/span&gt;
&lt;span class="nn"&gt;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;verb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/todos"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;http&lt;/code&gt; defined, AssemblyLift will create an HTTP API for the service with routes defined by the functions' &lt;code&gt;verb&lt;/code&gt; (method) and &lt;code&gt;path&lt;/code&gt;. Take a look at the &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html"&gt;API Gateway docs&lt;/a&gt; for information on using path parameters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Dependencies
&lt;/h3&gt;

&lt;p&gt;Our services are going to depend on &lt;a href="https://dev.to/dotxlem/assemblylift-v0-2-preview-rpc-based-io-modules-2d38"&gt;IO modules&lt;/a&gt; (&lt;em&gt;IOmods&lt;/em&gt;). IOmods are similar to packages in other environments such as Node.js. However in AssemblyLift, IOmods are implemented as binary "plugins" and they are how our functions communicate with the outside world.&lt;/p&gt;

&lt;p&gt;Add the following blocks to your &lt;code&gt;service.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="nn"&gt;[iomod.dependencies.aws-dynamodb]&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;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"file"&lt;/span&gt;
&lt;span class="py"&gt;from&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/your/path/to/iomod/akkoro-aws-dynamodb"&lt;/span&gt;

&lt;span class="nn"&gt;[iomod.dependencies.std-crypto]&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;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"file"&lt;/span&gt;
&lt;span class="py"&gt;from&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/your/path/to/iomod/akkoro-std-crypto"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Currently AssemblyLift only supports importing local files. Hopefully in the near future we'll have some registry infrastructure for IOmods. In the meantime, we have a manual step to fetch the latest build of the IOmod standard library. You can &lt;a href="https://github.com/akkoro/assemblylift-iomod-stdlib/suites/1348514110/artifacts/21839165"&gt;download a zip from GitHub here&lt;/a&gt;, and extract the binaries to a directory somewhere on your local system. At the moment the stdlib contains a whopping 2 (!!) modules, for DynamoDB and basic crypto respectively.&lt;/p&gt;

&lt;h1&gt;
  
  
  Your First Function
&lt;/h1&gt;

&lt;p&gt;Finally, some Rust code! 🦀 Let's look at the &lt;code&gt;lib.rs&lt;/code&gt; that was generated for us.&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;extern&lt;/span&gt; &lt;span class="n"&gt;crate&lt;/span&gt; &lt;span class="n"&gt;asml_awslambda&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;asml_core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GuestCore&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;asml_awslambda&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="n"&gt;AwsLambdaClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LambdaContext&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nd"&gt;handler!&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="n"&gt;LambdaContext&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="py"&gt;.event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nn"&gt;AwsLambdaClient&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;console_log&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;"Read event: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nn"&gt;AwsLambdaClient&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;"OK"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the bare minimum you need to have a complete AssemlyLift function written in Rust -- essentially just enough to prove that events are read in and status is written out correctly. The &lt;code&gt;handler!&lt;/code&gt; macro provides the entry point to our function, and hides the boilerplate code necessary to bootstrap the function.&lt;/p&gt;

&lt;p&gt;Let's make it more interesting. We'll start by rewriting this for HTTP invocation:&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;extern&lt;/span&gt; &lt;span class="n"&gt;crate&lt;/span&gt; &lt;span class="n"&gt;asml_awslambda&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;asml_core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GuestCore&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;asml_awslambda&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="nd"&gt;handler!&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="n"&gt;LambdaContext&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ApiGatewayEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="py"&gt;.event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="py"&gt;.body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// TODO&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;None&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;http_error!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"missing request payload"&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;The &lt;code&gt;http_error!&lt;/code&gt; macro is a helper which wraps &lt;code&gt;AwsLambdaClient::success&lt;/code&gt; and returns an HTTP 520 with a JSON response indicating a function error.&lt;/p&gt;

&lt;p&gt;Our create function is going to use the DynamoDB &lt;code&gt;PutItem&lt;/code&gt; call to store a new todo item. Each item will use a UUID for its primary key, for which we'll use the UUID v4 call from the crypto IOmod.&lt;/p&gt;

&lt;p&gt;First we'll need to import a few crates; add the following to the Cargo 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;serde&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0.53"&lt;/span&gt;
&lt;span class="nn"&gt;asml_iomod_dynamodb&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.1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;package&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"assemblylift-iomod-dynamodb-guest"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nn"&gt;asml_iomod_crypto&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.1.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;package&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"assemblylift-iomod-crypto-guest"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll need &lt;code&gt;serde&lt;/code&gt; to serialize/deserialize our request &amp;amp; response JSON. The other two are the "guest" crates for each IOmod we depend on.&lt;/p&gt;

&lt;p&gt;Next, let's add simple request &amp;amp; response structs to &lt;code&gt;lib.rs&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;use&lt;/span&gt; &lt;span class="nn"&gt;serde&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Serialize,&lt;/span&gt; &lt;span class="nd"&gt;Deserialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;CreateTodoRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;body&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="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Serialize,&lt;/span&gt; &lt;span class="nd"&gt;Deserialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;CreateTodoResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;uuid&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request contains only the &lt;code&gt;body&lt;/code&gt; field, which will store the text of the todo item. The item's ID and timestamp will be generated on the function.&lt;/p&gt;

&lt;p&gt;Let's move on to the body of our function. We'll start by deserializing the request body to our &lt;code&gt;CreateTodoRequest&lt;/code&gt; struct.&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="err"&gt;.&lt;/span&gt;
&lt;span class="nf"&gt;.
Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&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;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CreateTodoRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&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;content&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="err"&gt;.&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Easy enough. Next, lets use one of our IOmods! Import the &lt;code&gt;uuid4&lt;/code&gt; call from crypto, and use it to generate a UUID for the item.&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;asml_iomod_crypto&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;span class="nf"&gt;.
Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&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;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CreateTodoRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&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;content&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;uuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IOmod calls always take a single argument for the call's input, and always &lt;a href="https://dev.to/dotxlem/async-rust-but-less-intimidating-2c13"&gt;return a &lt;code&gt;Future&lt;/code&gt;&lt;/a&gt;. The &lt;code&gt;uuid4&lt;/code&gt; call doesn't actually require any input, so we pass &lt;code&gt;()&lt;/code&gt; for the input argument.&lt;/p&gt;

&lt;p&gt;We'll use this value as the primary key for the todo item. We'll construct this item as part of the &lt;code&gt;PutItemInput&lt;/code&gt; struct that our DynamoDB call will take as input.&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;asml_core_io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get_time&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;asml_iomod_crypto&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;span class="nf"&gt;.
Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&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;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CreateTodoRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&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;content&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;uuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;structs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PutItemInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.table_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"todo-example"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nd"&gt;val!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nd"&gt;val!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;get_time&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nd"&gt;val!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="py"&gt;.body&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The timestamp is generated by &lt;code&gt;get_time()&lt;/code&gt;, which returns the system time as the duration in seconds since the "Unix epoch". The &lt;code&gt;get_time&lt;/code&gt; function is an AssemblyLift ABI call, and is always available.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;val!&lt;/code&gt; macro provides a shorthand for writing the DynamoDB value JSON, and is borrowed from the &lt;code&gt;rusoto_dynamodb&lt;/code&gt; crate (as are the structs 🙃).&lt;/p&gt;

&lt;p&gt;The last thing we need to add is a call to DynamoDB's &lt;code&gt;PutItem&lt;/code&gt;, and a response from our a 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;asml_iomod_crypto&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;uuid4&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;asml_iomod_dynamodb&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;structs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;structs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AttributeValue&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="err"&gt;.&lt;/span&gt;
&lt;span class="nf"&gt;.
Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&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;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CreateTodoRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&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;content&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;uuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;structs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PutItemInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.table_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"todo-example"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nd"&gt;val!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nd"&gt;val!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;get_time&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
    &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nd"&gt;val!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="py"&gt;.body&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nf"&gt;put_item&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="k"&gt;.await&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="mi"&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CreateTodoResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
            &lt;span class="nd"&gt;http_ok!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&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;why&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;http_error!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;why&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="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;span class="err"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we've introduced the &lt;code&gt;http_ok!&lt;/code&gt; macro, which returns our response as an HTTP 200. If the call to &lt;code&gt;put_item&lt;/code&gt; fails for some reason, we call our error macro again.&lt;/p&gt;

&lt;p&gt;Putting it all together, the code for our create function should like 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;extern&lt;/span&gt; &lt;span class="n"&gt;crate&lt;/span&gt; &lt;span class="n"&gt;asml_awslambda&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;serde&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Deserialize&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;asml_core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GuestCore&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;asml_awslambda&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;asml_iomod_crypto&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;uuid4&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;asml_iomod_dynamodb&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;structs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;structs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AttributeValue&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="nd"&gt;handler!&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="n"&gt;LambdaContext&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ApiGatewayEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="py"&gt;.event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="py"&gt;.body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&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;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CreateTodoRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&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;content&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;uuid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;structs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PutItemInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.table_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"todo-example"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nd"&gt;val!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nd"&gt;val!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;get_time&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
            &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="py"&gt;.item&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nd"&gt;val!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="py"&gt;.body&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

            &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="nf"&gt;put_item&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="k"&gt;.await&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="mi"&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="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CreateTodoResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
                    &lt;span class="nd"&gt;http_ok!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&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;why&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;http_error!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;why&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="p"&gt;}&lt;/span&gt;

        &lt;span class="nb"&gt;None&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;http_error!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"missing request payload"&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="nd"&gt;#[derive(Serialize,&lt;/span&gt; &lt;span class="nd"&gt;Deserialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;CreateTodoRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;body&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="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Serialize,&lt;/span&gt; &lt;span class="nd"&gt;Deserialize)]&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;CreateTodoResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;uuid&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Building the Project
&lt;/h1&gt;

&lt;p&gt;Before getting too far, now would be a good time to try building our project to make sure everything is working.&lt;/p&gt;

&lt;p&gt;The CLI command you'll use for this is &lt;code&gt;asml cast&lt;/code&gt;. The &lt;code&gt;cast&lt;/code&gt; command compiles all function source &amp;amp; generates an infrastructure plan with Terraform. All build artifacts are written to the &lt;code&gt;net&lt;/code&gt; directory, which is the frozen (and deployable) representation of your project.&lt;/p&gt;

&lt;p&gt;You may need to scroll the output a little to verify there were no errors -- the Terraform plan will still run even if function compilation fails (we'll fix this soon :)).&lt;/p&gt;

&lt;h1&gt;
  
  
  Adding Additional Functions
&lt;/h1&gt;

&lt;p&gt;I'm going to leave the implementation of the remaning functions as an exercise to the reader. This is already long, plus there's a complete example on &lt;a href="https://github.com/akkoro/assemblylift-examples"&gt;Github&lt;/a&gt; if you'd like the full source.&lt;/p&gt;

&lt;p&gt;You should be aware of the &lt;code&gt;asml make&lt;/code&gt; command while you do this, which will let you generate &amp;amp; add a new service or function to your existing project.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;asml make service &amp;lt;service-name&amp;gt;&lt;/code&gt; will, as you probably guessed, create a new service. This uses the same template as the &lt;code&gt;init&lt;/code&gt; command to generate the stub.&lt;/p&gt;

&lt;p&gt;What about adding a function to &lt;em&gt;this&lt;/em&gt; service, that we already have? You do this by running &lt;code&gt;asml make function &amp;lt;service-name&amp;gt;.&amp;lt;function-name&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, if you want to add a &lt;code&gt;delete&lt;/code&gt; function to our todo service you might run &lt;code&gt;asml make function todo.delete&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For now you will still need to update your &lt;code&gt;.toml&lt;/code&gt; files by hand, but I would like &lt;code&gt;make&lt;/code&gt; to take care of that for you in the future as well in a future update 🙂.&lt;/p&gt;

&lt;h1&gt;
  
  
  Deployment
&lt;/h1&gt;

&lt;p&gt;The last command you're going to need is &lt;code&gt;asml bind&lt;/code&gt;. This command will take an existing &lt;code&gt;net&lt;/code&gt; structure and &lt;code&gt;bind&lt;/code&gt; it to the backend (i.e. AWS Lambda).&lt;/p&gt;

&lt;p&gt;If you aren't getting errors during &lt;code&gt;cast&lt;/code&gt;, there shouldn't be any issues running &lt;code&gt;bind&lt;/code&gt; successfully. If everything goes smoothly (or even if not), you should receive output from the underlying Terraform process.&lt;/p&gt;

&lt;p&gt;If it worked, head over to your AWS console and take a look for your API in API Gateway. You should be able to grab the endpoint URL it generated and start testing!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚧&lt;br&gt;
AssemblyLift doesn't yet provide a built-in means of adding IAM policies to the Roles generated for each Lambda. In the meantime you will have to attach policies manually (such as for DynamoDB access). A unique role has been generated by &lt;code&gt;asml&lt;/code&gt; for each function in your service, and should be easily identified by name in the console.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  &lt;em&gt;fin&lt;/em&gt;
&lt;/h1&gt;

&lt;p&gt;That's all! Please please &lt;em&gt;please&lt;/em&gt; reach out here or on Github if you have any issues! Things can't be fixed if I don't know that they're broken :).&lt;/p&gt;

&lt;p&gt;I'll do my best to keep this guide updated as changes &amp;amp; fixes are introduced. We'll keep a changelog here when the time comes.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>rust</category>
      <category>webassembly</category>
      <category>serverless</category>
      <category>assemblylift</category>
    </item>
    <item>
      <title>AssemblyLift v0.2 preview: RPC-based IO modules</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Tue, 15 Sep 2020 15:15:26 +0000</pubDate>
      <link>https://forem.com/dotxlem/assemblylift-v0-2-preview-rpc-based-io-modules-2d38</link>
      <guid>https://forem.com/dotxlem/assemblylift-v0-2-preview-rpc-based-io-modules-2d38</guid>
      <description>&lt;p&gt;I feel like it's been a looooong minute since I was last able to give an update on &lt;a href="https://assemblylift.akkoro.io" rel="noopener noreferrer"&gt;AssemblyLift&lt;/a&gt;. Real life is busy, summer heat makes me sluggish, and I finally took a vacation!&lt;/p&gt;

&lt;p&gt;Still, in my spare time I've managed to finish core work around the next major revision of AssemblyLift. It took almost exactly twice as long as I had expected &amp;amp; planned, but I think it was worth the extra effort.&lt;/p&gt;

&lt;p&gt;I spent a month thinking I was writing a plugin system, but it turned out to be fairly brittle and gave me trouble with respect to memory safety. So I spent another month re-working it into a solution based on &lt;a href="https://capnproto.org" rel="noopener noreferrer"&gt;Cap'n Proto RPC&lt;/a&gt;, and so far it seems to have paid off!&lt;/p&gt;

&lt;h2&gt;
  
  
  What are we talking about, anyway?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/akkoro/assemblylift" rel="noopener noreferrer"&gt;AssemblyLift&lt;/a&gt; is a framework I've been developing, which provides code &amp;amp; tooling for building serverless cloud applications running on services like AWS Lambda. AssemblyLift apps are written in Rust (more client languages to come!) and are compiled to WebAssembly (WASM).&lt;/p&gt;

&lt;p&gt;Running serverless functions as WebAssembly comes with several benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebAssembly modules are inherently isolated; they run inside their own memory space, and are by default unable to open sockets or access the underlying filesystem.&lt;/li&gt;
&lt;li&gt;They are often faster than their counterparts written in JavaScript or Python, both common language choices for Lambda.&lt;/li&gt;
&lt;li&gt;They can be much lighter in weight, in terms of memory footprint and size of deployment package.&lt;/li&gt;
&lt;li&gt;Several languages compile to WebAssembly, offering developer choice on a common runtime environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On its own, that first point might look like a problem -- we're probably going to need to communicate with the outside world at some point. Luckily, WebAssembly allows the implementer to provide its own system ABI to the module code. AssemblyLift provides its own ABI, which facilitates running our modules in places like AWS Lambda.&lt;/p&gt;

&lt;p&gt;Rather than trying to provide low-level APIs to the module (such as POSIX sockets for example), AssemblyLift provides a standard interface for registering plugin-like modules which the WASM module may access. Tasks which require network or storage access are implemented in these plugin modules, which the WASM module communicates with via the runtime host.&lt;/p&gt;

&lt;p&gt;In the AssemblyLift framework, these plugin modules are referred to as &lt;em&gt;IO modules&lt;/em&gt; (which I often abbreviate to &lt;em&gt;IOmod&lt;/em&gt;). The systems' design &amp;amp; implementation were inspired by &lt;a href="http://learnyouahaskell.com/input-and-output" rel="noopener noreferrer"&gt;Haskell's approach to IO&lt;/a&gt;, hence the name 🙂.&lt;/p&gt;

&lt;p&gt;In the v0.1 series of AssemblyLift, the IOmod portion of things is roughly present however the (currently lone) DynamoDB module is compiled statically into the rest of the host binary (essentially as a proof-of-concept). My goal was to allow IOmods to be distributed as packages, which naturally means that they must be able to be loaded (or not) at run-time on a per-function basis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Neat-O! So how does it all work? What does it look like?
&lt;/h2&gt;

&lt;p&gt;At a high level, it looks a little bit like the following diagram; I did my best to understand &amp;amp; stick to the &lt;a href="https://c4model.com" rel="noopener noreferrer"&gt;C4 model&lt;/a&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%2Fybr72yrwqg298p5dul60.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%2Fybr72yrwqg298p5dul60.png" alt="AssemblyLift Component Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Obviously we're glossing over some implementation details, but the basic idea really is as simple as it looks. To dive a little deeper, let's look at an AssemblyLift example and walk through how a simple network call is made 🙂.&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;extern&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt; &lt;span class="n"&gt;asml_awslambda&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="n"&gt;direct_executor&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;asml_core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GuestCore&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;asml_awslambda&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="n"&gt;AwsLambdaClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LambdaContext&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;asml_iomod_dynamodb&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;structs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list_tables&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nd"&gt;handler!&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="n"&gt;LambdaContext&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="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="nn"&gt;structs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ListTablesInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list_tables&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="k"&gt;.await&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// this is our IOmod call&lt;/span&gt;

    &lt;span class="nn"&gt;AwsLambdaClient&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Got response {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&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 above example uses a DynamoDB IOmod to call &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ListTables.html" rel="noopener noreferrer"&gt;ListTables&lt;/a&gt;. This method is implemented by &lt;code&gt;list_tables&lt;/code&gt;, which takes a single &lt;code&gt;input&lt;/code&gt; argument.&lt;/p&gt;

&lt;p&gt;Every IOmod call has this structure (ie &lt;code&gt;output_struct = call(input_struct)&lt;/code&gt;), and calls are always asynchronous. The &lt;code&gt;list_tables&lt;/code&gt; function comes from an IOmod "guest crate" -- a Rust crate providing the WASM-compatible guest interface to the IO module.&lt;/p&gt;

&lt;p&gt;When calling &lt;code&gt;list_tables&lt;/code&gt;, the guest calls the AssemblyLift ABI to invoke the method on its behalf. The AssemblyLift runtime in turn locates and invokes the method via RPC in the IOmod host process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Packaging &amp;amp; Deployment
&lt;/h3&gt;

&lt;p&gt;In the current implementation, IOmods are defined per-service in an AssemblyLift app. When deployed to AWS Lambda, each service is backed by a Lambda Layer which contains all of the IOmod binaries required by the service's functions. When the AssemblyLift runtime starts, it spawns all binaries that have been layered into the environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  When will it be ready?
&lt;/h2&gt;

&lt;p&gt;I'm aiming for early October, by the time I clean everything up and do more testing. This IOmod stuff also doesn't include everything I had planned for v0.2.x, but I may push everything else out to the next major release. We'll see -- stay tuned! 😊&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update Nov 8 2020&lt;/em&gt;: IOmods are now available in the v0.2.x line of AssemblyLift&lt;/p&gt;

</description>
      <category>rust</category>
      <category>webassembly</category>
      <category>assemblylift</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Why the Rust module system might be hard to understand</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Wed, 22 Jul 2020 19:37:15 +0000</pubDate>
      <link>https://forem.com/dotxlem/why-the-rust-module-system-might-be-hard-to-understand-2l</link>
      <guid>https://forem.com/dotxlem/why-the-rust-module-system-might-be-hard-to-understand-2l</guid>
      <description>&lt;p&gt;The &lt;a href="https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html" rel="noopener noreferrer"&gt;module system&lt;/a&gt; provided by Rust is, by most accounts, kind of weird.&lt;/p&gt;

&lt;p&gt;But so is Rust in many ways, so it kind of makes sense. However it seems like a side-effect is that some concepts, like the module system, are particularly tricky to figure out.&lt;/p&gt;

&lt;p&gt;There was recently &lt;a href="http://www.sheshbabu.com/posts/rust-module-system/" rel="noopener noreferrer"&gt;a blog post&lt;/a&gt; linked on &lt;a href="https://www.reddit.com/r/rust/comments/htzkq7/clear_explanation_of_rusts_module_system/" rel="noopener noreferrer"&gt;/r/rust&lt;/a&gt;, which I think does a really great job of explaining how it works (if you landed here looking for a tutorial, let me send you there instead!).&lt;/p&gt;

&lt;p&gt;The conversation on Reddit got me thinking about &lt;em&gt;why&lt;/em&gt; it's difficult to understand. People seem to have different opinions on it, and I think a lot of that might have to do with how much everyone's previous experience can vary when coming into the Rust ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Effect of Past Experiences
&lt;/h2&gt;

&lt;p&gt;First of all, I'm going to make an assumption: that the vast majority of people coming into Rust right now, are &lt;strong&gt;not&lt;/strong&gt; doing so with it as their first programming language. They most likely already work in another language, given that Rust is still relatively young. Rust is also, I think, rarely recommended as something one should try learning &lt;em&gt;first&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This assumption is important, because that's what my first point is kind of based on.&lt;/p&gt;

&lt;p&gt;No matter what you're learning, you are using your past experiences and accumulated knowledge to help you understand a concept, whether it's something completely novel or a "next step" of something else.&lt;/p&gt;

&lt;p&gt;In the psychological sense, &lt;a href="https://en.wikipedia.org/wiki/Priming_(psychology)" rel="noopener noreferrer"&gt;&lt;em&gt;priming&lt;/em&gt;&lt;/a&gt; is "&lt;em&gt;a phenomenon whereby exposure to one stimulus influences a response to a subsequent stimulus, without conscious guidance or intention&lt;/em&gt;".&lt;/p&gt;

&lt;p&gt;For Rust, I see see at least two potential priming vectors.&lt;/p&gt;

&lt;p&gt;The first, is the word "module" itself. In software development, "module" is a &lt;strong&gt;&lt;em&gt;very&lt;/em&gt;&lt;/strong&gt; overloaded term. That often means that one of the first things you have to do (mentally) when reading the docs, is disambiguate the word we use to describe a seriously central concept of Rust. Asking "what is a module?" is the kind of question &lt;a href="https://softwareengineering.stackexchange.com/questions/167859/what-actually-is-a-module-in-software-engineering" rel="noopener noreferrer"&gt;that gets closed on Stack Overflow&lt;/a&gt; for being impossible to answer definitively.&lt;/p&gt;

&lt;p&gt;This is a kind of example of priming (if you are a native English speaker; more on that in a second), except that you have been primed with what is essentially mush in my opinion. You know we're talking about a collection of code that is separate from the other modules (hopefully), and from there it's just a vague memory of every other kind of module you've ever encountered. Plus any other IRL-kinds of modules you can think of, even if only subconsciously.&lt;/p&gt;

&lt;p&gt;I have no idea what it is like coming across terms like &lt;em&gt;module&lt;/em&gt;, with English as a second language. I expect the effect is the same, since it's unlikely your last framework or language used anything other than the English word to describe the idea. And I'm also assuming priming works the same way for a "symbol" regardless of what language it's written in. Let me know if you can shed more light on this part!&lt;/p&gt;

&lt;p&gt;As for the second vector, the Reddit discussion I linked also indicated that people didn't necessarily expect Rust's module system to be independent of the filesystem. In part, this was based on their &lt;em&gt;previous experience&lt;/em&gt; in other languages. Sound familiar? 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  The Effect of Novel Jargon
&lt;/h2&gt;

&lt;p&gt;In addition to using overly ambiguous language adopted from the aether of software engineering, Rust also makes use of its own novel or invented jargon to express ideas. This isn't a criticism of Rust in isolation -- a lot of (most?) software engineering terms are completely made up.&lt;/p&gt;

&lt;p&gt;The novel jargon I'm talking about here, is the use of the word &lt;em&gt;crate&lt;/em&gt; to describe a Rust package. Or is a crate a module, and the crate in a package? Who knows, unless you can make it through the extra cognitive effort I described earlier to parse the official Rust book. That, or you hope someone writes a well-worded tutorial.&lt;/p&gt;

&lt;p&gt;I'm assuming they're called "crates" as a cutesy name derived from &lt;em&gt;Cargo&lt;/em&gt;'s name, or perhaps it's the reverse. &lt;/p&gt;

&lt;p&gt;In either case, if you speak English you think of a &lt;em&gt;crate&lt;/em&gt; as something that holds stuff in order to &lt;em&gt;ship it&lt;/em&gt; (my internal monologue: "&lt;em&gt;ohhhhh, now I get it!&lt;/em&gt;"). And they are managed with what is de facto known as a &lt;em&gt;package manager&lt;/em&gt;, called Cargo. Ok, so far so good, as long as crate is a word that already means something to you. And identifying Cargo as a package manager was probably easy.&lt;/p&gt;

&lt;p&gt;On packages and crates, the Rust book &lt;a href="https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html" rel="noopener noreferrer"&gt;states&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A crate is a binary or library. The crate root is a source file that the Rust compiler starts from and makes up the root module of your crate (...). A package is one or more crates that provide a set of functionality.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay...&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%2Fsrclf3ktys02wtkewuqg.gif" 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%2Fsrclf3ktys02wtkewuqg.gif" alt="Star Wars guy looking confused"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's look at just the first bit:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A crate is a binary or library. The crate root is a source file&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On my first read (or more, maybe), I don't see the word &lt;em&gt;root&lt;/em&gt; after the second use of &lt;em&gt;crate&lt;/em&gt;. I'm still processing what I was just told a crate &lt;em&gt;is&lt;/em&gt;, and then I take in another "a crate is" sentence. My brain immediately aborts. I've got two things a crate is, and none of them are what I expected -- a crate &lt;em&gt;is a&lt;/em&gt; binary or library? I thought we installed crates with a package manager...making them &lt;em&gt;packages&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;A little further:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;that the Rust compiler starts from and makes up the root module of your crate&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the first place that the word &lt;em&gt;module&lt;/em&gt; is used in this section, and it's got the modifier &lt;em&gt;root&lt;/em&gt;. But I still don't know what an ordinary module is in this context yet, or a what a crate really is for that matter. &lt;/p&gt;

&lt;p&gt;And finally:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A package is one or more crates that provide a set of functionality&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we learn that a package is really multiple crates. That still doesn't fit what we were primed with, and the explanation hasn't made anything clearer. &lt;/p&gt;

&lt;p&gt;I also have to point out how much work the words "&lt;em&gt;a set of functionality&lt;/em&gt;" are doing. Speaking of ambiguity!&lt;/p&gt;

&lt;p&gt;Altogether, there is quite of bit of jargon thrown at you "just" to learn how things are structured. And a lot of that jargon is pretty ambiguous.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution Space
&lt;/h2&gt;

&lt;p&gt;This isn't meant to be a roast of the Rust book authors. Technical writing is &lt;strong&gt;&lt;em&gt;hard&lt;/em&gt;&lt;/strong&gt; (and woefully undervalued as a profession, but that's another post). Overall the Rust book is extremely well written, and it's been useful nearly every day I've worked with Rust.&lt;/p&gt;

&lt;p&gt;My overall point, is that I think a lot more care could be taken about the words and phrases that are selected to describe abstract concepts. Maybe not just inside the Rust community, but industry-wide. It may make communicating with each other easier!&lt;/p&gt;

&lt;p&gt;Rust is difficult, so I think describing it is going to be more difficult in many cases. Unfortunately, I believe this may ultimately be a case of something requiring a bit more effort (than is maybe even possible right now). Either taking more time with documentation before it's released or dedicating more resources to it. Which is obviously tough, being a (mostly?) volunteer-run project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The End
&lt;/h2&gt;

&lt;p&gt;If you're still here, thank you! If you have any corrections, please reach out!&lt;/p&gt;

&lt;h4&gt;
  
  
  Credits
&lt;/h4&gt;

&lt;p&gt;&lt;span&gt;Cover Photo by &lt;a href="https://unsplash.com/@brunnotozzo?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Brunno Tozzo&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/crates?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>modules</category>
      <category>crates</category>
      <category>cargo</category>
    </item>
  </channel>
</rss>
