<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yev</title>
    <description>The latest articles on DEV Community by Yev (@melgenek).</description>
    <link>https://dev.to/melgenek</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%2F2801%2F3802287.jpeg</url>
      <title>DEV Community: Yev</title>
      <link>https://dev.to/melgenek</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/melgenek"/>
    <language>en</language>
    <item>
      <title>Getting a development domain and TLS certificates for free</title>
      <dc:creator>Yev</dc:creator>
      <pubDate>Wed, 28 Jul 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/melgenek/getting-a-development-domain-and-tls-certificates-for-free-4lge</link>
      <guid>https://dev.to/melgenek/getting-a-development-domain-and-tls-certificates-for-free-4lge</guid>
      <description>&lt;p&gt;Recently I have been experimenting with Http/3 protocol which uses TLS by default. Having self-signed TLS certificates makes browsers unhappy about the traffic, that’s why I needed a way to get a trusted certificate. While it took me more time than expected, I decided to write down the taken steps.&lt;/p&gt;


&lt;h4&gt;Table of Contents&lt;/h4&gt;

&lt;ul id="markdown-toc"&gt;
  &lt;li&gt;Getting the domain and certificates&lt;/li&gt;
  &lt;li&gt;What has just happened&lt;/li&gt;
  &lt;li&gt;Summary&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting the domain and certificates
&lt;/h2&gt;

&lt;p&gt;This section walks through the process of getting a domain name and TLS certificates.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;To start with, we need to have access to a DNS provider and a domain. I chose &lt;a href="https://www.duckdns.org/" rel="noopener noreferrer"&gt;DuckDNS&lt;/a&gt; because it is absolutely free and allows creating TXT DNS records, that are used to pass &lt;a href="https://letsencrypt.org/docs/challenge-types/#dns-01-challenge" rel="noopener noreferrer"&gt;the ACME DNS challenge&lt;/a&gt;. At DuckDNS we create our own domain and copy the token that looks like UUIDv4 string. This token is needed to update the DNS records via the DuckDNS api.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next we pass the ACME challenge and get the TLS certificates utilising Let’s Encrypt and CertBot. &lt;a href="https://letsencrypt.org/" rel="noopener noreferrer"&gt;Let’s Encrypt&lt;/a&gt; is the certificate authority that issues certificates that are valid in all the browsers.&lt;a href="https://certbot.eff.org/" rel="noopener noreferrer"&gt;CertBot&lt;/a&gt; is a tool that is usually used to pass ACME challenges on a wide variety of server platforms. Fortunately for us, &lt;a href="https://github.com/maksimstojkovic/docker-letsencrypt" rel="noopener noreferrer"&gt;there is a docker container&lt;/a&gt; dedicated to getting certificates at Let’s Encrypt for DuckDNS domains. The usage is as easy as running this command in the terminal:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it --rm \
-e DUCKDNS_TOKEN="396db3e9-5ecc-4d0c-a708-70a926b1389c" \
-e DUCKDNS_DOMAIN="melgenek.duckdns.org" \
-v `pwd`/melgenek_certs:/etc/letsencrypt \
maksimstojkovic/letsencrypt:latest

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

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;docker run&lt;/code&gt; we specified the token that DuckDNS provides for accessing their API and my domain. As a result of running this command the ACME challenge is succeeds, and the volume attached to the container contains the certificates. The private key and the public certificate can be found in the files &lt;code&gt;./melgenek_certs/live/melgenek.duckdns.org/privkey.pem&lt;/code&gt; and &lt;code&gt;./melgenek_certs/live/melgenek.duckdns.org/cert.pem&lt;/code&gt; respectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  What has just happened
&lt;/h2&gt;

&lt;p&gt;The docker container that we used in the previous section did the needed magic to validate the DNS record and get the certificates. In order to get the understanding of what the ACME flow looks like, let’s generate one more certificate using the plain CertBot. After passing the challenge, Let’s Encrypt is sure that the domain is ours and gives us a certificate.&lt;/p&gt;

&lt;p&gt;The first step is to start the CertBot flow. The CertBot is installed as &lt;a href="https://certbot.eff.org/docs/install.html" rel="noopener noreferrer"&gt;a standalone binary&lt;/a&gt; and can be run from terminal. The command specifies for which domain we want to pass the DNS challenge and where to store the certificates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;certbot certonly --manual \
   --preferred-challenges dns \
   --register-unsafely-without-email \
   -d "melgenek.duckdns.org" \
   --work-dir "./melgenek_certs/work_dir" \
   --logs-dir "./melgenek_certs/logs_dir" \
   --config-dir "./melgenek_certs/config_dir" \
   --agree-tos

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

&lt;/div&gt;



&lt;p&gt;As a result of the running the command CertBot generates a secret value and asks us to put it into the DNS record.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Please deploy a DNS TXT record under the name
_acme-challenge.melgenek.duckdns.org with the following value:

NaM0ODwHZfL6b1pjM_rrgfCSwVcy_CALKkxR2YzyE7A

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

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

&lt;/div&gt;



&lt;p&gt;CertBot proposes to set the TXT record at the &lt;code&gt;_acme-challenge.melgenek.duckdns.org&lt;/code&gt; subdomain. The validation of such a record would result in issuing a wildcard certificate for &lt;code&gt;*.melgenek.duckdns.org&lt;/code&gt;. We are setting the TXT record for the domain itself so that the certificate is valid only for the &lt;code&gt;melgenek.duckdns.org&lt;/code&gt; domain. The next cUrl call creates the TXT record in DuckDns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl "https://www.duckdns.org/update?domains=melgenek.duckdns.org&amp;amp;token=396db3e9-5ecc-4d0c-a708-70a926b1389c&amp;amp;txt=NaM0ODwHZfL6b1pjM_rrgfCSwVcy_CALKkxR2YzyE7A"

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

&lt;/div&gt;



&lt;p&gt;Before proceeding with the ACME challenge, we can check that the DNS record is actually set using &lt;code&gt;dig&lt;/code&gt;. In the lookup result we see that the TXT record is exactly what we expect it to be.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dig melgenek.duckdns.org TXT

;; ANSWER SECTION:
melgenek.duckdns.org. 59 IN TXT "NaM0ODwHZfL6b1pjM_rrgfCSwVcy_CALKkxR2YzyE7A"

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

&lt;/div&gt;



&lt;p&gt;Clicking “Enter” in the terminal where CertBot is waiting for input would trigger Let’s Encrypt validation of the TXT record. Passing this validation successfully produces certificates the specified folder &lt;code&gt;./melgenek_certs/config_dir/live/melgenek.duckdns.org&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The challenge secret is a not reused in the future, so it makes sense to clean up the TXT record. This is done by adding the &lt;code&gt;clear=true&lt;/code&gt; query param to the previous cUrl query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl "https://www.duckdns.org/update?domains=melgenek.duckdns.org&amp;amp;token=396db3e9-5ecc-4d0c-a708-70a926b1389c&amp;amp;txt=NaM0ODwHZfL6b1pjM_rrgfCSwVcy_CALKkxR2YzyE7A&amp;amp;clear=true"

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this article we described a simple way of getting perfectly valid TLS certificates as wells as a domain that can be used for development purposes. Hopefully, this information helps build exciting software and learn new technologies.&lt;/p&gt;

</description>
      <category>tls</category>
      <category>ssl</category>
      <category>certificate</category>
      <category>domain</category>
    </item>
    <item>
      <title>Enhancing DynamoDb client with Scala 3</title>
      <dc:creator>Yev</dc:creator>
      <pubDate>Thu, 31 Dec 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/melgenek/enhancing-dynamodb-client-with-scala-3-1e9h</link>
      <guid>https://dev.to/melgenek/enhancing-dynamodb-client-with-scala-3-1e9h</guid>
      <description>&lt;p&gt;After 8 years of development, Dotty is going to become Scala 3 soon. It’s the right time to try out Scala 3 and its new features. In this article, I am going to show a practical example of making DynamoDb more type-safe and convenient using &lt;a href="https://dotty.epfl.ch/docs/reference/metaprogramming/macros.html" rel="noopener noreferrer"&gt;macros&lt;/a&gt;,&lt;a href="https://dotty.epfl.ch/docs/reference/contextual/derivation.html" rel="noopener noreferrer"&gt;type class derivations&lt;/a&gt;, &lt;a href="https://dotty.epfl.ch/docs/reference/contextual/extension-methods.html" rel="noopener noreferrer"&gt;extensions methods&lt;/a&gt;, and a handful of implicits.&lt;/p&gt;


&lt;h4&gt;Table of Contents&lt;/h4&gt;

&lt;ul id="markdown-toc"&gt;
  &lt;li&gt;Introduction&lt;/li&gt;
  &lt;li&gt;Encoding attributes. Implicits&lt;/li&gt;
  &lt;li&gt;Obtaining class field names. Macros&lt;/li&gt;
  &lt;li&gt;Avoiding the map construction. Type class derivation&lt;/li&gt;
  &lt;li&gt;Convenience operators. Extension methods&lt;/li&gt;
  &lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;To start with, let’s look at how to put and get an item from DynamoDb utilizing the plain aws-sdk client. The examples assume that there is a case class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;case class NewYear(year: Int, wish: String) {
  def gift: String = "A fairy pony"
}

val year = NewYear(2020, "I wish Scala 3 was released soon")

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

&lt;/div&gt;



&lt;p&gt;The case class is defined in the file &lt;code&gt;NewYear.scala&lt;/code&gt;. The instance of the case class &lt;code&gt;val year=...&lt;/code&gt; as well as the case class itself are &lt;a href="https://dotty.epfl.ch/docs/reference/dropped-features/package-objects.html" rel="noopener noreferrer"&gt;at the top-level&lt;/a&gt; as well. This is the first notable feature of Scala 3: the package objects were removed from the language. The values and methods don’t need to be defined inside an object or class anymore.&lt;/p&gt;

&lt;p&gt;The instances of &lt;code&gt;NewYear&lt;/code&gt; are going to be stored in the dynamo table &lt;code&gt;new-years&lt;/code&gt;. I am omitting the code of creating the dynamo table, the whole example can be found in the &lt;a href="https://github.com/melgenek/dotty-dynamodb" rel="noopener noreferrer"&gt;github repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we know the entities that are going to be stored in the database. We can take a look at the put/get code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ddb.putItem(
  PutItemRequest.builder()
    .tableName(TableName)
    .item(Map(
      "year" -&amp;gt; AttributeValue.builder().n(year.year.toString).build(),
      "wish" -&amp;gt; AttributeValue.builder().s(year.wish).build()
    ).asJava)
    .build()
)

val item = ddb.getItem(
  GetItemRequest.builder()
    .tableName(TableName)
    .key(Map(
      "year" -&amp;gt; AttributeValue.builder().n("2020").build()
    ).asJava)
    .build()
)

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

&lt;/div&gt;



&lt;p&gt;What problems can we see here?&lt;/p&gt;

&lt;p&gt;Firstly, the &lt;code&gt;AttributeValues&lt;/code&gt; are being built explicitly, the &lt;code&gt;year&lt;/code&gt; of type &lt;code&gt;Int&lt;/code&gt; is transformed into a &lt;code&gt;String&lt;/code&gt; in order to be set as the value of the attribute. Not only we can make a mistake of choosing the DynamoDb type by confusing the &lt;code&gt;.n&lt;/code&gt; and &lt;code&gt;.s&lt;/code&gt; value setters on the builder, but also the code looks ugly and verbose. It’s a great use case for type classes to provide a unified way of converting scala types to the &lt;code&gt;AttributeValue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Secondly, the attribute names are passed as strings. The key of our table is &lt;code&gt;year&lt;/code&gt;. A typo in the key of the get request can lead to no results being returned. You can argue that having constants for the attribute names is enough. However, keeping the same name of the key in the item map and the case class field is going to be crucial to write cases classes in the &lt;code&gt;.item&lt;/code&gt; without an explicit construction of the map.&lt;/p&gt;

&lt;p&gt;Here comes the last issue that we’ll try solving in this article. The &lt;code&gt;.item&lt;/code&gt; ignores the instance of the class that we defined and expects a map. This case class has only 2 fields, so building a map is quite an easy task. Having 20 fields will definitely be error-prone because an additional field in the case class requires an additional line inside the &lt;code&gt;.item&lt;/code&gt; map.&lt;/p&gt;

&lt;p&gt;After making some improvements employing the features of Scala 3, we can get a neat code like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ddb.putItem(
  PutItemRequest.builder()
    .tableName(TableName)
    .item(year)
    .build()
)

val item = ddb.getItem(
  GetItemRequest.builder()
    .tableName(TableName)
    .key[NewYear](_.year, 2021)
    .build()
)

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

&lt;/div&gt;



&lt;p&gt;In the following sections, I’ll explain how to create the utilities for the code above to work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encoding attributes. Implicits
&lt;/h2&gt;

&lt;p&gt;I’m going to introduce the improvements step by step. To start with, we’ll make the attribute building more pleasant. In order to do this, we’ll have &lt;a href="https://dotty.epfl.ch/docs/reference/contextual/type-classes.html" rel="noopener noreferrer"&gt;a type class&lt;/a&gt; for the conversion of a scala type to the &lt;code&gt;AttributeValue&lt;/code&gt; and back. Every type that can be converted to the &lt;code&gt;AttributeValue&lt;/code&gt; will have an implementation of the &lt;code&gt;AttributeCodec&lt;/code&gt; trait:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trait AttributeCodec[A] {
  def encode(a: A): AttributeValue
  def decode(a: AttributeValue): A
}

given AttributeCodec[String] with {
  def encode(a: String): AttributeValue = AttributeValue.builder().s(a).build()
  def decode(a: AttributeValue): String = a.s()
}

implicit val intCodec: AttributeCodec[Int] = new AttributeCodec[Int] {
  def encode(a: Int): AttributeValue = AttributeValue.builder().n(a.toString).build()
  def decode(a: AttributeValue): Int = a.n().toInt
}

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

&lt;/div&gt;



&lt;p&gt;You can see that I defined two instances:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the instance for the &lt;code&gt;String&lt;/code&gt; type is defined with Scala 3 syntax&lt;/li&gt;
&lt;li&gt;the instance for the &lt;code&gt;Int&lt;/code&gt; uses the old Scala 2 syntax&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Scala 3 syntax is slightly nicer, the instance names can be omitted. They are never used after all, because the instances are found in the implicit scope via summoning. In the new Scala, the method &lt;code&gt;implicitly&lt;/code&gt;is renamed to be &lt;code&gt;summon&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;summon[AttributeCodec[Int]].encode(2021) // AttributeValue.builder().n(2021.toString).build()

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

&lt;/div&gt;



&lt;p&gt;We can make the encoding look even better by adding a so-called “summoner” method to the &lt;code&gt;AttributeCodec&lt;/code&gt;. There is a new keyword &lt;code&gt;using&lt;/code&gt; that marks the implicit function parameters. It replaces the old &lt;code&gt;implicit&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;object AttributeCodec {
  def apply[A](using codec: AttributeCodec[A]): AttributeCodec[A] = codec

  // The old syntax
  // def apply[A](implicit codec: AttributeCodec[A]): AttributeCodec[A] = codec
}

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

&lt;/div&gt;



&lt;p&gt;After this first round of enhancements our application is in the following state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ddb.putItem(
  PutItemRequest.builder()
    .tableName(TableName)
    .item(Map(
      "year" -&amp;gt; AttributeCodec[Int].encode(year.year),
      "wish" -&amp;gt; AttributeCodec[String].encode(year.wish)
    ).asJava)
    .build()
)

val item = ddb.getItem(
  GetItemRequest.builder()
    .tableName(TableName)
    .key(Map(
      "year" -&amp;gt; AttributeCodec[Int].encode(2021)
    ).asJava)
    .build()
)

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Obtaining class field names. Macros
&lt;/h2&gt;

&lt;p&gt;Our next step is the derivation of the attribute names based on the case class field names. When we complete implementing this macro, the code will use fields instead of strings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ddb.putItem(
  PutItemRequest.builder()
    .tableName(TableName)
    .item(Map(
      FieldName[NewYear](_.year) -&amp;gt; AttributeCodec[Int].encode(year.year),
      FieldName[NewYear](_.wish) -&amp;gt; AttributeCodec[String].encode(year.wish)
    ).asJava)
    .build()
)

val item = ddb.getItem(
  GetItemRequest.builder()
    .tableName(TableName)
    .key(Map(
      FieldName[NewYear](_.year) -&amp;gt; AttributeCodec[Int].encode(2021)
    ).asJava)
    .build()
)

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

&lt;/div&gt;



&lt;p&gt;As you can see the attribute name is defined via the accessor of the field &lt;code&gt;FieldName[NewYear](_.year)&lt;/code&gt;. The automatic acquisition of the field name is performed with a &lt;a href="https://dotty.epfl.ch/docs/reference/metaprogramming/macros.html" rel="noopener noreferrer"&gt;macro&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inline def apply[T](inline f: T =&amp;gt; Any): String = ${getName('f)}

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

&lt;/div&gt;



&lt;p&gt;This is an &lt;code&gt;apply&lt;/code&gt; method that is defined with the modifier &lt;a href="https://dotty.epfl.ch/docs/reference/metaprogramming/inline.html" rel="noopener noreferrer"&gt;inline&lt;/a&gt; and calls the macro implementation &lt;code&gt;getName&lt;/code&gt;. The methods that are implemented via macros are always required to be defined with the &lt;code&gt;inline&lt;/code&gt; modifier. The second &lt;code&gt;inline&lt;/code&gt; modifier on the parameter is optional. Let’s look at a simple example to understand why it’s needed in this situation. The following code prints the parameter that is passed to the method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import scala.quoted._
object InlineFunctions {
  inline def showExpr(expr: Any): String = ${showExprImpl('expr)}

  inline def showExprInlined(inline expr: Any): String = ${showExprImpl('expr)}

  private def showExprImpl(expr: Expr[Any])(using Quotes): Expr[String] =
    '{ ${Expr(expr.show)} + " = " + $expr }
}

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

&lt;/div&gt;



&lt;p&gt;The implementation of the macro is defined in the method &lt;code&gt;showExprImpl&lt;/code&gt;. The first parameter has the type &lt;code&gt;Expr&lt;/code&gt;. This type represents the abstract syntax tree for all the constructs that compose our code. For example, it’s subtype &lt;code&gt;Literal&lt;/code&gt; represents a single value, and the subtype &lt;code&gt;Block&lt;/code&gt; contains multiple statements. The &lt;code&gt;${expr}&lt;/code&gt; is the same as &lt;code&gt;$expr&lt;/code&gt;. It’s called “splicing” and calculates the value of an expression. For example, the &lt;code&gt;${Expr("hello")}&lt;/code&gt; is just the string &lt;code&gt;hello&lt;/code&gt;. The transformation can be reversed with the use of quotes &lt;code&gt;'{expr}&lt;/code&gt; which is the same as &lt;code&gt;'expr&lt;/code&gt;. Thus &lt;code&gt;'{"hello"}&lt;/code&gt; is equal to &lt;code&gt;Expr("hello")&lt;/code&gt;. In essence the &lt;code&gt;showExprImpl&lt;/code&gt; prints the string representation of the expression and its value using the splices and quotes. The &lt;code&gt;Quotes&lt;/code&gt; context parameter contains some low-level operations and is used implicitly by these operations. I defined 2 different functions: one with the &lt;code&gt;inline&lt;/code&gt; parameter and another one without it. Let’s call them and see the output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import InlineFunctions._

object InlineMain extends App {
  val a = 1
  val b = 2

  println(showExprInlined(a + b)) // demo.inline.InlineMain.a.+(demo.inline.InlineMain.b) = 3
  println(showExpr(a + b)) // expr$proxy2 = 3
}

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

&lt;/div&gt;



&lt;p&gt;The value of the sum operation is the same. The expressions that are passed to our macro are different though. The &lt;code&gt;inline&lt;/code&gt; modifier preserves the original expression. That’s exactly what we need in order to get the field name from the function such as &lt;code&gt;(w:NewYear) =&amp;gt; w.year&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After we had a quick look at the &lt;code&gt;inline&lt;/code&gt; modifier, splices, and quotes, it’s time to move on and implement the &lt;code&gt;getName&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private def getName[T](f: Expr[T =&amp;gt; Any])(using Type[T], Quotes): Expr[String] = {
  import quotes.reflect._
  val acc = new TreeAccumulator[String] {
    def foldTree(names: String, tree: Tree)(owner: Symbol): String = tree match {
      case Select(_, name) =&amp;gt; name
      case _ =&amp;gt; foldOverTree(names, tree)(owner)
    }
  }
  val fieldName = acc.foldTree(null, f.asTerm)(Symbol.spliceOwner)
  Expr(fieldName)
}

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

&lt;/div&gt;



&lt;p&gt;In the implementation, we dived even deeper into the Scala magic by calling &lt;code&gt;f.asTerm&lt;/code&gt; so as to get access to the AST that the compiler sees. This is so-called &lt;a href="https://dotty.epfl.ch/docs/reference/metaprogramming/tasty-reflect.html" rel="noopener noreferrer"&gt;TASTy Reflect&lt;/a&gt;. It provides an even more comprehensive view of the structure of the code. The power comes with a cost. Using TASTy Reflect can break type correctness guarantees and may fail at macro expansion time. In this particular use case, we are safe because we are only interested in reading the syntax tree, not in its modification. The &lt;code&gt;.asTerm&lt;/code&gt; call produces the &lt;code&gt;Tree&lt;/code&gt; instance. Similarly to &lt;code&gt;Expr&lt;/code&gt;, the &lt;code&gt;Tree&lt;/code&gt; has multiple subclasses that together represent our code. For instance, the call &lt;code&gt;FieldName[NewYear](_.year)&lt;/code&gt; is expanded to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inlined(EmptyTree,List(),Block(List(DefDef($anonfun,List(),List(List(ValDef(_$1,TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class demo)),class NewYear)],EmptyTree))),TypeTree[TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class &amp;lt;root&amp;gt;)),module scala),Any)],Select(Ident(_$1),year))),Closure(List(),Ident($anonfun),EmptyTree)))

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

&lt;/div&gt;



&lt;p&gt;This AST has quite many nesting levels. That’s why we use the &lt;code&gt;TreeAccumulator&lt;/code&gt; that traverses this tree for us. When the traversal reaches the desired &lt;code&gt;Select&lt;/code&gt; instance, it returns the name of the field.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;NewYear&lt;/code&gt; has a method defined outside the constructor and in the current implementation the call &lt;code&gt;FieldName[NewYear](_.gift)&lt;/code&gt; is perfectly valid. It returns the string &lt;code&gt;gift&lt;/code&gt; even though the field is not defined in the primary constructor. In order to prevent any fields and methods to be passed into the &lt;code&gt;getName&lt;/code&gt; method, we define a compile-time validation that issues a compilation error when the field is not a part of the primary constructor. Here is the final implementation of the macro including the validation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import scala.quoted.Expr.{ofTuple, summon}
import scala.quoted._

object FieldName {
  inline def apply[T](inline f: T =&amp;gt; Any): String = ${getName('f)}

  private def getName[T](f: Expr[T =&amp;gt; Any])(using Type[T], Quotes): Expr[String] = {
    import quotes.reflect._
    val acc = new TreeAccumulator[String] {
      def foldTree(names: String, tree: Tree)(owner: Symbol): String = tree match {
        case Select(_, name) =&amp;gt; name
        case _ =&amp;gt; foldOverTree(names, tree)(owner)
      }
    }
    val fieldName = acc.foldTree(null, f.asTerm)(Symbol.spliceOwner)
    val primaryConstructorFields = TypeTree.of[T].symbol.caseFields.map(_.name)
    if(!primaryConstructorFields.contains(fieldName))
      report.error(s"The field '$fieldName' is not one of the primary constructor parameter.", f)
    Expr(fieldName)
  }
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Avoiding map construction. Type class derivation
&lt;/h2&gt;

&lt;p&gt;Earlier in this article, I mentioned that it is crucial to know how to derive the field name and omit to have the attribute names as strings. The reason is that we will be generating the map based on the case class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trait ItemCodec[T] {
  def encode(t: T): Map[String, AttributeValue]
}

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

&lt;/div&gt;



&lt;p&gt;There will be an instance of the &lt;code&gt;ItemCodec&lt;/code&gt; trait created for any case class. Unlike &lt;code&gt;AttributeCodec&lt;/code&gt;, which had the explicitly defined instances, the type &lt;code&gt;ItemCodec&lt;/code&gt; instances are derived automatically. In Scala 2 you would use libraries like Magnolia in order to construct the macros and generate these instances. Scala 3 introduces some convenience utilities in the language itself. One of them is the trait &lt;code&gt;Mirror&lt;/code&gt;. The language provides an instance of &lt;code&gt;Mirror.Product&lt;/code&gt; for every case class. For our &lt;code&gt;NewYear&lt;/code&gt; the implementation of this trait looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class NewYearMirror extends Mirror {
  type MirroredMonoType = NewYear
  type MirroredLabel = "NewYear"
  type MirroredElemLabels = ("year", "wish")
  type MirroredElemTypes = (Int, String)
}

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

&lt;/div&gt;



&lt;p&gt;What we need to do is go field by field, and encode every field into the format that the DynamoDb client understands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for every field get the &lt;code&gt;AttributeCodec&lt;/code&gt;. For example, for the field &lt;code&gt;year&lt;/code&gt; we need to summon an instance &lt;code&gt;AttributeCodec[Int]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;set the encoded value in the map with the key &lt;code&gt;year&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;NewYearMirror&lt;/code&gt; provides enough information to write such a type class derivation, because we have both field names and field types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private inline def getAttributeNamesAndCodecs[N &amp;lt;: Tuple, T &amp;lt;: Tuple]: List[(String, AttributeCodec[Any])] =
  inline (erasedValue[N], erasedValue[T]) match {
    case (_: EmptyTuple, _: EmptyTuple) =&amp;gt; Nil
    case (_: (nameHead *: nameTail), _: (typeHead *: typeTail)) =&amp;gt;
      val attributeLabel = constValue[nameHead].toString
      val attributeCodec = summonInline[AttributeCodec[typeHead]].asInstanceOf[AttributeCodec[Any]]
      (attributeLabel, attributeCodec) :: getAttributeNamesAndCodecs[nameTail, typeTail]
  }

inline given derived[T &amp;lt;: Product](using m: Mirror.ProductOf[T]): ItemCodec[T] = {
  val namesAndCodecs = getAttributeNamesAndCodecs[m.MirroredElemLabels, m.MirroredElemTypes]
  new ItemCodec[T] {
    override def encode(t: T): Map[String, AttributeValue] = {
      namesAndCodecs.zip(t.productIterator)
        .map { case ((name, codec), value) =&amp;gt;
          name -&amp;gt; codec.encode(value)
        }
        .toMap
    }
  }
}

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

&lt;/div&gt;



&lt;p&gt;The most interesting parts of these two methods are how to go over fields one by one, and how to transform the field type to be a value.&lt;/p&gt;

&lt;p&gt;Let’s understand the traversal first. We have a type &lt;code&gt;type MirroredElemLabels = ("year", "wish")&lt;/code&gt; which is a tuple. In Scala 3 there is an extractor for the tuple type &lt;code&gt;*:&lt;/code&gt;. It works the same way as for sequences so that there are a head and a tail element. In order to pattern match the tuple, we need to have its value. The &lt;a href="https://dotty.epfl.ch/docs/reference/metaprogramming/inline.html#erasedvalue" rel="noopener noreferrer"&gt;erasedValue&lt;/a&gt; pretends to give us the value. In fact, it would always raise a NotImplementedError exception when called. That’s why we only pattern match the types and don’t use the values of &lt;code&gt;erasedValue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The second puzzle is how it’s possible to have the type of &lt;code&gt;"year"&lt;/code&gt; instead of a type &lt;code&gt;String&lt;/code&gt;, and how to transform the type &lt;code&gt;"year"&lt;/code&gt; to the value &lt;code&gt;year&lt;/code&gt;. In Scala 3 there are singleton types that’s why the type &lt;code&gt;"year"&lt;/code&gt; is valid. These types have only one instance, in this case, &lt;code&gt;year&lt;/code&gt;. In order to acquire this value we call the function &lt;code&gt;constValue&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Convenience operators. Extension methods
&lt;/h2&gt;

&lt;p&gt;All the planned functional improvements have been implemented. We can only add some operators to the &lt;code&gt;GetItemRequest&lt;/code&gt; and &lt;code&gt;PutItemRequest&lt;/code&gt; as if they were natively scala. Scala 2 approach is to define the implicit classes that wrap the objects and expose additional methods on them. Scala 3 has a dedicated keyword for adding such operators. It’s called &lt;a href="https://dotty.epfl.ch/docs/reference/contextual/extension-methods.html" rel="noopener noreferrer"&gt;extension methods&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extension[T] (b: GetItemRequest.Builder) {
  inline def key: GetItemRequestBuilderExtension[T] =
    new GetItemRequestBuilderExtension[T](b)
}

class GetItemRequestBuilderExtension[T](b: GetItemRequest.Builder) {
  inline def apply[A: AttributeCodec](inline k: T =&amp;gt; A, v: A): GetItemRequest.Builder =
    b.key(Map(
      FieldName[T](k) -&amp;gt; AttributeCodec[A].encode(v)
    ).asJava)
}

extension[T: ItemCodec] (b: PutItemRequest.Builder) {
  def item(t: T): PutItemRequest.Builder =
    b.item(ItemCodec[T].encode(t).asJava)
}

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

&lt;/div&gt;



&lt;p&gt;Here is the resulting code that uses this syntactic sugar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ddb.putItem(
  PutItemRequest.builder()
    .tableName(TableName)
    .item(year)
    .build()
)

val item = ddb.getItem(
  GetItemRequest.builder()
    .tableName(TableName)
    .key[NewYear](_.year, 2021)
    .build()
)

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

&lt;/div&gt;



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

&lt;p&gt;In this article, we got acquainted with some Scala 3 features based on a real world example of using the DynamoDb client. We also had a gentle introduction to the macros and type class derivations. If you need more information around this topic, then take a look at &lt;a href="https://blog.philipp-martini.de/blog/magic-mirror-scala3/" rel="noopener noreferrer"&gt;this arctile&lt;/a&gt; and &lt;a href="https://lampepfl.github.io/scala3-macro-tutorial/" rel="noopener noreferrer"&gt;the macro tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The result of the exercise that is described in this article is in &lt;a href="https://github.com/melgenek/dotty-dynamodb" rel="noopener noreferrer"&gt;github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>scala</category>
      <category>macros</category>
      <category>typeclass</category>
      <category>dynamodb</category>
    </item>
    <item>
      <title>Serverless Tapir</title>
      <dc:creator>Yev</dc:creator>
      <pubDate>Wed, 29 Jul 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/melgenek/serverless-tapir-377o</link>
      <guid>https://dev.to/melgenek/serverless-tapir-377o</guid>
      <description>&lt;p&gt;This blog post could start with a drawing of a tapir that has a pair of tiny angel wings and sits on a cloud. Unfortunately, I cannot draw. But I can code. So in this article will tell how to run a Tapir program with AWS Lambda and API Gateway.&lt;/p&gt;


&lt;h4&gt;Table of Contents&lt;/h4&gt;

&lt;ul id="markdown-toc"&gt;
  &lt;li&gt;Introduction&lt;/li&gt;
  &lt;li&gt;Implementing the interpreter&lt;/li&gt;
  &lt;li&gt;Packaging the Lambda&lt;/li&gt;
  &lt;li&gt;Deployment&lt;/li&gt;
  &lt;li&gt;Summary&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://tapir.softwaremill.com/en/latest/index.html" rel="noopener noreferrer"&gt;Tapir&lt;/a&gt; is an amazing scala framework that allows defining http endpoints as scala values. Let’s look at the example that I borrowed from the official documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import sttp.tapir._
import sttp.tapir.json.circe._
import io.circe.generic.auto._

type Limit = Int
type AuthToken = String
case class BooksFromYear(genre: String, year: Int)
case class Book(title: String)

val booksListing: Endpoint[(BooksFromYear, Limit, AuthToken), String, List[Book], Nothing] = 
  endpoint
    .get
    .in(("books" / path[String]("genre") / path[Int]("year")).mapTo(BooksFromYear))
    .in(query[Limit]("limit").description("Maximum number of books to retrieve"))
    .in(header[AuthToken]("X-Auth-Token"))
    .errorOut(stringBody)
    .out(jsonBody[List[Book]])

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

&lt;/div&gt;



&lt;p&gt;This is a representation of a single endpoint with a noticeable feature that it does not have any logic attached. The endpoint is solely a description of input parameters and outputs like response bodies.&lt;/p&gt;

&lt;p&gt;In order to make this definition runnable, we have to use an interpreter. Here is an example implementation in akka-http:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import sttp.tapir.server.akkahttp._
import akka.http.scaladsl.server.Route
import scala.concurrent.Future

val booksListingRoute: Route =
    booksListing.toRoute { case (bfy: BooksFromYear, limit: Limit, at: AuthToken) =&amp;gt;
      Future.successful(Right(List(Book("The Sorrows of Young Werther"))))
    }

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

&lt;/div&gt;



&lt;p&gt;The logic of the route is generic, there is no explicit use of the akka-http response codes or marshallers.There are in fact many options of server interpreters such as play, http4s, finatra and vert.x.However, these frameworks help only with writing the code. The next steps are most likely the docker packaging,the definition of the kubernetes manifests and deployment scripts.&lt;/p&gt;

&lt;p&gt;Deploying an application takes a signification amount of effort. I want to have the code up and running quickly and easily, preferably with a single bash command. Tapir, AWS Lambda and &lt;a href="https://github.com/aws/aws-cdk" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt; will help me with this venture. The complete code can be found in &lt;a href="https://github.com/melgenek/serverless-tapir" rel="noopener noreferrer"&gt;the github repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing the interpreter
&lt;/h2&gt;

&lt;p&gt;We start with an interpreter that transform Tapir code in an AWS Lambda. We will follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;define the logic to transform a Tapir request into the Lambda-specific request.&lt;/li&gt;
&lt;li&gt;then Tapir parses this request and gives me the inputs like query and path params, an input body and headers.&lt;/li&gt;
&lt;li&gt;the next step is to execute the user-defined logic using these inputs as arguments.&lt;/li&gt;
&lt;li&gt;finally, the response from the user-defined logic is transformed back into the response that Lambda understands.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AWs Lambda itself does not know anything about http. It is just an execution environment. We utilize the API Gateway &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html" rel="noopener noreferrer"&gt;Http API&lt;/a&gt;. It parses the request and invokes our lambda as soon as the request is ready to be processed. Http API passes the parsed request &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html" rel="noopener noreferrer"&gt;in a predefined format&lt;/a&gt;. I use the &lt;code&gt;"com.amazonaws" % "aws-lambda-java-events"&lt;/code&gt; to have the predefined java classes &lt;code&gt;APIGatewayV2HTTPEvent&lt;/code&gt; and &lt;code&gt;APIGatewayV2HTTPResponse&lt;/code&gt;that correspond to the Http API request and response models.&lt;/p&gt;

&lt;p&gt;As mentioned above the implementation starts mapping the &lt;code&gt;APIGatewayV2HTTPEvent&lt;/code&gt; into Tapir’s &lt;code&gt;ServerRequest&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class HttpApiServerRequest(event: APIGatewayV2HTTPEvent) extends ServerRequest {
  def method: Method = Method(event.getRequestContext.getHttp.getMethod.toUpperCase)

  def protocol: String = event.getRequestContext.getHttp.getProtocol

  def uri: URI =
    new URI(s"https://${event.getRequestContext.getDomainName}${event.getRawPath}?${event.getRawQueryString}")

  def connectionInfo: ConnectionInfo = ConnectionInfo(
    local = None,
    remote = Some(InetSocketAddress.createUnresolved(event.getRequestContext.getHttp.getSourceIp, 0)),
    secure = Some(true)
  )

  lazy val headers: Seq[(String, String)] = event.getHeaders.asScala.toList

  def header(name: String): Option[String] = event.getHeaders.getIgnoreCase(name)
}

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

&lt;/div&gt;



&lt;p&gt;A couple of moments are worth clarification here.&lt;/p&gt;

&lt;p&gt;First of all, Http API passes all the headers with lowercased names, so the header lookup is done ignoring the case.&lt;/p&gt;

&lt;p&gt;Secondly, in the &lt;code&gt;ConnectionInfo&lt;/code&gt; we have only the remote client, there is no port given to the lambda. The communication to Http API is always secure.&lt;/p&gt;

&lt;p&gt;The next step after defining the server request is the &lt;code&gt;DecodeInputsContext&lt;/code&gt;. As the name suggests, this class is used by Tapir during the inputs extraction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class HttpApiDecodeInputsContext(event: APIGatewayV2HTTPEvent, pathConsumed: Int = 0) extends DecodeInputsContext {
  def method: Method = Method(event.getRequestContext.getHttp.getMethod.toUpperCase)

  def nextPathSegment: (Option[String], DecodeInputsContext) = {
    val path = event.getRawPath.drop(pathConsumed)
    val nextStart = path.dropWhile(_ == '/')
    val segment = nextStart.split("/", 2) match {
      case Array("") =&amp;gt; None
      case Array(s) =&amp;gt; Some(s)
      case Array(s, _) =&amp;gt; Some(s)
    }
    val charactersConsumed = segment.map(_.length).getOrElse(0) + (path.length - nextStart.length)

    (segment, new HttpApiDecodeInputsContext(event, pathConsumed + charactersConsumed))
  }

  def header(name: String): List[String] = 
    event.getHeaders.getIgnoreCase(name).flatMap(_.split(",").toList).toList

  def headers: Seq[(String, String)] = event.getHeaders.asScala.toList

  def queryParameter(name: String): Seq[String] =
    event.getQueryStringParameters.getIgnoreCase(name).flatMap(_.split(",").toList).toList

  def queryParameters: QueryParams = QueryParams.fromMap(event.getQueryStringParameters.asScala.toMap)

  def bodyStream: Any =
    throw new UnsupportedOperationException("Trying to read streaming body from a non-streaming request")

  def serverRequest: ServerRequest = new HttpApiServerRequest(event)
}

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

&lt;/div&gt;



&lt;p&gt;Multivalued headers and query params are combined with commas in Http API. So we split them back into a &lt;code&gt;List&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The body is always passed into the lambda as a string so the whole incoming request is consumed before the lambda invocation. That’s why the body cannot be streamed, and the &lt;code&gt;bodyStream&lt;/code&gt; has no implementation.&lt;/p&gt;

&lt;p&gt;Now that we know how to map the lambda input into the input that Tapir understands, let’s implement the routes. The same way akka http has &lt;code&gt;akka.http.scaladsl.server.Route&lt;/code&gt;, or http4s has &lt;code&gt;org.http4s.HttpRoutes&lt;/code&gt;, we will also have a &lt;code&gt;Route&lt;/code&gt; type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Route = PartialFunction[APIGatewayV2HTTPEvent, APIGatewayV2HTTPResponse]

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

&lt;/div&gt;



&lt;p&gt;Tapir also requires a &lt;code&gt;MonadError&lt;/code&gt; implementation. For akka http there is an instance of a &lt;code&gt;MonadError&lt;/code&gt; based on &lt;code&gt;Future&lt;/code&gt;.That’s why the akka http routes return &lt;code&gt;Futures&lt;/code&gt; as results. A lambda function that runs on top of the Lambda Java runtime requires functions to be simple blocking functions with a signature &lt;code&gt;def onEvent(event: APIGatewayV2HTTPEvent): APIGatewayV2HTTPResponse&lt;/code&gt;.I chose &lt;code&gt;Try&lt;/code&gt; to be the result type of the Lambda logic. The example conversion of a function with some business logic into a Lambda route would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import scala.util.{Success, Try}
import sttp.tapir.server.httpapi._  

def logic(bfy: BooksFromYear, limit: Limit, at: AuthToken): Try[Either[String, List[Book]]] = {
  Success(Right(List(Book("The Sorrows of Young Werther"))))
}
val serverEndpoint = bookListing.serverLogic((logic _).tupled)
val booksListingRoute: Route = serverEndpoint.toRoute

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Route&lt;/code&gt; is a partial function. If the http request matches the Tapir endpoint definition then we execute the logic for this endpoint. If no then we try another route. This check is expressed via the &lt;code&gt;isDefinedAt&lt;/code&gt; method of the partial function.We use the &lt;code&gt;sttp.tapir.server.internal.DecodeInputs&lt;/code&gt;, pass the context and let Tapir parse the request for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def isDefinedAt(event: APIGatewayV2HTTPEvent): Boolean = {
  DecodeInputs(e.input, new HttpApiDecodeInputsContext(event)) match {
    case _: DecodeInputsResult.Values =&amp;gt; true
    case _: DecodeInputsResult.Failure =&amp;gt; false
  }
}

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

&lt;/div&gt;



&lt;p&gt;When the http request matches our endpoint, it’s time to run the actual application logic. The result of the &lt;code&gt;DecodeInputs&lt;/code&gt; is just a sequence of values. Thus, we map these values into scala classes, so that we get a tuple of case classes, like &lt;code&gt;(BooksFromYear, Limit, AuthToken)&lt;/code&gt; in the example above. This conversion is the responsibility of &lt;code&gt;sttp.tapir.server.internal.InputValues&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def apply(event: APIGatewayV2HTTPEvent): APIGatewayV2HTTPResponse = {
  DecodeInputs(e.input, new HttpApiDecodeInputsContext(event)) match {
    case values: DecodeInputsResult.Values =&amp;gt;
      InputValues(e.input, values) match {
        case InputValuesResult.Value(params, _) =&amp;gt; valueToResponse(params.asAny)
        case InputValuesResult.Failure(input, failure) =&amp;gt; handleDecodeFailure(input, failure)
      }
    case DecodeInputsResult.Failure(input, failure) =&amp;gt; handleDecodeFailure(input, failure)
  }
}

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

&lt;/div&gt;



&lt;p&gt;The next step, after the inputs are successfully parsed, is to pass these inputs into the user-defined logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def valueToResponse(value: Any): APIGatewayV2HTTPResponse = {
  endpoint.logic(TryMonadError)(value.asInstanceOf[I]) match {
    case Success(Right(result)) =&amp;gt; OutputToHttpApiResponse(ServerDefaults.StatusCodes.success, endpoint.output, result)
    case Success(Left(err)) =&amp;gt; OutputToHttpApiResponse(ServerDefaults.StatusCodes.error, endpoint.errorOutput, err)
    case Failure(e) =&amp;gt; OutputToHttpApiResponse(StatusCode.InternalServerError, e.getMessage)
  }
}

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

&lt;/div&gt;



&lt;p&gt;The only thing left is to map the Tapir’s output to the response type that Http API understands. This is what &lt;code&gt;OutputToHttpApiResponse&lt;/code&gt; does in the &lt;code&gt;valueToResponse&lt;/code&gt; method. The implementation requires some lines of code and it can be found &lt;a href="https://github.com/melgenek/serverless-tapir/blob/master/lambda/src/main/scala/sttp/tapir/server/httpapi/OutputToHttpApiResponse.scala" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We put the functionality that is described in the &lt;code&gt;toRoute&lt;/code&gt; function. The &lt;code&gt;Route&lt;/code&gt; is a partial function, so we can compose multiple routes into a single one via the &lt;code&gt;orElse&lt;/code&gt; method. If none of the routes matches the request, we use the predefined &lt;code&gt;EmptyRoute&lt;/code&gt; that answers with the 404 response code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;implicit class RichHttpApiServerEndpoint[I, E, O](endpoint: ServerEndpoint[I, E, O, Nothing, Try]) {
  def toRoute: Route = {
    // the partial function that is described above
  }
}

implicit class RichHttpApiServerEndpoints[I, E, O](serverEndpoints: List[ServerEndpoint[_, _, _, Nothing, Try]]) {
  def toRoutes: Route = {
    serverEndpoints
      .map(_.toRoute)
      .foldRight(EmptyRoute)(_ orElse _)
  }
}

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

&lt;/div&gt;



&lt;p&gt;Let’s also provide an interface that has to be implemented in order to have a complete lambda. This interface requires a list of &lt;code&gt;ServerEndpoints&lt;/code&gt; and then uses these endpoints to process a request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trait HttpApiFunction {
  val serverEndpoints: List[ServerEndpoint[_, _, _, Nothing, Try]]
  def onEvent(event: APIGatewayV2HTTPEvent): APIGatewayV2HTTPResponse = {
    serverEndpoints.toRoutes(event)
  }
}

object BookFunction extends HttpApiFunction {
  override val serverEndpoints = List(booksListingRoute)
}

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

&lt;/div&gt;



&lt;p&gt;Lambdas will have the handler that points to the &lt;code&gt;your.package.BookFunction::onEvent&lt;/code&gt;. The class will be instantiated by the Java runtime and the &lt;code&gt;onEvent&lt;/code&gt; function will be invoked for every http request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Packaging the Lambda
&lt;/h2&gt;

&lt;p&gt;I am not using lambda layers, so the Lambda function has to contain all of the dependencies. The fat jar is packaged using the &lt;code&gt;sbt-assembly&lt;/code&gt; plugin. The only interesting part of this process is the merge conflict resolution. The reference configurations are concatenated and some files with conflict names are discarded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assemblyMergeStrategy in assembly := {
  case PathList("META-INF", _@_*) =&amp;gt; MergeStrategy.discard
  case PathList(ps@_*) if ps.last endsWith "reference-overrides.conf" =&amp;gt; MergeStrategy.concat
  case PathList(ps@_*) if ps.last endsWith "module-info.class" =&amp;gt; MergeStrategy.discard
  case x =&amp;gt;
    val oldStrategy = (assemblyMergeStrategy in assembly).value
    oldStrategy(x)
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;The interpreter is ready, it can be used to compose Tapir endpoints together into a single &lt;code&gt;Route&lt;/code&gt;. The Lambda function is also bundled into a fat jar. Everything is ready for uploading and running this jar. We can go into the AWS UI, click a couple of buttons, create the lambda and upload the code. However, this is a manual process. The whole idea of the experiment, that is described in this article, is to have an easy and automatic process of deploying applications.&lt;/p&gt;

&lt;p&gt;In order to automate the lambda creation process, we will use &lt;a href="https://github.com/aws/aws-cdk" rel="noopener noreferrer"&gt;AWS Cloud Development Kit&lt;/a&gt;. This is a tool that allows defining the AWS infrastructure in Java and transforming this definition into CloudFormation stacks.CloudFormation then makes sure that the infrastructure is created in AWS.&lt;/p&gt;

&lt;p&gt;Let’s create a function that receives an &lt;code&gt;HttpApiFunction&lt;/code&gt; and the name of the Lambda function. This function creates a so-called &lt;code&gt;App&lt;/code&gt;, that contains all the resources. Then it synthesizes the Cloudformation template based on the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def deploy(httpApiFunction: HttpApiFunction, title: String): Unit = {
  val app = new awscdk.core.App()
  ...
  app.synth()
}

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

&lt;/div&gt;



&lt;p&gt;All the resources have scopes. The top-level scope is the &lt;code&gt;App&lt;/code&gt;. Each app is a set of &lt;code&gt;Stacks&lt;/code&gt;. Every &lt;code&gt;Stack&lt;/code&gt; corresponds to a Cloudformationstack. For us, it is enough to create a single Stack.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val stack = new Stack(app, s"$title-stack")

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

&lt;/div&gt;



&lt;p&gt;The first meaningful resource that we create is the lambda function. It is a lambda that is based on the Java 8 runtime. It sets the handler method to be the &lt;code&gt;def onEvent(event: APIGatewayV2HTTPEvent): APIGatewayV2HTTPResponse&lt;/code&gt; of our lambda class. Additionally, we set the local path of the fat jar file that we have bundled. This jar is automatically uploaded by CDK into an s3 bucket. Then this s3 object is used as the source for the lambda function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val function = lambda.Function.Builder.create(stack, s"$title-lambda")
  .memorySize(192)
  .timeout(Duration.seconds(30))
  .functionName(title)
  .runtime(lambda.Runtime.JAVA_8)
  .handler(s"${httpApiFunction.getClass.getName.replace("$", "")}::onEvent")
  .code(Code.fromAsset("lambda/target/scala-2.13/assembly.jar"))
  .build()

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

&lt;/div&gt;



&lt;p&gt;After the lambda is present, we create the API Gateway Http API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val api = HttpApi.Builder.create(stack, s"$title-api")
  .apiName(title)
  .build()

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

&lt;/div&gt;



&lt;p&gt;After both lambda and API are set up, we need to bind them together so that Http API passes the requests into lambda. For this to happen, we create a Lambda integration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val integration = LambdaProxyIntegration.Builder.create()
  .handler(function)
  .payloadFormatVersion(PayloadFormatVersion.VERSION_2_0)
  .build()

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

&lt;/div&gt;



&lt;p&gt;The last step is to define all the http routes and point them to the same lambda function. Tapir’s ability to transform endpoints into Open API helps us construct the routes. For every path in the Open API specification, we create a route in the Http API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import sttp.tapir.docs.openapi._
private def apiRoutes(httpApiFunction: HttpApiFunction, integration: LambdaProxyIntegration): List[AddRoutesOptions] = {
  val openAPI = httpApiFunction.serverEndpoints.map(_.endpoint).toOpenAPI("any name", "v1")
  openAPI.paths
    .map { case (path, pathItem) =&amp;gt; 
    val methods =
      pathItem.get.map(_ =&amp;gt; HttpMethod.GET) ++
        pathItem.post.map(_ =&amp;gt; HttpMethod.POST) ++
        pathItem.delete.map(_ =&amp;gt; HttpMethod.DELETE)
    AddRoutesOptions.builder()
      .methods(methods.toList.asJava)
      .path(path)
      .integration(integration)
      .build()
    }
    .toList
}

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

&lt;/div&gt;



&lt;p&gt;That’s it. Now we pass our lambda class into the deployment function, run the &lt;code&gt;cdk deploy&lt;/code&gt; command in the terminal, and after a short time, our code is up and running in AWS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;object Main extends App {
  HttpApiCdkServer.deploy(BookFunction, "my-bookshop")
}

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

&lt;/div&gt;



&lt;p&gt;Cdk also allows adding outputs into stacks. One of such outputs can be the url of the Http API that we deployed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CfnOutput.Builder.create(stack, "api-url").exportName("url").value(api.getUrl).build()

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

&lt;/div&gt;



&lt;p&gt;This output is shown after the &lt;code&gt;cdk deploy&lt;/code&gt; succeeds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ my-bookshop-stack

Outputs:
my-bookshop-stack.apiurl = https://2qpnchfg11.execute-api.us-east-1.amazonaws.com/

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

&lt;/div&gt;



&lt;p&gt;Calling this url results in the request being handled by our lambda that is described above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -v -H "X-Auth-Token: Bearer token" https://2qpnchfg11.execute-api.us-east-1.amazonaws.com/books/novel/2020?limit=10

Result:
[
  {
    "title": "The Sorrows of Young Werther"
  }
]

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this article, I showed how to run the Tapir application in Lambda and automatically deploy the code with CDK. I believe that the use of CDK brings a lot of benefit into scala applications because it keeps the infrastructure close to the code. The infrastructure has the same version as the code does. This helps us to be sure that the required infrastructure is created at the deployment time. In addition, CDK gives a way to deploy with a command.&lt;/p&gt;

&lt;p&gt;The code for this article can be found in &lt;a href="https://github.com/melgenek/serverless-tapir" rel="noopener noreferrer"&gt;the github repo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>scala</category>
      <category>aws</category>
      <category>lambda</category>
    </item>
  </channel>
</rss>
