<?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: jakubkoci</title>
    <description>The latest articles on Forem by jakubkoci (@jakubkoci).</description>
    <link>https://forem.com/jakubkoci</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%2F162758%2F904324eb-bd33-47ff-b036-74e083891d5d.jpeg</url>
      <title>Forem: jakubkoci</title>
      <link>https://forem.com/jakubkoci</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jakubkoci"/>
    <language>en</language>
    <item>
      <title>OpenID Connect Login</title>
      <dc:creator>jakubkoci</dc:creator>
      <pubDate>Fri, 12 Dec 2025 16:28:00 +0000</pubDate>
      <link>https://forem.com/jakubkoci/openid-connect-login-10e5</link>
      <guid>https://forem.com/jakubkoci/openid-connect-login-10e5</guid>
      <description>&lt;p&gt;I've implemented OpenID Connect (OIDC) login a few times in my career. Two times this year, actually. But I always forget all the steps and details, so I wanted to write them down in this article for future reference. Even if we use a library to manage the majority of those steps, we we can still benefit knowing the details under the hood.&lt;/p&gt;

&lt;p&gt;I'm going to describe Authorization Code flow with PKCE. This diagram illustrates the flow from a high-level perspective:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Terminology
&lt;/h2&gt;

&lt;p&gt;The OpenID Connect is built upon the OAuth specification. The OAuth defines quite a specific terminology that we don't usually use in our day-to-day engineering work. There are a few terms from the &lt;a href="https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/12/" rel="noopener noreferrer"&gt;The OAuth 2.1 Authorization Framework&lt;/a&gt; spec I intentionally simplified or omit for the purpose of this writing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User Agent: the &lt;strong&gt;Browser&lt;/strong&gt;, just a regular web browser&lt;/li&gt;
&lt;li&gt;Client: the &lt;strong&gt;App&lt;/strong&gt;, a confidential, web application client&lt;/li&gt;
&lt;li&gt;Authorization Server: the &lt;strong&gt;Identity Provider&lt;/strong&gt; as referred to in OIDC specification&lt;/li&gt;
&lt;li&gt;Resoruce Server: The Identity Provider issues a JWT at the end of the process that is then used to access a Resource Server. That part is out of scope of this article.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the purpose of this article, I also use the terms front-channel and back-channel that are commonly used, though not part of the OAuth specification:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Front-channel: &lt;strong&gt;Unsecure&lt;/strong&gt;, browser-based &lt;strong&gt;redirects&lt;/strong&gt;. We should not send any sensitive information through this channel.&lt;/li&gt;
&lt;li&gt;Back-channel: &lt;strong&gt;Secure&lt;/strong&gt;, direct server-to-server communication between the App and the Identity Provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Flow
&lt;/h2&gt;

&lt;p&gt;I haven't found a better way to explain the flow than using HTTP requests and responses. It's independent of a particular programming language and can demonstrate lower-level details without too much boilerplate. The flow begins when a user enters the URL of the App into the Browser. The Browser sends a request to the App without a session cookie yet (step 1).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET / HTTP/1.1 
Host: app.com
Cookie:
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flow begins when a user enters the URL of the App into the Browser. The Browser sends a request to the App without a session cookie yet (step 1).&lt;/p&gt;

&lt;p&gt;The App sends a response to the Browser with a redirect to the the Identity Provider (step 2). We can't send anything sensitive via a front-channel because it's publicly visible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;302&lt;/span&gt; &lt;span class="ne"&gt;Found&lt;/span&gt;
&lt;span class="na"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://identityprovider.com/login?response_type=code&amp;amp;client_id=acme&amp;amp;redirect_uri=https://app.com/api/auth/login-callback&amp;amp;scope=profile,email&amp;amp;state=xyz789random&amp;amp;code_challenge=xyz&amp;amp;code_challenge_method=S256&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;response_type&lt;/code&gt;: Suggests we want to use the Authorization Code flow from the OAuth spec. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;client_id&lt;/code&gt;: An identifier of the App.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;redirect_uri&lt;/code&gt;: Where the Identity Provider should redirect the user after successful login.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;state&lt;/code&gt;: 

&lt;ul&gt;
&lt;li&gt;Protection against CSRF (Cross-Site Request Forgery) attacks.&lt;/li&gt;
&lt;li&gt;Randomly generated string.&lt;/li&gt;
&lt;li&gt;Must be verified by the App when handling the &lt;code&gt;login-callback&lt;/code&gt; request as described in the next step.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;code_challenge&lt;/code&gt;:  PKCE part of the flow. 

&lt;ul&gt;
&lt;li&gt;Protection against Authorization Code Injection/Replay attacks.&lt;/li&gt;
&lt;li&gt;Generated based on a randomly generated &lt;code&gt;code_verifier&lt;/code&gt;. The app adds only the &lt;code&gt;code_challenge&lt;/code&gt; to the URL. The app will send the &lt;code&gt;code_verifier&lt;/code&gt; to the Identity Provider later.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Side note: The &lt;code&gt;state&lt;/code&gt; and &lt;code&gt;code_verifier&lt;/code&gt; must be stored somewhere during the authorization flow. In our case, we use a web application with a server component so we can store both &lt;code&gt;state&lt;/code&gt; and &lt;code&gt;code_verifier&lt;/code&gt; temporarily in a server-side session storage.&lt;/p&gt;

&lt;p&gt;The flow continues with the Identity Provider showing a login form. After successful login, the Identity Provider sends a response to the Browser with a redirect to the App (step 3). It uses &lt;code&gt;redirect_uri&lt;/code&gt; as the redirect location. Again, this is a front-channel, so we can't just send the token yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;302&lt;/span&gt; &lt;span class="ne"&gt;Found&lt;/span&gt;
&lt;span class="na"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/api/auth/login-callback?code=123state=xyz789random &lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;code&lt;/code&gt;: Generated by the Identity Provider and stored together with &lt;code&gt;code_challenge&lt;/code&gt; and &lt;code&gt;redirect_uri&lt;/code&gt; to be verified later.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;state&lt;/code&gt;: Received from the App in the previous step (step 2). The app checks if the &lt;code&gt;state&lt;/code&gt; matches the value it sent before.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The App sends a token request to the Identity Provider (step 4). Although we put the values into URL params, we sent them in the body. That means we're in secure back-channel and we can finally send sensitive information such as &lt;code&gt;client_secret&lt;/code&gt; and &lt;code&gt;code_verifier&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="nn"&gt;/token&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;identityprovider.com&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/x-www-form-urlencoded&lt;/span&gt;

code=123&amp;amp;client_id=acme&amp;amp;client_secret=acme-123&amp;amp;code_verifier=verified-xyz&amp;amp;redirect_uri=https://app.com/api/auth/login-callback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;code&lt;/code&gt;: Received from the Identity Provider in the previous step.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;client_id&lt;/code&gt;: The same ID as in the first step.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;client_secret&lt;/code&gt;: The secret obtained before, together with &lt;code&gt;client_id&lt;/code&gt;, during the App registration (not part of this article).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;redirect_uri&lt;/code&gt;: 

&lt;ul&gt;
&lt;li&gt;Protects against Authorization Code Redirection URI Manipulation.&lt;/li&gt;
&lt;li&gt;Must be the same value the App sent in the first request.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;code_verifier&lt;/code&gt;: Retrieved from a storage based on the &lt;code&gt;state&lt;/code&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The Identity Provider verifies that &lt;code&gt;client_id&lt;/code&gt; and &lt;code&gt;client_secret&lt;/code&gt; are correct. It checks if the &lt;code&gt;code_verifier&lt;/code&gt; matches the previously stored &lt;code&gt;code_challenge&lt;/code&gt; and if the &lt;code&gt;redirect_uri&lt;/code&gt; matches the previously stored &lt;code&gt;redirect_uri&lt;/code&gt; for the given &lt;code&gt;code&lt;/code&gt;. Then, it sends a response with token(s) to the App (step 5).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="ne"&gt;OK&lt;/span&gt;

{ 
    "access_token": "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"
    "refresh_token": "def50200a8f4b9c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;access_token&lt;/code&gt;: A token used to access a Resource Server. It usually has short expiration period in minutes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;refresh_token&lt;/code&gt;: A token that has longer expiration period (half an hour and longer) and it's used to refresh the &lt;code&gt;access_token&lt;/code&gt; when that expires.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The App sends a response to the Browser with redirect to home page at &lt;code&gt;/&lt;/code&gt;. The response contains session as an &lt;code&gt;http-only&lt;/code&gt; cookie.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;302&lt;/span&gt; &lt;span class="ne"&gt;Found&lt;/span&gt;
&lt;span class="na"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
&lt;span class="na"&gt;Set-Cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;access_token=eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ; Path=/; HttpOnly; Secure; SameSite=Strict; Max-Age=900&lt;/span&gt;
&lt;span class="na"&gt;Set-Cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;refresh_token=def50200a8f4b9c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5; Path=/api/auth/refresh; HttpOnly; Secure; SameSite=Strict; Max-Age=604800&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the following requests the Browser sends to the App, automatically contains the session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/whatever&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app.com&lt;/span&gt;
&lt;span class="na"&gt;Cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;access_token=eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to understand more about the OAuth in general, this is the best talk on OAuth I've ever seen &lt;a href="https://www.youtube.com/watch?v=996OiexHze0" rel="noopener noreferrer"&gt;OAuth 2.0 and OpenID Connect (in plain English)&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>oidc</category>
      <category>oauth</category>
    </item>
    <item>
      <title>Hyperledger SSI Ecosystem</title>
      <dc:creator>jakubkoci</dc:creator>
      <pubDate>Mon, 16 Aug 2021 08:40:16 +0000</pubDate>
      <link>https://forem.com/jakubkoci/hyperledger-ssi-ecosystem-4j2p</link>
      <guid>https://forem.com/jakubkoci/hyperledger-ssi-ecosystem-4j2p</guid>
      <description>&lt;p&gt;I assume you already know something about SSI principles. If you don’t, I suggest checking out &lt;a href="https://dev.to/jakubkoci/introduction-to-self-sovereign-identity-3kkm"&gt;Introduction to Self-Sovereign Identity&lt;/a&gt;. Now, you’re probably interested in what particular SSI technologies are out there. In this article, I’ll describe SSI technology from Hyperledger. There are three projects under the Hyperledger umbrella related to digital identity. Hyperledger Indy, Aries, and Ursa. Indy and Aries also contain more, let’s say, sub-projects. Therefore, it could be hard to get oriented in all of that. I don’t want to dive too deep here, but describe their purpose and how they’re related to each other.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hyperledger Indy (distributed ledger and wallet)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/hyperledger/indy-node"&gt;indy-node&lt;/a&gt; contains a source code for the node running as part of the distributed ledger network. It implements PBFT consensus protocol, and it’s not intended to run as a public permissionless network as Bitcoin or Etherum but rather as a permissioned network. There is not one single instance of the Indy network. There are many of them. The most famous and publicly available is Sovrin, which was the first one. You can also use indy-node to run your network or run it locally on your machine via Docker for testing purposes. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/hyperledger/indy-sdk"&gt;indy-sdk&lt;/a&gt; works partially as a client for indy-node, but it has much more functionality. The library is written in Rust, and you can find it under the &lt;code&gt;libindy&lt;/code&gt; folder. The binary file name is the same. There are also wrappers allowing you to use the library with other languages like Node.js, .NET, Java, Obj-C, and Python. We can divide the functionality into three parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client for the distributed ledger.&lt;/strong&gt; It allows to write public DID, register schema, and credential definition or work with revocation registry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manipulation with DIDs and verifiable credentials.&lt;/strong&gt; There are methods to create and update DIDs, encrypt and decrypt messages, and create credentials or proofs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A wallet as secure storage for keys, credentials, and other data.&lt;/strong&gt; The wallet automatically stores private keys and allows storing other data. All encrypted with a wallet seed. It’s possible to export and import the data back if needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these functions are still relatively low-level, so it would be better to try out some of the Aries frameworks, as I’ll explain later in the Aries chapter.&lt;/p&gt;

&lt;p&gt;There are discussions in the community about splitting &lt;code&gt;indy-sdk&lt;/code&gt; into more specific standalone libraries. There are already these three projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/hyperledger/indy-vdr/"&gt;indy-vdr&lt;/a&gt;: client for distributed ledger.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/hyperledger/indy-shared-rs"&gt;indy-shared-rs&lt;/a&gt;: DIDs and verifiable credentials.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/hyperledger/aries-askar"&gt;aries-askar&lt;/a&gt;: a wallet as secure storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is another project that wants to evolve from &lt;code&gt;indy-sdk&lt;/code&gt;. Evernym company forked the &lt;code&gt;indy-sdk&lt;/code&gt; and created &lt;a href="https://gitlab.com/evernym/verity/vdr-tools"&gt;vdr-tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I think you’re still good to go with &lt;code&gt;indy-sdk&lt;/code&gt; for now while being aware of other libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hyperledger Ursa (cryptography)
&lt;/h3&gt;

&lt;p&gt;In the beginning, there was no Ursa or Aries, just Indy with all functionality together. As time went by, the Hyperledger community realized that there are a lot of useful cryptographic primitives which can be extracted and used by other Hyperledger projects. That’s the reason why Ursa has been created. It’s only one &lt;a href="https://github.com/hyperledger/ursa"&gt;ursa&lt;/a&gt; repository containing encryption, signatures, and zero-knowledge algorithms. I’m not a cryptographer, and I’ve been working mainly with Indy and Aries, so I don’t know many details about it. I will leave that investigation up to you if you need to learn more. However, for many SSI use case implementations, you will be good just with knowledge of Indy and Aries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hyperledger Aries (protocol and higher-level abstractions)
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;indy-sdk&lt;/code&gt; section, I described that it provides functionality to create DIDs, credentials, proofs, etc. Now, you need a way to securely exchange those items in an interoperable and portable way according to SSI principles. That’s the goal of the Aries project. The specification of the protocol is in &lt;a href="https://github.com/hyperledger/aries-rfcs/"&gt;aries-rfcs&lt;/a&gt;, which originated from an older project, &lt;code&gt;indy-hipe&lt;/code&gt; (the protocol was part of Indy in the beginning).&lt;/p&gt;

&lt;p&gt;There are implementations in more languages like JavaScript, Python, .NET, Go, and Rust. All of them except for Go are using &lt;code&gt;indy-sdk&lt;/code&gt; under the hood. Go framework implemented &lt;code&gt;indy-sdk&lt;/code&gt; functionality on its own from scratch. That’s the beauty of it. As long as you’re compliant with the protocol, you can build it according to your own needs.&lt;/p&gt;

&lt;p&gt;On top of that, as I mentioned earlier, Aries frameworks and libraries add some level of abstraction over &lt;code&gt;indy-sdk&lt;/code&gt; to save you some time with repeating tasks. They offer better developer experience, simplicity, and faster development of SSI applications for all issuer, holder, and verifier roles.&lt;/p&gt;

&lt;p&gt;Here is a diagram showing how all those components fit together. I took &lt;a href="https://github.com/hyperledger/aries-framework-javascript"&gt;Aries JavaScript Framework&lt;/a&gt; for demonstration (I’m a little bit biased here because I started the project, and I’m a fan of it, of course):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2u59EvTk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o3fx3qfahwtr8g6encql.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2u59EvTk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o3fx3qfahwtr8g6encql.png" alt="aries-framework-javascript-Page-3"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Each project would deserve a standalone article. Hopefully, you have at least a good overview of the SSI ecosystem. Maybe we can dive deeper next time.&lt;/p&gt;

</description>
      <category>ssi</category>
      <category>selfsovereignidentity</category>
      <category>digitalidentity</category>
      <category>hyperledger</category>
    </item>
    <item>
      <title>Introduction to Self-Sovereign Identity</title>
      <dc:creator>jakubkoci</dc:creator>
      <pubDate>Sun, 28 Mar 2021 13:22:28 +0000</pubDate>
      <link>https://forem.com/jakubkoci/introduction-to-self-sovereign-identity-3kkm</link>
      <guid>https://forem.com/jakubkoci/introduction-to-self-sovereign-identity-3kkm</guid>
      <description>&lt;p&gt;In this article, I will do my best to explain self-sovereign identity from the end-user perspective, without any technicalities.&lt;/p&gt;

&lt;p&gt;Self-sovereign identity (SSI) is, simply put, a decentralized digital identity, but before we dive in, let’s look at what identity and digital identity actually means.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identity
&lt;/h2&gt;

&lt;p&gt;Identity is not only about a physical identity card issued by the government. An identity is a group of various attributes and relationships describing the existence of each individual. Some of these attributes we get assigned (like a name), some of them just happen (like date of birth). It could be our capabilities, our relationships, our biometric information, and our behavior. All these attributes belong to our identity. We can be uniquely identified based on some of these attributes in a given context. Sometimes our first name is good enough, sometimes we need our last name or date of birth. In a more formal context (communication with the government for example), we need an ID card with an ID number on it, which was given to us. On the other hand, our friends probably wouldn’t need to see our ID card but could be skeptical about our behavior, in both positive and negative ways. Remember when you did something unexpected and your friend was confused, asking “Who are you?”.&lt;/p&gt;

&lt;p&gt;Nowadays, we usually use physical documents such as an ID card, driving license, birth certificate, university diploma, marriage certificate, and so on, to prove our particular identity attributes. How can we do the same thing in today’s digital world?&lt;/p&gt;

&lt;h2&gt;
  
  
  Digital Identity
&lt;/h2&gt;

&lt;p&gt;You probably already have some sort of digital identity. Do you have an account on any social network? How many usernames and passwords do you have? I bet it’s plenty. Every username and password represent your so-called user account to access a specific software system (web or mobile application). Such system also keeps other information about us, like name, birth date, address. It sometimes also links your user account with other user accounts, representing your “digital” relationships with these users. As you can see it’s really similar to the identity description above. However, it has some problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problems with Digital Identity
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It’s &lt;strong&gt;hard to reuse&lt;/strong&gt; our data. There are systems that require more than just your e-mail (as username) and password. Such systems often require additional personal details like date of birth, residence address, and sometimes even more. This data is usually usable only on the specific software platform. You’re vendor locked-in.&lt;/li&gt;
&lt;li&gt;You have to provide this data all over again and you are actually not able to remember what you’ve shared with whom. It brings us to a problem where there is a large amount of &lt;strong&gt;duplicated data&lt;/strong&gt; in the systems we’re using.&lt;/li&gt;
&lt;li&gt;We can partially solve this data reuse and duplication problem by using a mechanism called single sign-on. Single sign-on is when you see buttons like “Log in with Facebook” or “Log in with Google”. First, you log in with your Facebook username and password, then when you’re trying to log into another system, it asks Facebook who you are and creates your user account based on that. The benefit is that you don’t need to create yet another password. The problem is that it creates &lt;strong&gt;centralized silos of data&lt;/strong&gt;. Let’s say you’re using Facebook as a single sign-on on every other web application. Your digital life becomes dependent on Facebook. You have to hope they won’t cut you off from their service (yes, they can do that) or you won’t have a reason to leave. Facebook also knows exactly when and where you’re logging in. If there is a data breach, your user accounts in other software applications are at risk. These centralized silos of data are problematic even without single sign-on. Services with a huge amount of users with one centralized database are honeypots for hackers.&lt;/li&gt;
&lt;li&gt;If you follow current security recommendations, you should use a new username and password for every new registration to an application. Even if you don’t use a new username, but you just create a new password and use your e-mail as a username, it’s still &lt;strong&gt;too many passwords to manage&lt;/strong&gt;. You can solve this with a password manager, and you should (really, go and install one right now). However, using your e-mail as a username has its own issue. What if you want to change your primary e-mail address? I’ll let you think about the consequences of such an act :). It’s possible to get rid of all usernames and passwords with SSI. I’ll explain how later.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Decentralization
&lt;/h2&gt;

&lt;p&gt;So far we’ve discussed identity and its digital representation. What about that decentralized part which is so crucial for SSI?&lt;/p&gt;

&lt;p&gt;Let’s look at physical documents. These documents contain selected attributes about our identity attested and issued to us by an authority. They have signatures, stamps and other watermarks to provide tamper-proof and trust. Whoever trusts these signatures and authority, trusts the data on the document and doesn’t have to contact an issuer for every verification. We have it under control and in our possession, stored in a wallet or in other places. They’re already somehow decentralized. For example, my ID card contains my ID number, first name, last name, date of birth, and address. It’s attested by the government. I can use it to prove my age in a liquor store and the merchant doesn’t have to contact the government.&lt;/p&gt;

&lt;p&gt;We can do the same with digital documents. Of course, we’re not able to sign it with a physical signature, so we need to use a digital signature. Instead of storing such documents in our physical wallet, we save them in a software wallet, which could be an application on our mobile phone, tablet, or laptop. These documents are called &lt;strong&gt;verifiable credentials&lt;/strong&gt; and we can use them in both the digital and physical world.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just Scan a QR Code
&lt;/h2&gt;

&lt;p&gt;I’ll demonstrate some scenarios of how it could work in the real world. We start with a software wallet, most likely in the form of a mobile app that we can download from an app store. Then, we go to the government office just as we go there for a new ID card. A clerk will generate a QR code on a display. We scan it with our mobile app and get our government identity card in the form of a verifiable credential. Now, we can go to a bank website to open a bank account. The bank website shows a QR that contains the information they need from us to open the account. We will see the requested data in our mobile app. If we confirm this share request, the bank will verify the digital signature from the government, and if the bank trusts this they can open an account for us.&lt;/p&gt;

&lt;p&gt;Verifiable credentials are not only about a digital identity card. You can have almost any document you can imagine in the form of a verifiable credential. It could be a bank account statement proving your income, certificate or diploma proving your education, or just an ordinary public transport ticket. Another example could be an application for a credit card. Let’s say you have a bank account in ABC bank and you want a credit card in XYZ bank. You go to the XYZ bank website, scan a QR code and share your ID number, last name, and address from the digital identity credential together with your income for the last 3 months from bank account statement credentials issued by ABC bank. No more filling sensitive data into endless forms again and again. Similarly, you can get a verifiable credential representing your university diploma and then share it with your new employer. This way, you are building your decentralized digital identity one credential at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Roles of SSI
&lt;/h2&gt;

&lt;p&gt;There are three basic roles in SSI. Issuer, verifier, and holder. The first scenario above described the government as an &lt;strong&gt;issuer&lt;/strong&gt;, issuing an ID card credential, the bank as a &lt;strong&gt;verifier&lt;/strong&gt; of the credential, and us, users, as &lt;strong&gt;holders&lt;/strong&gt; of the credential. In the second scenario with a credit card, one bank was an issuer of a bank account statement and the other was a verifier. The reason I’m explaining these roles instead of just using government, bank, and user directly is because who is in what role depends on the exact use case. Let’s say I want to verify if an e-shop is a legit business by verifying its business license before I place an order. Then I can issue a credential to my friend to receive the delivery if I’m not at home.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o5FnFXV5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jbtq8541szvkxzly8cst.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o5FnFXV5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jbtq8541szvkxzly8cst.png" alt="SSI Roles"&gt;&lt;/a&gt;Roles in SSI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Principles of SSI
&lt;/h2&gt;

&lt;p&gt;Each party in the examples demonstrated above needs some software to participate in a credential exchange. This software doesn’t have to be from the same provider at all. If everyone is compliant with &lt;strong&gt;self-sovereign identity standards&lt;/strong&gt;, we can use whatever vendor or platform we want and still be &lt;strong&gt;interoperable&lt;/strong&gt;. This also allows for &lt;strong&gt;portability&lt;/strong&gt; from one provider to another. Remember, we need to have data under our control and decide where it will be stored. Therefore we should be able to move our credentials from one mobile app to another, keeping all of them usable and valid.&lt;/p&gt;

&lt;p&gt;The software wallet &lt;strong&gt;securely stores all credentials encrypted&lt;/strong&gt; and accessible only via biometric or passcode authentication. Each credential exchange is done via a &lt;strong&gt;secure communication channel&lt;/strong&gt;. It’s created when a user scans the QR code or reused if the channel with the given party already exists.&lt;/p&gt;

&lt;p&gt;Last thing I kept intentionally until the end is &lt;strong&gt;minimal disclosure&lt;/strong&gt;, the best of all these innovations brought by SSI from my perspective. With physical or ordinary digital documents we need to share the whole document even if another party asks us just for one attribute. Let’s look at the date of birth and liquor store use case again. We need to share the whole ID card with the merchant although they look at the date of birth only. With verifiable credentials, we can use modern cryptography to disclose just one attribute while preserving data integrity and signatures. We can go even further and &lt;strong&gt;disclose only that the required attribute is in a given range without revealing the exact value&lt;/strong&gt;. Imagine proving you’re older than 21 without revealing your age, proving your income is higher than a specific amount without revealing your salary or that you live in a specific city without revealing your exact address.&lt;/p&gt;

&lt;p&gt;That’s all for the introduction to SSI. I hope I got you excited about this amazing technology. I tried to keep it high level so I can imagine you have a lot of questions. If so, don’t hesitate to ask and stay tuned for other articles that will probably go deeper.&lt;/p&gt;

</description>
      <category>ssi</category>
      <category>selfsovereignidentity</category>
      <category>digitalidentity</category>
      <category>decentralization</category>
    </item>
    <item>
      <title>How to start with programming?</title>
      <dc:creator>jakubkoci</dc:creator>
      <pubDate>Sat, 15 Aug 2020 10:50:57 +0000</pubDate>
      <link>https://forem.com/jakubkoci/how-to-start-with-programming-2cih</link>
      <guid>https://forem.com/jakubkoci/how-to-start-with-programming-2cih</guid>
      <description>&lt;p&gt;I’ve been interested in programming since I was 16, I studied computer science and was lucky to start a career as a software engineer. This, however, doesn’t mean that everyone necessarily has to take the same path as I did. I know many people who started programming without any previous experience or education and still succeeded. Although programming might be very challenging at first, it will most likely be fun. You will be able to create amazing stuff on your device and work wherever you are.&lt;/p&gt;

&lt;p&gt;Many people ask me whether it’s possible to learn it, how hard it is, and where to start. I always try to give them as many positive answers as possible and encourage them to try it. On the other hand, I struggle to give them a simple explanation, so I decided to share a few tips with you.&lt;/p&gt;

&lt;p&gt;Can anyone learn how to program? I think if you can read, write and count, then you will pretty much be able to learn at least basics of programming. There is no secret magic behind it, we’re not special magic species or wizards like Harry Potter, there is no secret Hogwarts college behind platform 9 and 3/4 for programmers. Don’t be afraid and just do it! That’s the most important first step.&lt;/p&gt;

&lt;p&gt;Can anyone make a living on it? Maybe not. In my opinion, it depends on you and how much effort you want to put in it and there is no doubt that you need a lot of passion to become a good software developer. Not everyone has it, as not everyone necessarily likes music (no offense, I like it). Is it a problem if you are not good at math? No, I’m a good example it’s not :).&lt;/p&gt;

&lt;p&gt;Now as you are motivated, let’s look at the difficult part, programming itself. Before I tell you where to start, let me explain what programming actually is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Definition of programming
&lt;/h2&gt;

&lt;p&gt;Programming means describing instructions of what we want our computer to do. We need a programming language, as computers don’t understand any human language, only machine code consisted of zeros and ones like this 1101010101.&lt;/p&gt;

&lt;p&gt;Such instructions are usually in a textual form called “source code” written in a given programming language. It’s just a bunch of keywords and symbols (syntax) with given meaning (semantics), kind of similar to English, with more structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Selecting a programming language
&lt;/h2&gt;

&lt;p&gt;Before you start, you need to select a programming language. There are hundreds of them, but I don’t want to make you confused. In the beginning, I recommend to choose JavaScript. You can find it everywhere as you can create many different kinds of apps (mobile, desktop, web). There is a lot of resources on the internet, some of them for free.&lt;/p&gt;

&lt;p&gt;Although I highly recommend JavaScript, another good option for you might be Java or Python. If you have a good friend who knows one of them and is able to help you with it, these could be even better for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to start?
&lt;/h2&gt;

&lt;p&gt;The best idea is to start with &lt;a href="https://learn.freecodecamp.org/"&gt;Welcome to learn.freeCodeCamp!&lt;/a&gt;, specifically, with these two courses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Responsive Web Design Certification (I would go for this one if you are interested in making websites or web apps. Anyway, I think you will always find a way to use the basics of HTML and CSS. The benefit is that it’s more visual and you can apply this knowledge with your learning of JS later on.)&lt;/li&gt;
&lt;li&gt;JavaScript Algorithms and Data Structures Certification
Each course has around 300 hours or learning material. Don't be scared by this amount of time. Courses are divided into small interactive sections where you have a short explanation of the topic and playground where you can directly try and test your understanding to progress in small steps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other good JavaScript resources for beginners:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.khanacademy.org/computing/computer-programming/programming"&gt;Khan Academy - Unit: Intro to JS: Drawing &amp;amp; Animation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.khanacademy.org/computing/ap-computer-science-principles/programming-101"&gt;Khan Academy - Unit: Programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://eloquentjavascript.net/index.html"&gt;Eloquent JavaScript&lt;/a&gt;. It’s a free book about JavaScript, from the very basic to the most advanced part. Read and try at least Intro plus the first 5 chapters, which could be enough to start with. After practicing you can check out other articles or courses for JavaScript basics and come back later for the advanced stuff.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codecademy.com/learn/introduction-to-javascript"&gt;JavaScript Tutorial: Learn JavaScript For Free | Codecademy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pluralsight.com/courses/code-school-javascript-road-trip-part-1"&gt;Code School: JavaScript Road Trip Part 1 | Pluralsight&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://javascript.info/"&gt;The Modern Javascript Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also like &lt;a href="https://egghead.io/"&gt;@eggheadio&lt;/a&gt;. Although courses for JavaScript are paid, there are free courses related to other programming topics.&lt;/p&gt;

&lt;p&gt;I’ve recently discovered the &lt;a href="https://www.youtube.com/watch?v=-1CuAiKdBQs"&gt;Programming 101 with “Uncle Bob”&lt;/a&gt; video. I would say the content is mainly language agnostic, but there is a Java demo at the end. It nicely introduces you to programming logic. Look at the first 35 minutes, the rest is optional.&lt;/p&gt;

&lt;p&gt;If you’ve really decided that Java will be your first language, look at &lt;a href="https://www.youtube.com/playlist?list=PL84A56BC7F4A1F852"&gt;Course | Programming Methodology - YouTube&lt;/a&gt;. It’s a course from Stanford University, not strictly about Java, but more about general programming principles demonstrated with Java programming language and taught by the most passionate teacher I’ve ever seen. I guess it’s not for total beginners, take it as a part of education, not only a resource for your learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next
&lt;/h2&gt;

&lt;p&gt;After you make your first steps into programming, you should already know what exactly you are interested in. Mobile apps? Web apps? Games? Your interests can also influence your decision about choosing a programming language. I just want you to know that this is not the end, but the beginning. If you are thinking about taking programming seriously, as your job, &lt;a href="https://www.greenfoxacademy.cz/en/junior-developer#thematics"&gt;Green Fox Academy - Junior Developer Course&lt;/a&gt; provides a good overview and a roadmap of the programmer’s knowledge base.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Read, watch, listen.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do&lt;/strong&gt; tutorials, don't bother with re-writing it, that's ok.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write your own stuff&lt;/strong&gt;. Inspire yourself with a tutorial, then change requirements a little. If you did a tutorial on the to-do list, change the to-do list to a list of finance records. In this way, you’ll be enforced to think more about what you’re learning, not only re-writing code from tutorials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Practice, practice, practice.&lt;/strong&gt; Have you heard about 10 000 hours rule? You learn programming only by writing code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus.&lt;/strong&gt; You will see a lot of different resources, opinions, job opportunities for a lot of different technologies. Although a software development career is a never-ending learning story, it’s good to master your already gained skills first, don’t jump from one language to another. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Patience&lt;/strong&gt;. I said it is possible, but I didn’t say it would be easy. It takes a lot of effort. It takes a lot of time. Don’t give up with first struggles. Don’t be too harsh to yourself. You don’t have to get everything for the first time, even for the second or third time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nobody knows what they're doing.&lt;/strong&gt; Don’t forget, software engineering is a young field and  &lt;a href="https://medium.com/@mxstbr/nobody-knows-what-the-fuck-they-re-doing-b62945f88b0d"&gt;Nobody knows what the fuck they’re doing – Max Stoiber – Medium&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you’re now motivated and couldn’t wait to start. Good luck and enjoy the road!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;To my lovely girlfriend.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>learning</category>
      <category>programming</category>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Origin of Banks</title>
      <dc:creator>jakubkoci</dc:creator>
      <pubDate>Thu, 16 Jul 2020 19:56:25 +0000</pubDate>
      <link>https://forem.com/jakubkoci/origin-of-banks-19g7</link>
      <guid>https://forem.com/jakubkoci/origin-of-banks-19g7</guid>
      <description>&lt;p&gt;Last summer I was on vacation in Italy. Because of my interest in the history of money, I realized there are some interesting places worth visiting connected to banking history. Let me take you on a short trip explaining the origin of banks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pisa
&lt;/h2&gt;

&lt;p&gt;Our first stop is Pisa. This was the birthplace of &lt;strong&gt;Leonardo of Pisa&lt;/strong&gt;. You probably know him as &lt;strong&gt;Fibonacci&lt;/strong&gt;. He is known for his sequence of numbers, Fibonacci sequence, but he also helped build the financial industry. During his travels across the Mediterranean, he realized how much easier it is for merchants to use &lt;strong&gt;Arabic numerals&lt;/strong&gt; for calculations vs. &lt;strong&gt;Roman numerals&lt;/strong&gt;, which were used heavily in Italy back then. Based on this finding he wrote the &lt;strong&gt;Book of Calculation&lt;/strong&gt; in the year 1202, demonstrating the benefits of Arabic numerals for different kinds of commercial calculations like currency conversion or computation of interest from money loans.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--45BWvuXR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h40leoqikh7jo8ywpsp1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--45BWvuXR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h40leoqikh7jo8ywpsp1.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
Pisa



&lt;h2&gt;
  
  
  Venice
&lt;/h2&gt;

&lt;p&gt;Fibonacci’s calculations became very valuable in &lt;strong&gt;Venice&lt;/strong&gt;, which was &lt;strong&gt;the trade center&lt;/strong&gt; between Western Europe and the rest of the world. But that was just the first step towards banking as we know it today. &lt;strong&gt;Overseas business voyages&lt;/strong&gt; were profitable, but costly and &lt;strong&gt;merchants needed funding&lt;/strong&gt; to make it happen. There was also a risk of ships sinking, causing the loss of all invested money therefore nobody wanted to lend money for free. The &lt;strong&gt;problem&lt;/strong&gt; was the Medieval church’s law against usury, &lt;strong&gt;charging interest&lt;/strong&gt; for a loan. However, this law only applied to Christians, not to &lt;strong&gt;Jews&lt;/strong&gt;. Jews weren’t supposed to lend with interest to other Jews, but they could lend to a stranger, to a Christian.&lt;/p&gt;

&lt;p&gt;Jews were forced to live in a ghetto where they were providing financial services, sitting behind their desks on &lt;strong&gt;benches&lt;/strong&gt;. That’s the origin of the word &lt;strong&gt;bank&lt;/strong&gt;, from the Italian word “banco” which means a bench.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qs9NMhzP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/am7fevkdsr5cnis7sm5d.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qs9NMhzP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/am7fevkdsr5cnis7sm5d.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
Banco Rosso, Venice. The place with one of the first banks (benches).



&lt;p&gt;Today’s banks are usually big companies. That’s not a coincidence, they have to be big to reduce risk. In comparison to individuals or a small group of Jews in Venice, it’s a huge difference. When an individual lends money, it’s usually a significant part of his portfolio and it could have a devastating impact on his business. Therefore he is forced to require a large interest to cover such cases. A higher interest could be good for the lender, but it’s not so convenient for the borrower. Shakespeare’s play &lt;strong&gt;Merchant of Venice&lt;/strong&gt; demonstrates this issue nicely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Florence
&lt;/h2&gt;

&lt;p&gt;Money lenders needed to become bigger. Let me take you from Venice to our last stop, Florence. The Florentine &lt;strong&gt;Medici family&lt;/strong&gt;, which I consider the biggest financial disruptors of the &lt;strong&gt;15th century&lt;/strong&gt;, created huge wealth based on two tricks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;creation of a decentralized &lt;strong&gt;network of partners&lt;/strong&gt; to protect against defaulting of their clients&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;hide interests&lt;/strong&gt; as commission for currency conversion&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The second point allowed them to avoid the church’s anti-usury law. They couldn’t provide a loan for interest but could charge &lt;strong&gt;a commission for currency exchange&lt;/strong&gt;. Let’s say you would like to exchange 10 euros for 12 dollars. You would get 12 dollars immediately, but pay them 10 euros plus some commission later. The longer the period, the higher the commission and therefore interest.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EHIus4iR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nm1dzmlbfpi50chl058w.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EHIus4iR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nm1dzmlbfpi50chl058w.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
Via Arte Della Lana, Florence. The street where the Medici family had their bench and was providing financial services.



&lt;p&gt;The Medici family founded the Medici bank in 1397 and we can even say they later financed the whole renaissance.&lt;/p&gt;

&lt;p&gt;If you like such stories, I really recommend watching the documentary &lt;a href="https://www.imdb.com/title/tt6959282/"&gt;The Ascent of Money (TV Series 2009) - IMDb&lt;/a&gt; which served as a reference for this article.&lt;/p&gt;

</description>
      <category>banking</category>
      <category>finance</category>
      <category>money</category>
      <category>travelling</category>
    </item>
    <item>
      <title>Infrastructure as Code in TypeScript</title>
      <dc:creator>jakubkoci</dc:creator>
      <pubDate>Mon, 06 Apr 2020 19:50:19 +0000</pubDate>
      <link>https://forem.com/jakubkoci/infrastructure-as-a-code-in-typescript-1a39</link>
      <guid>https://forem.com/jakubkoci/infrastructure-as-a-code-in-typescript-1a39</guid>
      <description>&lt;p&gt;It's been about 4 three years since I participated in the AWS hackathon. There were some great talks about AWS before the hackathon itself. I remember I was both amazed and overwhelmed at the same time. I was amazed by the possibilities you have with AWS and saw a huge potential there. On the other hand, I was overwhelmed by all the clicking here and there across the AWS console. Time went by and I haven’t worked with infrastructure so much until now. &lt;/p&gt;

&lt;p&gt;Fortunately, I’ve recently found Pulumi which saved me from the AWS console clicking panic. Pulumi is a tool that allows you to define your infrastructure as a code. It supports AWS, Azure, GCP, and many other cloud providers. You can also use it for Kubernetes. I know there are already similar tools like AWS CloudFormation or Terraform. The problem is that the first one is only for AWS and the second has its own custom language. Here comes the biggest advantage Pulumi has from my perspective. You can define your infrastructure in JavaScript or TypeScript. It also supports Python and there is some preview version for Go and C#.&lt;/p&gt;

&lt;p&gt;My infrastructure is just one EC2 instance with inbound SSH and outbound internet access. However, I still ended up with something a little bit different than what was in the official Pulumi Getting Started documentation and I also found some errors I needed to solve along the way. That's what I want to share with you here. &lt;/p&gt;

&lt;p&gt;Pulumi &lt;a href="https://www.pulumi.com/docs/get-started/aws/"&gt;Get Started with AWS | Pulumi&lt;/a&gt; manual is quite good, so look for the Pulumi installation, AWS Setup and creating a new project there.&lt;/p&gt;

&lt;p&gt;After successfully going through the &lt;code&gt;quickstart&lt;/code&gt; project, I continued with a project for my infrastructure. It consists of VPC, subnet in the VPC, routing tables, internet gateway, EC2 instance and connecting them all together. Therefore &lt;a href="https://www.pulumi.com/docs/tutorials/aws/ec2-webserver/"&gt;Deploy a Webserver to AWS EC2 | Pulumi&lt;/a&gt; wasn’t enough for me.&lt;/p&gt;

&lt;p&gt;Let’s start with the VPC, internet gateway, one subnet and routing table. Here, it’s important to say that you don't need to define &lt;code&gt;10.0.0.0/24&lt;/code&gt; with &lt;code&gt;local&lt;/code&gt; target because it's created automatically. Actually, it throws an error if you try to do so. &lt;/p&gt;

&lt;p&gt;This is not mentioned in &lt;a href="https://www.pulumi.com/docs/reference/pkg/aws/ec2/routetable/"&gt;RouteTable | Pulumi&lt;/a&gt; docs. But, fortunately, it’s based on Terraform &lt;a href="https://github.com/terraform-providers/terraform-provider-aws/blob/master/website/docs/r/route_table.html.markdown"&gt;aws_route_table&lt;/a&gt; where you can find the explanation “Note that the default route, mapping the VPC’s CIDR block to ‘local’, is created implicitly and cannot be specified.”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@pulumi/aws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-vpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;cidrBlock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10.0.0.0/16&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;internetGateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;InternetGateway&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-internetgateway&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subnet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Subnet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-public-subnet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;cidrBlock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10.0.0.0/24&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Main&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Allow access to any address outside VPC except for addresses inside VPC.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;publicRouteTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RouteTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-route-table&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;routes&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="na"&gt;cidrBlock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0/0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;gatewayId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;internetGateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;AWS creates a default routing table when creating VPC, but it permits everything. We needed to create a routing table to allow access from the internet and associate it with subnet here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;publicRouteTableAssociation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RouteTableAssociation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-route-table-association&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;routeTableId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;publicRouteTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;subnetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, let's create a security group allowing inbound SSH access to EC2 instance and security group allowing outbound internet access to EC2 instance. For the definition of the second one, the &lt;a href="https://www.pulumi.com/docs/reference/pkg/aws/ec2/securitygroup/"&gt;SecurityGroup | Pulumi&lt;/a&gt; documentation says: “If you select a protocol of &lt;code&gt;-1&lt;/code&gt; (semantically equivalent to &lt;code&gt;all&lt;/code&gt;, which is not a valid value here), you must specify a &lt;code&gt;from_port&lt;/code&gt; and &lt;code&gt;to_port&lt;/code&gt; equal to &lt;code&gt;0&lt;/code&gt;. If not &lt;code&gt;icmp&lt;/code&gt;, &lt;code&gt;tcp&lt;/code&gt;, &lt;code&gt;udp&lt;/code&gt;, or &lt;code&gt;-1&lt;/code&gt;”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sshGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SecurityGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ssh-access&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ingress&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="na"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tcp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fromPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;toPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;cidrBlocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0/0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;internetGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SecurityGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;internet-access&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;egress&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="na"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fromPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;toPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;cidrBlocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0/0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;vpcId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Pulumi can also upload a public key for SSH access to EC2 instance for you. I don't like to hardcode such things so I added &lt;code&gt;dotenv&lt;/code&gt; package and set the key in &lt;code&gt;.env&lt;/code&gt; file, which is not versioned. This is the beauty of using TypeScript because you can use it in a way you're used to in your usual development process. The format of the key and other details are described here &lt;a href="https://www.pulumi.com/docs/reference/pkg/aws/ec2/keypair/"&gt;KeyPair | Pulumi&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add import at the start of the file&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SSH_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Missing public key.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;KeyPair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, we define our EC2 server. You can see I didn't use &lt;code&gt;aws.getAmi(...)&lt;/code&gt; method, but I set &lt;code&gt;amiId&lt;/code&gt;  I found in &lt;a href="https://cloud-images.ubuntu.com/locator/ec2/"&gt;Ubuntu Amazon EC2 AMI Finder&lt;/a&gt; directly. Also, if you don’t have &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-classic-platform.html"&gt;EC2-Classic&lt;/a&gt; VPC, you need to assign groups with &lt;code&gt;vpcSecurityGroupIds&lt;/code&gt; attribute. The code in the official documentation example shows usage of &lt;code&gt;securityGroups: [group.name]&lt;/code&gt;, but it has been deprecated and throws an error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;instanceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ami&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;amiId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subnetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;vpcSecurityGroupIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sshGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;internetGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;keyName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keyName&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One more thing. This EC2 instance we created doesn't have a public IPv4 assigned by default. We can set &lt;code&gt;associatePublicIpAddress: true&lt;/code&gt; in &lt;code&gt;InstanceArgs&lt;/code&gt; definition or define Elastic IP. The benefit of Elastic IP is that it stays the same even if you restart the machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Eip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;my&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;eip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;, {
  instance: server.id,
  vpc: true
});
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, you can run &lt;code&gt;pulumi up&lt;/code&gt;  and Pulumi creates everything in AWS for you. No clicking, just the code. You can access the machine by &lt;code&gt;ssh -i ~/.ssh/id_rsa ubuntu@&amp;lt;ELASTIC_IP&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There aren’t as many tutorials and examples on the Pulumi docs site. You would need to go through the API reference or look into Github (yes, it’s open-source). I’m adding some links I found useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/reference/pkg/aws/"&gt;Pulumi AWS API Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/reference/pkg/aws/ec2/"&gt;Pulumi AWS EC2 API Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pulumi/pulumi-aws/tree/master/sdk/nodejs"&gt;Pulumi AWS Node.js SDK on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/pulumi/examples"&gt;Pulumi examples on Github&lt;/a&gt; - Examples in all supported languages. Particularly the folder &lt;code&gt;aws-ts-resources&lt;/code&gt; helped me with my effort.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.terraform.io/docs/providers/aws/index.html"&gt;Provider: AWS - Terraform by HashiCorp&lt;/a&gt; - You can also look into Terraform docs as I did with RouteTable specification.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>typescript</category>
      <category>pulumi</category>
      <category>aws</category>
    </item>
    <item>
      <title>React Native Push Notifications</title>
      <dc:creator>jakubkoci</dc:creator>
      <pubDate>Sat, 29 Feb 2020 21:37:33 +0000</pubDate>
      <link>https://forem.com/jakubkoci/react-native-push-notifications-313i</link>
      <guid>https://forem.com/jakubkoci/react-native-push-notifications-313i</guid>
      <description>&lt;p&gt;So you want to start using push notifications in your new shiny mobile app written in React Native. But if you’re new to mobile development and you don’t know anything about how push notifications work, you can be lost (as I was the first time). What’s so difficult about push notifications? &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each platform (Android, iOS) implements it differently.&lt;/li&gt;
&lt;li&gt;React Native implementation itself is a bit different for each platform and React Native push notification libraries can also have differences.&lt;/li&gt;
&lt;li&gt;There is some backend/server-side involved.&lt;/li&gt;
&lt;li&gt;Different behavior based on the state of the app (open, in the background, closed) from the user perspective.&lt;/li&gt;
&lt;li&gt;Various types of notifications (local/remote, foreground/background, …).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, let’s look at the general specifics of push notifications and then I’ll discuss the selection of React Native library and show you how to set up push notifications and React Native notifications library on each platform.&lt;/p&gt;

&lt;h1&gt;
  
  
  Architecture
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oZDYjw89--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y700xtbqzbas833uh0ms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oZDYjw89--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y700xtbqzbas833uh0ms.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html"&gt;APNs&lt;/a&gt; (Apple Push Notification service) and &lt;a href="https://firebase.google.com/docs/cloud-messaging"&gt;FCM&lt;/a&gt; (Firebase Cloud Messaging) are cloud services provided by Apple for iOS and by Google for Android, respectively. To utilize these services as a developer, you need to register your app for APNs or FCM (I’ll explain how to do that later). After that process, you will get a certificate for iOS and Server API Key for FCM which you will save into your notification provider. Notification Provider could be AWS SNS for example. You can also use FCM, build your own or it can be part of your backend system.&lt;/p&gt;

&lt;p&gt;The goal of APNs and FCM services is to allow you to send a notification to a user without knowing anything about the IP address of the user’s device. You just add some code into your app which registers the user’s device with APNs or FCM and returns back a device token. Then you send a notification message for the given device token from your backend system via notification provider to APNs or FCM and they take care of the rest - delivery to the user’s device.&lt;/p&gt;

&lt;h1&gt;
  
  
  Notification Types
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Foreground vs. Background
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Foreground notification means notification which the user gets when the app is open and running.&lt;/li&gt;
&lt;li&gt;Background notification is either when the app is running in the background or when the app is closed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a different behavior and API for handling notifications depending on the state of the app on the user’s device and you have to be prepared for that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remote vs. Local
&lt;/h3&gt;

&lt;p&gt;A local notification is a notification initiated from within the app and then delivered into the system notification center by a given time or repeatedly.  Such notification is not being sent from the server. Vice versa, a remote notification is sent from a server. In this article I’ll be focusing mainly on remote notifications.&lt;/p&gt;

&lt;h1&gt;
  
  
  React Native library
&lt;/h1&gt;

&lt;p&gt;So far, I’ve tried two libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/zo0r/react-native-push-notification"&gt;zo0r/react-native-push-notification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wix/react-native-notifications/"&gt;wix/react-native-notifications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I started with zo0r/react-native-push-notification, but I had an issue with receiving background notification on iOS so I went with wix/react-native-notifications.&lt;/p&gt;

&lt;p&gt;Install the library by running: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Yarn: &lt;code&gt;yarn add react-native-notifications&lt;/code&gt; or &lt;/li&gt;
&lt;li&gt;NPM: &lt;code&gt;npm install —save react-native-notifications&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, you can go through the setup section for iOS or Android as you need. In any case, you need to go through &lt;strong&gt;React Native Implementation&lt;/strong&gt; section right after that, before going to “testing” section for any platform.&lt;/p&gt;

&lt;h1&gt;
  
  
  iOS Setup
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Enroll in Apple Developer Program
&lt;/h3&gt;

&lt;p&gt;If you want to send a &lt;strong&gt;remote notification&lt;/strong&gt;, even just for testing purposes, you have to be enrolled in Apple's developer program. It costs $100 for a year, but if you want to publish your app in App Store you would need to do it anyway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable push notification
&lt;/h3&gt;

&lt;p&gt;Open your project in Xcode. I’m using RN &amp;gt; 0.60 so I open &lt;code&gt;PushNotificationsWixDemo.xcworkspace&lt;/code&gt;. Go to Xcode project settings -&amp;gt; Capabilities and turn on Push Notifications (see &lt;a href="https://help.apple.com/xcode/mac/current/#/dev88ff319e7"&gt;Add a capability to a target&lt;/a&gt;). To see this option in Capabilities menu, you need to be logged into Xcode with your Apple ID which is enrolled in the Apple developer program as I mentioned before. &lt;a href="https://developer.apple.com/support/app-capabilities/"&gt;Advanced App Capabilities&lt;/a&gt; shows what kind of developer account you need for a specific capability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Certificate
&lt;/h3&gt;

&lt;p&gt;You need to create a TLS certificate to be able to communicate with APNs. You can do that in your &lt;a href="https://developer.apple.com/account/"&gt;Apple Developer Account&lt;/a&gt; page in Certificates, Identifiers &amp;amp; Profiles section. &lt;/p&gt;

&lt;p&gt;Before you start, you need to &lt;a href="https://help.apple.com/developer-account/#/devbfa00fef7"&gt;Create a certificate signing request&lt;/a&gt; (don’t forget to fill in “Common Name” field, otherwise, the certificate created from such CSR won’t work). When you have one, for example, &lt;code&gt;CertificateSigningRequest.certSigningRequest&lt;/code&gt;, continue with creating the certificate as described in &lt;a href="https://help.apple.com/developer-account/#/dev82a71386a"&gt;Communicate with APNs using a TLS certificate&lt;/a&gt;. When asked for Certificate type, just select Development SSL Certificate, that’s good enough for playing around with push notifications within your project. For the production version of the app distributed via App Store and even for beta testing via TestFlight you would need to create a Production SSL Certificate.&lt;/p&gt;

&lt;p&gt;During this process, you’ll create, download and add  &lt;code&gt;cer&lt;/code&gt; file into your Keychain. Then you’ll export &lt;code&gt;p12&lt;/code&gt; file which we will use later for testing push notifications.&lt;/p&gt;

&lt;p&gt;NOTE: While writing this article, I found there is another option: &lt;a href="https://help.apple.com/developer-account/#/deva05921840"&gt;Communicate with APNs using authentication tokens&lt;/a&gt;, but I haven’t tried it.&lt;/p&gt;

&lt;p&gt;Other useful resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://help.apple.com/xcode/mac/current/#/devdfd3d04a1"&gt;Enable push notifications&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fluffy.es/remote-push-notification-testflight-app-store/"&gt;Sending remote push notification to app in  Testflight / App Store&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  React Native Setup
&lt;/h3&gt;

&lt;p&gt;Continue with other steps in &lt;a href="https://wix.github.io/react-native-notifications/docs/getting-started#ios"&gt;React Native Notifications Getting Started Guide · React native notifications&lt;/a&gt; related to iOS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pod install —project-directory=ios/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;AppDelegate.m&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Android Setup
&lt;/h1&gt;

&lt;p&gt;As I mentioned before, Android is using FCM for push notification delivery. I would say it’s more straightforward. You just need a Google Account to log in to Firebase Console and create a project for Android there. There is one thing that could be a bit confusing. You can set up and use FCM also for other platforms such as iOS, web, C++ or Unity, but this only means that FCM could work also as a Notification Provider from our diagram. It’s not a replacement for APNs service and you would need to do iOS setup described above anyway.&lt;/p&gt;

&lt;p&gt;SIDE NOTE: As of April 10, 2018, Google deprecated GCM. Then removed the GCM server and client APIs by April 11, 2019. You need to migrate GCM apps to Firebase Cloud Messaging if you’ve used it before. That’s also the reason why you can spot GCM from time to time, in dependencies or as an attribute in message payloads for example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Firebase Project
&lt;/h3&gt;

&lt;p&gt;If you want to send push notifications to Android, you would need to create a project in Firebase Console &lt;a href="https://console.firebase.google.com/"&gt;Firebase Console&lt;/a&gt; and register your app there (as described at &lt;a href="https://firebase.google.com/docs/android/setup#console"&gt;Add Firebase to your Android project | Firebase&lt;/a&gt; step 1., 2. and 3. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Step 1: Create a Firebase project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add Project&lt;/li&gt;
&lt;li&gt;Project name push-notifications-wix-demo&lt;/li&gt;
&lt;li&gt;Turn off “Enable Google Analytics for this project"&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Step 2: Register your app with Firebase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android package name: com.pushnotificationswixdemo (you can find it in &lt;code&gt;android/app/build.gradle&lt;/code&gt; file, android -&amp;gt; defaultConfig -&amp;gt; applicationId)&lt;/li&gt;
&lt;li&gt;App nickname (optional): Push Notifications Wix Demo&lt;/li&gt;
&lt;li&gt;Register app&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Step 3: Add a Firebase configuration file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;code&gt;google-services.json&lt;/code&gt; and put it into &lt;code&gt;PROJECT_DIR/android/app/&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;PROJECT_DIR/android/build.gradle&lt;/code&gt; and  &lt;code&gt;PROJECT_DIR/android/app/build.gradle&lt;/code&gt; files. Beware that there might be differences in specific versions defined in Firebase console and &lt;a href="https://wix.github.io/react-native-notifications/docs/installation-android"&gt;Android Installation · React native notifications&lt;/a&gt;. I usually try to set the Gradle files according to current Firebase console recommendations and downgrade if it doesn’t work with React Native notification library.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  React Native Setup
&lt;/h3&gt;

&lt;p&gt;Continue with other steps in &lt;a href="https://wix.github.io/react-native-notifications/docs/installation-android"&gt;Android Installation · React native notifications&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the library to your application class (e.g. MainApplication.java)&lt;/li&gt;
&lt;li&gt;Link react-native-notifications in &lt;code&gt;PROJECT_DIR/android/settings.gradle&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you should have everything set up correctly. Open Android Studio and try to build your app as a sanity check whether you have correct dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Android Client Setup Under the Hood
&lt;/h3&gt;

&lt;p&gt;There is more information about &lt;a href="https://firebase.google.com/docs/cloud-messaging/android/client"&gt;Set up a Firebase Cloud Messaging client app on Android | Firebase&lt;/a&gt; and &lt;a href="https://developers.google.com/android/reference/com/google/firebase/messaging/FirebaseMessagingService.html"&gt;FirebaseMessagingService | Google APIs for Android | Google Developers&lt;/a&gt;, but  &lt;code&gt;wix/react-native-notifications&lt;/code&gt; library does a lot of it for you and you don’t have to worry about it. I’m adding it just for reference. I found it interesting to know what’s under the hood.&lt;/p&gt;

&lt;h1&gt;
  
  
  React Native Implementation
&lt;/h1&gt;

&lt;p&gt;Create &lt;code&gt;PushNotificationsManager.js&lt;/code&gt; file with following content and add it into your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Platform&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Notifications&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native-notifications&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;PushNotificationManager&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;componentDidMount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;registerDevice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;registerNotificationEvents&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;registerDevice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;registerRemoteNotificationsRegistered&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// TODO: Send the token to my server so it could send back push notifications...&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Device Token Received&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deviceToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nx"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;registerRemoteNotificationsRegistrationFailed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nx"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;registerRemoteNotifications&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;registerNotificationEvents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;registerNotificationReceivedForeground&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notification Received - Foreground&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;// Calling completion on iOS with `alert: true` will present the native iOS inApp notification.&lt;/span&gt;
      &lt;span class="nx"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;badge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nx"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;registerNotificationOpened&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notification opened by device user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Notification opened with an action identifier: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nx"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;registerNotificationReceivedBackground&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Notification Received - Background&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="c1"&gt;// Calling completion on iOS with `alert: true` will present the native iOS inApp notification.&lt;/span&gt;
      &lt;span class="nx"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;alert&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="na"&gt;sound&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="na"&gt;badge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nx"&gt;Notifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getInitialNotification&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notification&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Initial notification was:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;notification&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;N/A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getInitialNotifiation() failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&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;Add &lt;code&gt;PushNotificationManager&lt;/code&gt; into  &lt;code&gt;App.js&lt;/code&gt; file like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-native&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-redux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PushNotificationManager&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pushNotifications&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RootScreen&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PushNotificationManager&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RootScreen&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;View&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;PushNotificationManager&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Testing iOS Push Notifications
&lt;/h1&gt;

&lt;p&gt;To test push notifications on iOS you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start the app: currently, it's not possible to test remote push notifications by running the app in Simulator, so you have to start the app from Xcode and run it on a connected device. It should change in the future versions of Xcode (see &lt;a href="https://medium.com/better-programming/how-to-send-push-notifications-to-the-ios-simulator-2988092ba931"&gt;How to Send Push Notifications to the iOS Simulator&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Device Token: in this demo project, we’re just logging it into the browser console in the &lt;code&gt;registerDevice&lt;/code&gt; method, you can just copy it from there. In real world, you would send a token to your Notification Provider and then send a notification from there.&lt;/li&gt;
&lt;li&gt;Get TLS certificate: We’ve created such certificate in the iOS Setup -&amp;gt; Create Certificate section of this article.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can test push notifications just by sending an HTTP request directly to APNs via &lt;code&gt;curl&lt;/code&gt;. But first, we need to generate &lt;code&gt;.pem&lt;/code&gt; from our &lt;code&gt;.p12&lt;/code&gt; which we will send with that request. &lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;.pem&lt;/code&gt; from &lt;code&gt;.p12&lt;/code&gt; certificate file via &lt;code&gt;openssl&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openssl pkcs12 -nodes -clcerts -in Certificates.p12 -out Certificates.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're confused what these files and file extensions mean, try to look at &lt;a href="https://security.stackexchange.com/questions/183072/pem-cer-crt-p12-what-is-it-all-about"&gt;certificates - PEM, CER, CRT, P12 - what is it all about? - Information Security Stack Exchange&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After that, you can send the HTTP request by the following command (just replace &lt;code&gt;abcd&lt;/code&gt; with a password you set for the &lt;code&gt;.pem&lt;/code&gt; certificate in the previous step):&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;-v&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"aps":{"alert": {"title": "Game Request", "body": "Bob wants to play poker"},"sound":"default"}, "data": "some custom data"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"apns-topic:PROJECT_BUNDLE_IDENTIFIER"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"apns-expiration: 1"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"apns-priority: 10"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--http2&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cert&lt;/span&gt; CERTIFICATE_FILE_PATH:CERTIFICATE_PASS &lt;span class="se"&gt;\&lt;/span&gt;
  https://api.development.push.apple.com/3/device/DEVICE_TOKEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other useful resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/@kavithakumarasamy89/testing-your-ios-apns-certificate-a-developers-help-guide-d06c0f8d10d"&gt;Testing your iOS APNS certificate — A developer’s help guide.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html"&gt;Local and Remote Notification Programming Guide: Creating the Remote Notification Payload&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Testing Android Push Notifications
&lt;/h1&gt;

&lt;p&gt;To test push notifications on Android you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start the app: you can use an emulator or connected device.&lt;/li&gt;
&lt;li&gt;Get Device Token: in this demo project, we’re just logging it into the browser console in the &lt;code&gt;registerDevice&lt;/code&gt; method, you can just copy it from there. In real world, you would send a token to your Notification Provider and then send a notification from there.&lt;/li&gt;
&lt;li&gt;Get Server Key: you will find it in your project's Project Settings -&amp;gt; Cloud Messaging -&amp;gt; Server key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first option to try whether it works is to go into your project in &lt;a href="https://console.firebase.google.com/"&gt;Firebase console&lt;/a&gt;. Go to Cloud Messaging -&amp;gt; Notifications tab -&amp;gt; New notification. This approach has one problem. It doesn’t work for initial notifications, which are a special case of background notifications when your app is closed and you open it by tapping on the notification in notification center. The reason is that Android distinguishes two types of push notification message:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Notification Message&lt;/li&gt;
&lt;li&gt;Data Message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main difference is whether the message payload contains &lt;code&gt;notification&lt;/code&gt; or &lt;code&gt;data&lt;/code&gt; attribute. To send a notification that can be processed as initial notification, you would need to put &lt;code&gt;data&lt;/code&gt; attribute into the payload, but I didn’t find out how to send Data message via Firebase console. You can find more details in the following links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://firebase.google.com/docs/cloud-messaging/concept-options"&gt;About FCM messages | Firebase&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://firebase.google.com/docs/cloud-messaging/android/receive"&gt;Receive messages in an Android app | Firebase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/37711082/how-to-handle-notification-when-app-in-background-in-firebase"&gt;android - How to handle notification when app in background in Firebase - Stack Overflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/37358462/firebase-onmessagereceived-not-called-when-app-in-background"&gt;android - Firebase onMessageReceived not called when app in background - Stack Overflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully, we can use the good old pure HTTP request via &lt;code&gt;curl&lt;/code&gt; or Postman (&lt;a href="https://medium.com/android-school/test-fcm-notification-with-postman-f91ba08aacc3"&gt;Test FCM Notification with POSTMAN! - Android School - Medium&lt;/a&gt;) for example. Here is the &lt;code&gt;curl&lt;/code&gt; command I use:&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="se"&gt;\&lt;/span&gt;
  https://fcm.googleapis.com/fcm/send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Authorization: key=SERVER_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Host: fcm.googleapis.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
 "to" : "DEVICE_TOKEN",
 "data" : {
     "body" : "Body of Your Notification in Data",
     "title": "Title of Your Notification in Title",
     "key_1" : "Value 1",
     "key_2" : "Value 1"
 }
}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is documentation for the &lt;a href="https://firebase.google.com/docs/cloud-messaging/http-server-ref"&gt;Firebase Cloud Messaging HTTP protocol&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When you run the command, you should get the notification into your Android. The notification should appear in system notification center and in the console log. Even if the app is not running, you should get the notification and see it as an initial notification in the browser’s console log after opening the app by tapping on the notification. &lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Whichever React Native library you choose, you still need to know how to set up push notifications specifically for a given platform.&lt;/li&gt;
&lt;li&gt;There are various types of push notifications (foreground/background, local/remote - this article focuses on remote notifications, …).&lt;/li&gt;
&lt;li&gt;You can send push notifications for each platform by sending an HTTP request via &lt;code&gt;curl&lt;/code&gt; command. The difference is in the authentication mechanism with a certificate for iOS and Serve key for Android. The setup is vastly different for each platform. &lt;/li&gt;
&lt;li&gt;Android:

&lt;ul&gt;
&lt;li&gt;You have to create a project in Firebase console and add the Android app to get push notifications key. You can also add the iOS app, but it's not necessary. You would still need to set your APNs authentication key and register for remote notifications for iOS anyway.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;iOS: 

&lt;ul&gt;
&lt;li&gt;You must be enrolled in Apple Developer Program if you want to send remote notifications. 

&lt;ul&gt;
&lt;li&gt;You need to set your APNs authentication key or certificate and register for remote notifications in your project.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;It’s not possible to send a push notification into an app running on Simulator.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope I provided you at least a good overview of what you need to know to use push notifications on both Android and iOS platforms via React Native library. My goal wasn’t to describe all the steps in detail but to put together pieces of information and links I’ve gathered while setting up push notifications. &lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>pushnotifications</category>
    </item>
    <item>
      <title>How to build VCX iOS library </title>
      <dc:creator>jakubkoci</dc:creator>
      <pubDate>Fri, 31 Jan 2020 21:50:49 +0000</pubDate>
      <link>https://forem.com/jakubkoci/how-to-build-a-vcx-ios-library-f32</link>
      <guid>https://forem.com/jakubkoci/how-to-build-a-vcx-ios-library-f32</guid>
      <description>&lt;p&gt;VCX is part of Hyperledger’s &lt;a href="https://www.hyperledger.org/projects/hyperledger-indy" rel="noopener noreferrer"&gt;Indy&lt;/a&gt; and &lt;a href="https://www.hyperledger.org/projects/aries" rel="noopener noreferrer"&gt;Aries&lt;/a&gt; projects. It’s a library for exchange of verifiable credentials written in Rust. It has also c-callable API with wrappers for iOS, Java, Node and other languages.&lt;br&gt;
Our team needed to build the iOS static library from scratch and I decided to write down some notes from the process. The description of the build process is not only a good help for those who need the same, but it’s also good for understanding the build process itself which can be useful for any other library.&lt;/p&gt;

&lt;p&gt;I won’t go into details describing all commands, I just want to provide a high-level description. If you want to see specifics, go to this repo &lt;a href="https://github.com/jakubkoci/indy-vcx-build" rel="noopener noreferrer"&gt;jakubkoci/indy-vcx-build&lt;/a&gt; with the final Bash script or look at these two links which were my inspiration (thank you to all authors for their contribution):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/hyperledger/indy-sdk/blob/master/vcx/libvcx/build_scripts/ios/mac/README.txt" rel="noopener noreferrer"&gt;indy-sdk/README.txt at master · hyperledger/indy-sdk · GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/faisal00813/indy-sdk-android/blob/master/android.build.sh" rel="noopener noreferrer"&gt;indy-sdk-android/android.build.sh at master · faisal00813/indy-sdk-android · GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Prerequisities
&lt;/h2&gt;

&lt;p&gt;You need to run a build script on Mac OS with Rust and some other libraries installed. You will find everything described in the &lt;a href="https://github.com/jakubkoci/indy-vcx-build/blob/master/setup.sh" rel="noopener noreferrer"&gt;setup.sh&lt;/a&gt; script.&lt;/p&gt;
&lt;h2&gt;
  
  
  Goal
&lt;/h2&gt;

&lt;p&gt;At the end of the process, we want to have a &lt;code&gt;vcx.framework&lt;/code&gt; folder containing a binary file compiled for all required architectures together. This binary file will be combined from &lt;code&gt;libvcx&lt;/code&gt; library and all its dependencies &lt;code&gt;libindy&lt;/code&gt;, &lt;code&gt;libssl&lt;/code&gt;, &lt;code&gt;libcrypto&lt;/code&gt;, &lt;code&gt;libsodium&lt;/code&gt; and &lt;code&gt;libzmq&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Architectures
&lt;/h2&gt;

&lt;p&gt;Whenever you want to build a native library, you need to select the architecture a.k.a type of processor of a device where your app, and therefore library, will be running. There are usually following options for iOS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;arm64&lt;/code&gt; (&lt;code&gt;aarch64-apple-ios&lt;/code&gt;): 64-bit ARM processor in iPhone 5s, iPad Air and newer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;armv7s&lt;/code&gt; (&lt;code&gt;armv7s-apple-ios&lt;/code&gt;): 32-bit ARM processor in iPhone 5.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;armv7&lt;/code&gt; (&lt;code&gt;armv7-apple-ios&lt;/code&gt;): 32-bit ARM processor in iPhone 3GS, 4, 4S.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;x86_64&lt;/code&gt; (&lt;code&gt;x86_64-apple-ios&lt;/code&gt;): 64-bit simulator.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;i386&lt;/code&gt; (&lt;code&gt;i386-apple-ios&lt;/code&gt;): 32-bit simulator.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my case, OpenSSL library supports only two architectures, &lt;code&gt;arm64&lt;/code&gt; for devices and &lt;code&gt;x86_64&lt;/code&gt; for a simulator, so I need to build libraries only for these two.&lt;/p&gt;

&lt;p&gt;You can find more about architectures here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blakespot.com/ios_device_specifications_grid.html" rel="noopener noreferrer"&gt;Blake's iOS Device Specification Grid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ktatsiu.wordpress.com/2016/11/15/about-arm-architectures-for-ios-development/" rel="noopener noreferrer"&gt;About ARM architectures for iOS development – Stanley SIU’s Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.elementscompiler.com/Platforms/Cocoa/CpuArchitectures/" rel="noopener noreferrer"&gt;CPU Architectures&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Build Native Libraries
&lt;/h2&gt;

&lt;p&gt;For every 3rd party library I checkout particular repo and run a build script within it:&lt;/p&gt;
&lt;h3&gt;
  
  
  OpenSSL
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;clone &lt;a href="https://github.com/x2on/OpenSSL-for-iPhone" rel="noopener noreferrer"&gt;https://github.com/x2on/OpenSSL-for-iPhone&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;./build-libssl.sh&lt;/code&gt; which produces both &lt;code&gt;libssl.a&lt;/code&gt; and &lt;code&gt;libcrypto.a&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Libsodium
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;clone &lt;a href="https://github.com/evernym/libsodium-ios" rel="noopener noreferrer"&gt;https://github.com/evernym/libsodium-ios&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;run &lt;code&gt;./libsodium.rb&lt;/code&gt; which produces &lt;code&gt;libsodium.a&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  ZMQ
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;clone &lt;a href="https://github.com/evernym/libzmq-ios" rel="noopener noreferrer"&gt;https://github.com/evernym/libzmq-ios&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;run &lt;code&gt;./libzmq.rb&lt;/code&gt; -&amp;gt; which produces &lt;code&gt;libzmq.a&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Libindy
&lt;/h3&gt;

&lt;p&gt;I take similar steps with &lt;code&gt;libindy&lt;/code&gt;, but on top of cloning the repo, I also checkout the required version by tag:&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;git clone git clone https://github.com/hyperledger/indy-sdk
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;indy-sdk/libindy
&lt;span class="nv"&gt;$ &lt;/span&gt;git checkout &lt;span class="nv"&gt;$INDY_VERSION&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;cargo lipo —release —targets&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"aarch64-apple-ios,x86_64-apple-ios”
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can spot that instead of architectures &lt;code&gt;arm64&lt;/code&gt; or &lt;code&gt;x86_64&lt;/code&gt; I use &lt;code&gt;aarch64-apple-ios, x86_64-apple-ios&lt;/code&gt;. I call them triplets. Some libraries use the first architecture format, some use triplets, but you can see the mapping between architectures and triplets in the Architectures section above. &lt;/p&gt;

&lt;p&gt;You can find more about architectures here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blakespot.com/ios_device_specifications_grid.html" rel="noopener noreferrer"&gt;Blake's iOS Device Specification Grid&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ktatsiu.wordpress.com/2016/11/15/about-arm-architectures-for-ios-development/" rel="noopener noreferrer"&gt;About ARM architectures for iOS development – Stanley SIU’s Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.elementscompiler.com/Platforms/Cocoa/CpuArchitectures/" rel="noopener noreferrer"&gt;CPU Architectures&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Lipo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://ss64.com/osx/lipo.html" rel="noopener noreferrer"&gt;Lipo&lt;/a&gt; is a command-line tool that allows us to create universal binary with more architectures in one file (called Universal Static Library, or just “fat file”). We can also use it for extracting one universal file into more files according to given architecture (“non-fat file”).&lt;/p&gt;

&lt;p&gt;If you check the output library with &lt;code&gt;lipo&lt;/code&gt; you will see whether it’s a fat-file or not, and what architectures it contains.&lt;/p&gt;

&lt;p&gt;For example, in our case:&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;lipo &lt;span class="nt"&gt;-info&lt;/span&gt; output/libsodium-ios/dist/ios/lib/libsodium.a
Architectures &lt;span class="k"&gt;in &lt;/span&gt;the fat file: output/libsodium-ios/dist/ios/lib/libsodium.a are: armv7 armv7s i386 x86_64 arm64 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or, for &lt;code&gt;libindy&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;lipo &lt;span class="nt"&gt;-info&lt;/span&gt; output/indy-sdk/libindy/target/aarch64-apple-ios/release/libindy.a
Non-fat file: output/indy-sdk/libindy/target/aarch64-apple-ios/release/libindy.a is architecture: arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run this command for every library you’ll see that all 3rd party libraries are fat files with all architectures, but  &lt;code&gt;libindy&lt;/code&gt; has been built as non-fat files. We need to extract architectures from fat-files to non-fat files:&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;lipo &lt;span class="nt"&gt;-extract&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; ../&lt;span class="nv"&gt;$FILE_PATH&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/&lt;span class="nv"&gt;$FILE_NAME&lt;/span&gt;&lt;span class="nt"&gt;-fat&lt;/span&gt;.a
&lt;span class="nv"&gt;$ &lt;/span&gt;lipo &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/&lt;span class="nv"&gt;$FILE_NAME&lt;/span&gt;&lt;span class="nt"&gt;-fat&lt;/span&gt;.a &lt;span class="nt"&gt;-thin&lt;/span&gt; &lt;span class="nv"&gt;$arch&lt;/span&gt; &lt;span class="nt"&gt;-output&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arch&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/&lt;span class="nv"&gt;$FILE_NAME&lt;/span&gt;.a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may be confused why there are two steps (extracting — keep output as a fat file with given architecture only, and thinning — create a non-fat file with given architecture). That’s because you need to extract architecture before you thin the file. If you try to thin the file directly, you will get the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: input file (arm64/libzmq.a) must be a fat file when the -thin option is specified
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Libvcx
&lt;/h3&gt;

&lt;p&gt;I also copied &lt;code&gt;libindy&lt;/code&gt; from &lt;code&gt;indy-sdk&lt;/code&gt; to a different directory. Extracting and copying helps us set environment variables which are required to build &lt;code&gt;libvcx&lt;/code&gt; in the following way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENSSL_LIB_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$WORK_DIR&lt;/span&gt;/libs/openssl/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;IOS_SODIUM_LIB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$WORK_DIR&lt;/span&gt;/libs/sodium/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;IOS_ZMQ_LIB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$WORK_DIR&lt;/span&gt;/libs/zmq/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;LIBINDY_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$WORK_DIR&lt;/span&gt;/libs/indy/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

cargo build —target “&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TRIPLET&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;” &lt;span class="nt"&gt;--release&lt;/span&gt; &lt;span class="nt"&gt;--no-default-features&lt;/span&gt; —features “ci”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Combine It All
&lt;/h2&gt;

&lt;p&gt;Now, we have all libraries &lt;code&gt;libssl&lt;/code&gt;, &lt;code&gt;libcrypto&lt;/code&gt;, &lt;code&gt;libsodium&lt;/code&gt;, &lt;code&gt;libzmq&lt;/code&gt;, &lt;code&gt;libindy&lt;/code&gt; and &lt;code&gt;libvcx&lt;/code&gt; separated by architecture. What we want is one file with all libraries for all architectures. This part is too code heavy to describe it here. In general, we first combine all libraries for given platform and then create a fat file with all architectures with &lt;code&gt;lipo&lt;/code&gt;. I prepared a simple drawing describing it:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F9xusrdcss3ulqaeoooej.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F9xusrdcss3ulqaeoooej.png" alt="Alt Process of extracting and combining native libraries"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This still not over. To call output &lt;code&gt;libvcxall.a&lt;/code&gt; library from our code we need to wrap it with Objective-C and c-callable headers. First, we copy the &lt;code&gt;libvcxall.a&lt;/code&gt; to &lt;code&gt;indy-sdk/vcx/wrappers/ios/vcx&lt;/code&gt; which contains these headers and then we use &lt;code&gt;xcodebuild&lt;/code&gt; and &lt;code&gt;lipo&lt;/code&gt; utility to create our final &lt;code&gt;vcx.framework&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Yes, we’re finally done. I hope you find it helpful even if you don’t need to build the library by yourself, but were curious about the process.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>vcx</category>
      <category>indy</category>
    </item>
    <item>
      <title>What's Wrong With Agile Development</title>
      <dc:creator>jakubkoci</dc:creator>
      <pubDate>Mon, 23 Dec 2019 15:41:42 +0000</pubDate>
      <link>https://forem.com/jakubkoci/what-s-wrong-with-agile-development-2gam</link>
      <guid>https://forem.com/jakubkoci/what-s-wrong-with-agile-development-2gam</guid>
      <description>&lt;p&gt;It's been a while since I've heard an amazing episode of JavaScript Jabber podcast about agile development &lt;a href="https://devchat.tv/js-jabber/jsj-349-agile-development-the-technical-side-with-james-shore/"&gt;JSJ 349: Agile Development - The Technical Side with James Shore&lt;/a&gt;. The ideas from that episode are coming up again and again, not only in my mind but also in discussions with other developers about the software development process. I decided to summarize my key takeaways from that episode in this short blog post:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Scrum masters aren’t there to charge but to enable. Perhaps, they should be just a temporary role until the team is self-organized in the process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scrum certifications are unfortunately more about the business that has been built around it rather than bringing actual value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Agile tends to be more focused on how to organize rather than how to do the actual work. We need to discuss the technical side of agile more.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start with one particular method (XP recommended), but always be focused mainly on the basic ideas from Agile manifesto.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Agile manifesto values some things more than others, but it doesn’t mean that the other parts are not important or useful.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Software development is not a sprint, it’s a marathon. Try to imagine athletes to run one sprint after another. Don't count weekends as a pause between sprints. Look at &lt;a href="https://3.basecamp-help.com/article/35-the-six-week-cycle"&gt;The Six Week Cycle&lt;/a&gt; by Basecamp for an example of a different approach.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agile is about shortening the feedback loop with a focus on delivering value to the customer according to values in &lt;a href="https://agilemanifesto.org/"&gt;Agile Manifesto&lt;/a&gt;. Keep it in mind whenever introducing some process or technique from any agile methodology.&lt;/p&gt;

</description>
      <category>agile</category>
      <category>scrum</category>
      <category>xp</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Polling with async/await</title>
      <dc:creator>jakubkoci</dc:creator>
      <pubDate>Thu, 19 Sep 2019 07:28:50 +0000</pubDate>
      <link>https://forem.com/jakubkoci/polling-with-async-await-25p4</link>
      <guid>https://forem.com/jakubkoci/polling-with-async-await-25p4</guid>
      <description>&lt;p&gt;This article is based on my real experience with refactoring a small piece of code with polling function so I won’t be starting from the scratch. I know its not rocket science, but I was looking for the solution for polling in the past and I found similar articles very helpful. It’s also a nice demonstration of how &lt;code&gt;async/await&lt;/code&gt; and higher-order functions could help to code maintainability and readability.&lt;/p&gt;

&lt;p&gt;I have been using the following piece of code for some polling functionality for a while.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;originalPoll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;checkCondition&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;result&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;checkCondition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;end&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="nx"&gt;checkCondition&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;It takes function &lt;code&gt;fn&lt;/code&gt; and calls it every 3 seconds until it gets required result (I simplified it here to a condition &lt;code&gt;result &amp;lt; 3&lt;/code&gt;), then it calls callback &lt;code&gt;end&lt;/code&gt; passed as the second parameter. The function somehow works and does what I need. But, it’s not possible to re-use it with a different condition. So I decided to refactor it a little bit. After a few minutes of thinking and tweaking I finally ended up with this simplification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fnCondition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fnCondition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`waiting &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ms...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&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 still calls the &lt;code&gt;fn&lt;/code&gt; function repeatedly, but now it takes also another parameter &lt;code&gt;fnCondition&lt;/code&gt; which is called with the result of calling the &lt;code&gt;fn&lt;/code&gt; function. Function &lt;code&gt;poll&lt;/code&gt; will be calling the function &lt;code&gt;fn&lt;/code&gt; until the function &lt;code&gt;fnCondition&lt;/code&gt; returns &lt;code&gt;false&lt;/code&gt;. I also extracted &lt;code&gt;setTimeout&lt;/code&gt; function, it improves the readability of the polling function and keeps its responsibility straightforward (I don’t care how the waiting is implemented at this abstraction level). We also got rid of function inside a function which just added unnecessary complexity.&lt;/p&gt;

&lt;p&gt;I didn’t start with a test first to be honest. Anyway, I still wanted to check my design, provide some safety for the future refactoring and also to document how to call the &lt;code&gt;poll&lt;/code&gt; function. We can nicely achieve all of that by adding some tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;poll&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;returns result of the last call&lt;/span&gt;&lt;span class="dl"&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;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createApiStub&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fnCondition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;finalResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fnCondition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalResult&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;calls api many times while condition is satisfied&lt;/span&gt;&lt;span class="dl"&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;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createApiStub&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fnCondition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fnCondition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toHaveBeenCalledTimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;createApiStub&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testApi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;calling api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;testApi&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;I’m using Jest as a testing library. It has great support for testing async functions and provides stubs with assertions by default. Function &lt;code&gt;createApiStub&lt;/code&gt; is here just for the purpose of the test and assertions and it'll represent our real API call or whatever function we would want to poll.&lt;/p&gt;

&lt;p&gt;You can find and run the code in this CodeSandbox: &lt;a href="https://codesandbox.io/s/ovqop57mzy"&gt;Polling with async/await - CodeSandbox&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>asyncawait</category>
      <category>polling</category>
    </item>
  </channel>
</rss>
