<?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: aseem wangoo</title>
    <description>The latest articles on Forem by aseem wangoo (@aseemwangoo).</description>
    <link>https://forem.com/aseemwangoo</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%2F350539%2Ff657525e-87c9-4131-9ac6-bfbd29e811b5.jpg</url>
      <title>Forem: aseem wangoo</title>
      <link>https://forem.com/aseemwangoo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/aseemwangoo"/>
    <language>en</language>
    <item>
      <title>Using FFIGen in Dart 2.18</title>
      <dc:creator>aseem wangoo</dc:creator>
      <pubDate>Thu, 22 Dec 2022 14:49:40 +0000</pubDate>
      <link>https://forem.com/aseemwangoo/using-ffigen-in-dart-218-2l0h</link>
      <guid>https://forem.com/aseemwangoo/using-ffigen-in-dart-218-2l0h</guid>
      <description>&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;We will cover briefly:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;What’s FFIGen&lt;/li&gt;



&lt;li&gt;What’s new in FFIGen&lt;/li&gt;



&lt;li&gt;Dart CLI App and integrate obj-c-based libraries&lt;/li&gt;



&lt;li&gt;Testing FFIGen &lt;/li&gt;
&lt;/ol&gt;



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

&lt;h3&gt;Wait, what’s FFIGen?&lt;/h3&gt;

&lt;p&gt;Before explaining the answer to this question, the reader needs to know about &lt;code&gt;FFI&lt;/code&gt; (Foreign Function Interface)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s FFI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;FFI enables programs written in one language to call libraries written in other languages. The term &lt;code&gt;FFI&lt;/code&gt; comes from &lt;a href="http://wiki.c2.com/?CommonLisp" rel="noreferrer noopener"&gt;CommonLisp&lt;/a&gt;, however, it’s applicable to any language. Some languages such as Java, use FFI in their ecosystem and call it &lt;a href="http://wiki.c2.com/?JavaNativeInterface" rel="noreferrer noopener"&gt;JavaNativeInterface&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If we refer to the low-level language as the “&lt;strong&gt;host&lt;/strong&gt;” language and the high-level language as the “&lt;strong&gt;guest&lt;/strong&gt;” language, below are the ways to communicate between them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;The host is expected to bridge the gap with the guest. We write host-language functions specifically to be called by the guest. An API is offered for the host language to communicate with guests.&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;em&gt;The gap is bridged by some kind of tool that does not belong strictly to either the host or guest languages.&lt;/em&gt;&lt;/li&gt;



&lt;li&gt;&lt;em&gt;The guest is also expected to bridge the gap with the host. Guest language can call any host-language function, but it needs to support many low-level features, in order to communicate with the host language effectively.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;According to Wikipedia, these are the things to consider for FFI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If one language supports garbage collection (GC) and the other does not; care must be taken that the non-GC language code does nothing to cause GC in the other to fail.&lt;/li&gt;



&lt;li&gt;Complicated or non-trivial objects or datatypes may be difficult to map from one environment to another.&lt;/li&gt;



&lt;li&gt;One or both languages may be running on a &lt;a href="https://en.wikipedia.org/wiki/Virtual_machine" rel="noreferrer noopener"&gt;virtual machine&lt;/a&gt; (VM); moreover, if both are, these will probably be different VMs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fortunately, we are able to use &lt;strong&gt;FFI &lt;/strong&gt;in Dart through the &lt;code&gt;dart:ffi&lt;/code&gt;library. With Dart v2.12 onwards, &lt;a href="https://medium.com/dartlang/announcing-dart-2-12-499a6e689c87" rel="noreferrer noopener"&gt;&lt;strong&gt;Dart FFI&lt;/strong&gt;&lt;/a&gt; is available on the stable channel. Dart FFI allows you to use the existing code in C libraries. By using FFI we can avail the benefits of both portability and integration of highly tuned C code for performance-intensive tasks. We are not limited to &lt;code&gt;C&lt;/code&gt; , in fact, we can write the code in any language that is compiled to the C library, for instance &lt;code&gt;Go, Rust&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Another use case for using Dart FFI can be there are times when the Flutter app needs to have greater control over memory management and garbage collection, for instance, an app using tensor flow.&lt;/p&gt;

&lt;p&gt;Dart FFI can be used to read, write, allocate and deallocate the native memory. There are some packages that already used this feature:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;&lt;a href="https://pub.dev/packages/file_picker" rel="noreferrer noopener"&gt;file_picker&lt;/a&gt;&lt;/code&gt;, &lt;code&gt;&lt;a href="https://pub.dev/packages/printing" rel="noreferrer noopener"&gt;printing&lt;/a&gt;&lt;/code&gt;, &lt;code&gt;&lt;a href="https://pub.dev/packages/win32" rel="noreferrer noopener"&gt;win32&lt;/a&gt;&lt;/code&gt;, &lt;code&gt;&lt;a href="https://pub.dev/packages/objectbox" rel="noreferrer noopener"&gt;objectbox&lt;/a&gt;&lt;/code&gt;, &lt;code&gt;&lt;a href="https://pub.dev/packages/realm" rel="noreferrer noopener"&gt;realm&lt;/a&gt;&lt;/code&gt;, &lt;code&gt;&lt;a href="https://pub.dev/packages/isar" rel="noreferrer noopener"&gt;isar&lt;/a&gt;&lt;/code&gt;, &lt;code&gt;&lt;a href="https://pub.dev/packages/tflite_flutter" rel="noreferrer noopener"&gt;tflite_flutter&lt;/a&gt;&lt;/code&gt;, and &lt;code&gt;&lt;a href="https://pub.dev/packages/dbus" rel="noreferrer noopener"&gt;dbus&lt;/a&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;Ways of using Dart FFI&lt;/h4&gt;

&lt;p&gt;There are times when you want to create your own fresh library, but the maximum number of times, the library would already exist (created by some other team) and you simply want to use it. In either of the cases, we have the following choices&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manually creating the FFI bindings&lt;/li&gt;



&lt;li&gt;Automatically generating the FFI bindings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you like automation, you probably chose the second option, and as a result, we have &lt;code&gt;&lt;a href="https://pub.dev/packages/ffigen" rel="noreferrer noopener"&gt;package:ffigen&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The idea behind the package &lt;code&gt;ffigen&lt;/code&gt; is: For large APIs, it can be very time-consuming to write the Dart bindings which allow the integration with the C code. Hence, the Dart team came up with a binding generator (&lt;strong&gt;ffigen&lt;/strong&gt;) that automatically creates the FFI wrappers out of the C header files.&lt;/p&gt;

&lt;p&gt;Under the hood, this package uses &lt;a href="https://medium.datadriveninvestor.com/whats-llvm-4c0c3ed43a72" rel="noreferrer noopener"&gt;LLVM&lt;/a&gt; and &lt;code&gt;LibClang&lt;/code&gt; to parse C header files. For installing LLVM inside &lt;code&gt;macOS&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;brew install llvm&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are multiple types provided by &lt;code&gt;dart:ffi&lt;/code&gt; for representing the types in C. However, they broadly are classified in&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instantiable Native Types&lt;/li&gt;



&lt;li&gt;Purely marker Native Types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instantiable Native Types: They or their subtypes can be instantiated in the Dart Code. For instance, &lt;code&gt;Array&lt;/code&gt; &lt;code&gt;Pointer&lt;/code&gt; &lt;code&gt;Struct&lt;/code&gt; &lt;code&gt;Union&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Purely marker Native Types: They are platform agnostic and cannot be instantiated in the Dart Code. For instance, &lt;code&gt;Bool&lt;/code&gt; &lt;code&gt;Double&lt;/code&gt; &lt;code&gt;Int64&lt;/code&gt; &lt;code&gt;Int32&lt;/code&gt; etc&lt;/p&gt;

&lt;p&gt;There are also &lt;a href="https://api.dart.dev/stable/dart-ffi/Abi-class.html" rel="noreferrer noopener"&gt;ABI&lt;/a&gt; marker types that extend &lt;code&gt;AbiSpecificInteger&lt;/code&gt; For instance &lt;code&gt;Size&lt;/code&gt; &lt;code&gt;Short&lt;/code&gt; etc&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Until now, we have covered what’s &lt;strong&gt;FFI&lt;/strong&gt; and what’s &lt;strong&gt;ffigen&lt;/strong&gt;, let’s explore what’s new inside &lt;em&gt;ffigen from Dart 2.18&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;What’s new in FFIGen&lt;/h3&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A__o2z4PlwKCYgCNo" 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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A__o2z4PlwKCYgCNo" alt="Dart 2.18"&gt;&lt;/a&gt;Dart 2.18&lt;/p&gt;

&lt;p&gt;The Dart team wants Dart to support interoperability with all the primary languages on the platforms where Dart runs.&lt;/p&gt;

&lt;p&gt;As of &lt;a href="https://dart.dev/guides/language/evolution#dart-218" rel="noreferrer noopener"&gt;&lt;em&gt;Dart 2.18&lt;/em&gt;&lt;/a&gt;&lt;em&gt; &lt;/em&gt;the &lt;code&gt;Dart&lt;/code&gt; code can now call the Objective-C and Swift code since these are used for writing APIs for macOS and iOS. This interop mechanism is supported across all types of apps (for instance, CLI app to backend app to Flutter code)&lt;/p&gt;

&lt;p&gt;This feature is not limited to command-line apps. Even the Dart mobile, and server apps running on the &lt;a href="https://dart.dev/overview#platform" rel="noreferrer noopener"&gt;Dart Native platform&lt;/a&gt;, on macOS or iOS, can use &lt;code&gt;dart:ffi&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This unlocks the possibilities since before 2.18 it was only possible to call the &lt;code&gt;C/C++&lt;/code&gt;based libraries.&lt;/p&gt;

&lt;p&gt;According to the official blog,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This new mechanism utilizes the fact that Objective-C and Swift code can be exposed as C code based on API bindings. The Dart API wrapper generation tool, &lt;code&gt;&lt;a href="https://pub.dev/packages/ffigen" rel="noreferrer noopener"&gt;ffigen&lt;/a&gt;&lt;/code&gt;, can create these bindings from API headers&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This support for Objective-C and Swift is &lt;strong&gt;marked as experimental starting from &lt;/strong&gt;&lt;code&gt;&lt;strong&gt;Dart 2.18&lt;/strong&gt;&lt;/code&gt; In case someone experiences any problems, they can comment on the &lt;a href="https://github.com/dart-lang/sdk/issues/49673" rel="noreferrer noopener"&gt;feedback issue&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;h3&gt;Dart CLI App with Objective-C-based libraries&lt;/h3&gt;

&lt;p&gt;In this section, we create a Dart-based command line application that demonstrates how to call an Objective-C-based library using the new functionalities from &lt;code&gt;ffigen&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;We will choose any Objective-C library present inside the macOS, and integrate it inside the Dart CLI App.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One such library is &lt;code&gt;&lt;a href="https://developer.apple.com/documentation/foundation/nsurlcache" rel="noreferrer noopener"&gt;NSURLCache&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;macOS has an API for querying URL cache information exposed by the &lt;code&gt;&lt;a href="https://developer.apple.com/documentation/foundation/nsurlcache" rel="noreferrer noopener"&gt;NSURLCache&lt;/a&gt;&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;NSURLCache&lt;/code&gt; implements the caching of responses to URL load requests, by mapping &lt;code&gt;&lt;a href="https://developer.apple.com/documentation/foundation/nsurlrequest" rel="noreferrer noopener"&gt;NSURLRequest&lt;/a&gt;&lt;/code&gt; objects to &lt;code&gt;&lt;a href="https://developer.apple.com/documentation/foundation/nscachedurlresponse" rel="noreferrer noopener"&gt;NSCachedURLResponse&lt;/a&gt;&lt;/code&gt; objects. It provides a composite in-memory and on-disk cache, and lets you manipulate the sizes of both the in-memory and on-disk portions.&lt;/p&gt;

&lt;p&gt;We will be integrating the &lt;code&gt;NSURLCache&lt;/code&gt; inside &lt;code&gt;Dart&lt;/code&gt; and call some of its functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;currentDiskUsage&lt;/code&gt; : The current size of the on-disk cache, in bytes.&lt;/li&gt;



&lt;li&gt;
&lt;code&gt;diskCapacity&lt;/code&gt; : The capacity of the on-disk cache, in bytes.&lt;/li&gt;



&lt;li&gt;
&lt;code&gt;memoryCapacity&lt;/code&gt; : The capacity of the in-memory cache, in bytes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Create Dart CLI App&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We start by creating the Dart CLI App using the below command. Also, upgrade to the latest Dart version &lt;code&gt;2.18&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;dart&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;ffi_2_18&lt;/span&gt;
&lt;span class="ss"&gt;##&lt;/span&gt; &lt;span class="n"&gt;ffi_2_18&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt; &lt;span class="n"&gt;which&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: There are various templates available for Dart, see below. By default, it selects console application.&lt;/p&gt;
&lt;/blockquote&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A-pkYl31cp_Sb8xHzLUN5wA.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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A-pkYl31cp_Sb8xHzLUN5wA.png" alt="Dart Templates"&gt;&lt;/a&gt;Dart Templates&lt;/p&gt;

&lt;p&gt;This gives us a basic template with all the necessary files, for instance, &lt;code&gt;pubspec&lt;/code&gt; or &lt;code&gt;linter&lt;/code&gt; Open the &lt;code&gt;pubspec&lt;/code&gt; file to check the dependencies which come bundled with this template.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dev_dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;lints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.0.0&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.16.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit your &lt;code&gt;pubspec&lt;/code&gt; file to add the &lt;code&gt;&lt;a href="https://pub.dev/packages/ffigen" rel="noreferrer noopener"&gt;ffigen&lt;/a&gt;&lt;/code&gt; dev dependency. Next, specify the configuration under this dependency. &lt;a href="https://pub.dev/packages/ffigen#configurations" rel="noreferrer noopener"&gt;Configurations&lt;/a&gt; can be provided in 2 ways-&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the project’s &lt;code&gt;pubspec.yaml&lt;/code&gt; file under the key &lt;code&gt;ffigen&lt;/code&gt;.&lt;/li&gt;



&lt;li&gt;Via a custom YAML file, then specify this file while running — &lt;code&gt;dart run ffigen --config config.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;We will see the &lt;strong&gt;option 2 first.&lt;/strong&gt; Separate config files for the libraries&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create a file called &lt;code&gt;url_cache_config.yaml&lt;/code&gt; and put the below contents inside it. &lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;URLCacheLibrary&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;objc&lt;/span&gt;
&lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url_cache_bindings.dart"&lt;/span&gt;
&lt;span class="na"&gt;exclude-all-by-default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;objc-interfaces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NSURLCache"&lt;/span&gt;
&lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;entry-points&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSURLCache.h"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s see the above configuration options-&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; The name for the class which will be generated, after we run the &lt;code&gt;ffigen&lt;/code&gt;, this class will be called &lt;code&gt;URLCacheLibrary&lt;/code&gt; &lt;/li&gt;



&lt;li&gt;
&lt;code&gt;language&lt;/code&gt; Must be one of `c`, or ‘objc’. Defaults to ‘c’. Since the library we select is written in Objective-C, we specify &lt;code&gt;objc&lt;/code&gt; &lt;/li&gt;



&lt;li&gt;
&lt;code&gt;output&lt;/code&gt; Output path of the generated bindings. This file will have all the FFI bindings which take care of the functions inside &lt;code&gt;Obj-C&lt;/code&gt;
&lt;/li&gt;



&lt;li&gt;
&lt;code&gt;headers&lt;/code&gt; This includes the path to the &lt;code&gt;header files&lt;/code&gt; It includes everything from the location as specified under the &lt;code&gt;entry-points&lt;/code&gt;In our case, the header files are present inside the &lt;code&gt;Foundation.framework&lt;/code&gt;
&lt;/li&gt;



&lt;li&gt;
&lt;code&gt;exclude-all-by-default&lt;/code&gt; When a declaration filter (eg functions or structs:) is empty, it defaults to including everything. If this flag is enabled, the default behavior is to exclude everything instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Objective-C config options&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;objc-interfaces&lt;/code&gt; This filters for the interface declarations. In our case, we specify the &lt;code&gt;NSURLCache&lt;/code&gt; interface&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;objc-interfaces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Includes a specific interface.&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;NSURLCache'&lt;/span&gt;
    &lt;span class="c1"&gt;# Includes all interfaces starting with "NS".&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;NS.*'&lt;/span&gt;
  &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Override the above NS.* inclusion, to exclude NSURL.&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;NSURL'&lt;/span&gt;
  &lt;span class="na"&gt;rename&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Removes '_' prefix from interface names.&lt;/span&gt;
    &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;_(.*)'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$1'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Generate Bindings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To generate the bindings, run the following:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;dart run ffigen --config url_cache_config.yaml&lt;/span&gt;
&lt;span class="c1"&gt;## url_cache_config is the file which we created above&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a new file (&lt;strong&gt;url_cache_bindings.dart&lt;/strong&gt;) as specified inside the &lt;code&gt;output&lt;/code&gt; parameter of the &lt;code&gt;url_cache_config.yaml&lt;/code&gt;which contains a bunch of generated API bindings. Using this binding file, we can write our Dart &lt;code&gt;main&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integrate into Dart&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We generated the bindings using the &lt;code&gt;ffigen&lt;/code&gt; in the above step. Let’s see how to integrate it inside the &lt;code&gt;Dart&lt;/code&gt; We create a new dart file called &lt;code&gt;url_cache.dart&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Inside this file, we would be loading and interacting with the generated library.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;dylibPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;lib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;URLCacheLibrary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DynamicLibrary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dylibPath&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;urlCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NSURLCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSharedURLCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urlCache&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'currentDiskUsage: &lt;/span&gt;&lt;span class="si"&gt;${urlCache.currentDiskUsage}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'currentMemoryUsage: &lt;/span&gt;&lt;span class="si"&gt;${urlCache.currentMemoryUsage}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'diskCapacity: &lt;/span&gt;&lt;span class="si"&gt;${urlCache.diskCapacity}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'memoryCapacity: &lt;/span&gt;&lt;span class="si"&gt;${urlCache.memoryCapacity}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We mention the path of the library in the first step. Since, the library we are using is an internal library, the &lt;code&gt;dylib&lt;/code&gt; points to the macOS’s framework &lt;code&gt;dylib&lt;/code&gt; We can consider this library to be dynamically linked.&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Arr0NgVo2Gjmx5AC2.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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Arr0NgVo2Gjmx5AC2.png" alt="Library linking"&gt;&lt;/a&gt;Library linking&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: We can also use our own library or a static library (linked inside our app)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Dynamic Linking&lt;/strong&gt;: In this type, the external libraries are placed inside the final executable, however, the actual linking happens at the run time. In dynamic linking, only one copy of the shared library is kept inside the memory which &lt;strong&gt;reduces the program size, memory, and disk space&lt;/strong&gt;. Since the libraries are shared, &lt;strong&gt;dynamic linking programs are slower&lt;/strong&gt; in comparison to static linking programs.&lt;/p&gt;

&lt;p&gt;A dynamically linked library is distributed in a separate file or folder within the app and loaded on demand. A dynamically linked library can be loaded into Dart via &lt;code&gt;DynamicLibrary.open&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Static Linking&lt;/strong&gt;: In this type, the modules are copied inside the program before creating the final executable. Since these programs include libraries, they are &lt;strong&gt;large in size&lt;/strong&gt;. However, because of the libraries already compiled, these programs are &lt;strong&gt;faster than dynamically linked programs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A statically linked library is embedded into the app’s executable image and is loaded when the app starts. Symbols from a statically linked library can be loaded using &lt;code&gt;DynamicLibrary.executable&lt;/code&gt; or &lt;code&gt;DynamicLibrary.process&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next&lt;/strong&gt;, we construct the &lt;code&gt;URLCacheLibrary&lt;/code&gt; by using the constructor which needs the &lt;code&gt;dylib&lt;/code&gt; path. For this, we call the &lt;code&gt;DynamicLibrary.open&lt;/code&gt; This loads the library file and provides the access to its symbols.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This process loads the library into the DartVM only once, regardless of the function calls.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once the library gets initialized, we can call the different methods present inside it (which were generated).&lt;/p&gt;

&lt;p&gt;We are looking for a &lt;code&gt;NSURLCache&lt;/code&gt; class. This class implements the caching of responses to URL load requests, by mapping &lt;code&gt;&lt;a href="https://developer.apple.com/documentation/foundation/nsurlrequest" rel="noreferrer noopener"&gt;NSURLRequest&lt;/a&gt;&lt;/code&gt; objects to &lt;code&gt;&lt;a href="https://developer.apple.com/documentation/foundation/nscachedurlresponse" rel="noreferrer noopener"&gt;NSCachedURLResponse&lt;/a&gt;&lt;/code&gt; objects. For getting an instance of this class, we call &lt;code&gt;sharedURLCache&lt;/code&gt; &lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;urlCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NSURLCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSharedURLCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we have the instance of &lt;code&gt;URLCache&lt;/code&gt; we can access the different methods &lt;code&gt;currentDiskUsage&lt;/code&gt; &lt;code&gt;currentMemoryUsage&lt;/code&gt; &lt;code&gt;diskCapacity&lt;/code&gt; &lt;code&gt;memoryCapacity&lt;/code&gt;. Let’s run the dart code using&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;dart&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;url_cache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dart&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is as&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A0IRU5Jp6JwNt967IxvOD5w.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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A0IRU5Jp6JwNt967IxvOD5w.png" alt="NSURLCache data"&gt;&lt;/a&gt;NSURLCache data&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;Using configuration inside pubspec&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;In the above section, we saw how to use the configuration specified inside a separate config file, let’s see how to use the configuration inside the &lt;code&gt;pubspec&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;We will choose another Objective-C library present inside the macOS.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One such library is &lt;code&gt;&lt;a href="https://developer.apple.com/documentation/foundation/nstimezone?language=objc]" rel="noreferrer noopener"&gt;&lt;em&gt;NSTimeZone&lt;/em&gt;&lt;/a&gt;&lt;/code&gt;&lt;em&gt; &lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This API is used for querying the time zones along with the standard time policies of a region. These time zones can have identifiers such as &lt;code&gt;America/Los_Angeles&lt;/code&gt; and can also be identified by abbreviations such as &lt;code&gt;PST&lt;/code&gt; for Pacific Standard Time.&lt;/p&gt;

&lt;p&gt;The header for this library is present inside the &lt;code&gt;NSTimeZone.h&lt;/code&gt;which can be found inside the Apple Foundation library. Let’s include the configuration inside the pubspec:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dev_dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;ffigen&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TimeZoneLibrary&lt;/span&gt;
  &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;objc&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timezone_bindings.dart"&lt;/span&gt;
  &lt;span class="na"&gt;exclude-all-by-default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;objc-interfaces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NSTimeZone"&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;entry-points&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSTimeZone.h"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above configuration, we specify the &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; This class will be called &lt;code&gt;TimeZoneLibrary&lt;/code&gt;
&lt;/li&gt;



&lt;li&gt;
&lt;code&gt;language&lt;/code&gt; The library we select is written in Objective-C, we specify &lt;code&gt;objc&lt;/code&gt;
&lt;/li&gt;



&lt;li&gt;
&lt;code&gt;headers&lt;/code&gt; The path to the &lt;code&gt;header files&lt;/code&gt; which is present inside the &lt;code&gt;Foundation.framework&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For generating the bindings we run the following&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;dart&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;ffigen&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a new file (&lt;strong&gt;timezone_bindings.dart&lt;/strong&gt;) as specified inside the &lt;strong&gt;output &lt;/strong&gt;parameter that contains a bunch of generated API bindings. Using this binding file, we can write our Dart &lt;code&gt;main&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;We create a new dart file called &lt;code&gt;timezones.dart&lt;/code&gt; Inside this file, we load and interact with the generated library.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;dylibPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'/System/Library/Frameworks/Foundation.framework/Versions/Current/Foundation'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;lib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeZoneLibrary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DynamicLibrary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dylibPath&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;timeZone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NSTimeZone&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLocalTimeZone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeZone&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Timezone name: &lt;/span&gt;&lt;span class="si"&gt;${timeZone.name}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Offset: &lt;/span&gt;&lt;span class="si"&gt;${timeZone.secondsFromGMT / 60 / 60}&lt;/span&gt;&lt;span class="s"&gt; hours'&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;&lt;strong&gt;W&lt;/strong&gt;e construct the &lt;code&gt;TimeZoneLibrary&lt;/code&gt; by using the constructor which needs the &lt;code&gt;dylib&lt;/code&gt; path. Once the library gets initialized, we call the different methods present inside it.&lt;/p&gt;

&lt;p&gt;We will be integrating the &lt;code&gt;NSTimeZone&lt;/code&gt; inside &lt;code&gt;Dart&lt;/code&gt; and call some of its functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; : The geopolitical region ID that identifies the receiver.&lt;/li&gt;



&lt;li&gt;
&lt;code&gt;secondsFromGMT&lt;/code&gt; : The current difference in seconds between the receiver and Greenwich Mean Time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For getting an instance of this class, we call &lt;code&gt;localTimeZone&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;timeZone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NSTimeZone&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLocalTimeZone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we have the instance of &lt;code&gt;NSTimeZone&lt;/code&gt; we can access the different methods &lt;code&gt;name&lt;/code&gt; &lt;code&gt;secondsFromGMT&lt;/code&gt;. Let’s run the dart code using&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;dart&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;timezones&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dart&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is as&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AN5OZQ5ULW7wt3ThZb3vpiw.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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AN5OZQ5ULW7wt3ThZb3vpiw.png" alt="NSTimeZone data"&gt;&lt;/a&gt;NSTimeZone data&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Garbage Collection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Objective-C uses reference counting for memory management, but on the Dart side, memory management is handled automatically. The Dart wrapper object retains a reference to the Objective-C object, and when the Dart object is garbage collected, the generated code automatically releases that reference using a &lt;code&gt;&lt;a href="https://api.dart.dev/dart-ffi/NativeFinalizer-class.html" rel="noreferrer noopener"&gt;NativeFinalizer&lt;/a&gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations of Objective-C Interop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The issues with the multithreading currently are a limitation to Dart’s experimental support for &lt;code&gt;Objective-C&lt;/code&gt; interop. However, these limitations are not intentional, but due to the relationship between the Dart isolates and OS threads, and also how Apple handles the multithreading.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;While &lt;code&gt;ffigen&lt;/code&gt; supports converting Dart functions to Objective-C blocks, but most Apple APIs don’t guarantee on which thread a callback will run.&lt;/li&gt;



&lt;li&gt;Dart isolates are not the same as threads. Isolates run on threads but aren’t guaranteed to run on any particular thread. The VM can change which thread an isolate is running on without warning.&lt;/li&gt;



&lt;li&gt;Apple APIs are not &lt;a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html" rel="noreferrer noopener"&gt;thread-safe&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since the VM can change the thread in which an isolate can run, this means a callback created in one isolate might be invoked on a different or no isolate. However, there are some tweaks around this, as implemented in the &lt;code&gt;&lt;a href="https://github.com/dart-lang/http/blob/master/pkgs/cupertino_http/src/CUPHTTPClientDelegate.m" rel="noreferrer noopener"&gt;cupertino:http&lt;/a&gt;&lt;/code&gt; &lt;/p&gt;

&lt;h3&gt;Testing FFIGen&lt;/h3&gt;

&lt;p&gt;Till now, we saw how to generate the bindings, and consume them from Dart CLI. In this section, we will see how to test the generated bindings.&lt;/p&gt;

&lt;p&gt;We install the dependencies &lt;code&gt;&lt;a href="https://pub.dev/packages/yaml" rel="noreferrer noopener"&gt;yaml&lt;/a&gt;&lt;/code&gt; and &lt;code&gt;&lt;a href="https://pub.dev/packages/logging" rel="noreferrer noopener"&gt;logging&lt;/a&gt;&lt;/code&gt; and create a file called &lt;code&gt;ffi_2_18_test&lt;/code&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: The tests should follow &lt;/em&gt;&lt;code&gt;&lt;em&gt;&amp;lt;name&amp;gt;_test.dart&lt;/em&gt;&lt;/code&gt;&lt;em&gt; pattern&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;yaml&lt;/code&gt; dependency helps in the parsing of a &lt;code&gt;YAML&lt;/code&gt; file. Whereas &lt;code&gt;logging&lt;/code&gt; provides us with the APIs useful for logging (based on the configuration as specified).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup Logging&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We configure the logging level and add a handler for the log messages. The level is set to &lt;code&gt;Level.SEVERE&lt;/code&gt; and next, we listen on the &lt;code&gt;onRecord&lt;/code&gt; stream for &lt;code&gt;LogRecord&lt;/code&gt; events.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;logWarnings&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;Level&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Level&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WARNING&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;onRecord&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;${record.level.name.padRight(8)}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;${record.message}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function &lt;code&gt;logWarnings&lt;/code&gt; is called inside the &lt;code&gt;setUpAll&lt;/code&gt; The function registered under &lt;code&gt;setUpAll&lt;/code&gt; will be run once before all the tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test for NSURLCache&lt;/strong&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'url_cache'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;pubspecFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'url_cache_config.yaml'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;pubspecYaml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loadYaml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pubspecFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readAsStringSync&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;YamlMap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromYaml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pubspecYaml&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'class URLCacheLibrary{'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'static NSURLCache?getSharedURLCache('&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
 &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We begin writing a test using the &lt;code&gt;test&lt;/code&gt; method. The first thing we do is create the &lt;code&gt;url_cache_config.yaml&lt;/code&gt; using a &lt;a href="https://api.flutter.dev/flutter/package-file_file/File-class.html" rel="noreferrer noopener"&gt;file&lt;/a&gt; object. &lt;/p&gt;

&lt;p&gt;Next, we use the &lt;code&gt;&lt;a href="https://pub.dev/documentation/yaml/latest/yaml/loadYaml.html" rel="noreferrer noopener"&gt;loadYaml&lt;/a&gt;&lt;/code&gt; the function which loads a single document from the YAML string. Since this method expects the parameter to be a string, we use the &lt;code&gt;readAsStringSync&lt;/code&gt; to convert the file contents into string synchronously.&lt;/p&gt;

&lt;p&gt;The return value is mostly normal Dart objects. Since we are using the &lt;code&gt;YAML&lt;/code&gt;file, we specify the result as &lt;code&gt;&lt;a href="https://pub.dev/documentation/yaml/latest/yaml/YamlMap-class.html" rel="noreferrer noopener"&gt;YamlMap&lt;/a&gt;&lt;/code&gt;YAML mappings support some key types that the default Dart map implementation doesn’t have.&lt;/p&gt;

&lt;p&gt;Next, we use the &lt;code&gt;&lt;a href="https://pub.dev/documentation/ffigen/latest/ffigen/Config-class.html" rel="noreferrer noopener"&gt;Config&lt;/a&gt;&lt;/code&gt; from the &lt;code&gt;ffigen&lt;/code&gt; to create the configuration required for testing from the above &lt;code&gt;yaml&lt;/code&gt; map. Finally, we use the &lt;code&gt;&lt;a href="https://pub.dev/documentation/ffigen/latest/ffigen/parse.html" rel="noreferrer noopener"&gt;parse&lt;/a&gt;&lt;/code&gt; to generate the bindings.&lt;/p&gt;

&lt;p&gt;The output from the above step is compared against the strings, for instance&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'class URLCacheLibrary{'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'static NSURLCache? getSharedURLCache('&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because once we run the test using&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;dart&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ffi_2_18_test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dart&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It generates the config file during the runtime and this gets compared with the strings above.&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AjE85taC0nAduR40g7SAcRg.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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AjE85taC0nAduR40g7SAcRg.png" alt="Test passed using FFIGen"&gt;&lt;/a&gt;Test passed using FFIGen&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test for NSTimeZone &lt;/strong&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'timezones'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;pubspecFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'pubspec.yaml'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;pubspecYaml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loadYaml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pubspecFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readAsStringSync&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;YamlMap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromYaml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pubspecYaml&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'ffigen'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;YamlMap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'class TimeZoneLibrary{'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'class NSString extends _ObjCWrapper {'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'static NSTimeZone? getLocalTimeZone('&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
 &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create a &lt;a href="https://api.flutter.dev/flutter/package-file_file/File-class.html" rel="noreferrer noopener"&gt;file&lt;/a&gt; object using the &lt;code&gt;pubspec.yaml&lt;/code&gt; file. Next, we use the &lt;code&gt;&lt;a href="https://pub.dev/documentation/yaml/latest/yaml/loadYaml.html" rel="noreferrer noopener"&gt;loadYaml&lt;/a&gt;&lt;/code&gt; which loads the file from the YAML string. &lt;/p&gt;

&lt;p&gt;Next, we use the &lt;code&gt;&lt;a href="https://pub.dev/documentation/ffigen/latest/ffigen/Config-class.html" rel="noreferrer noopener"&gt;Config&lt;/a&gt;&lt;/code&gt; from the &lt;code&gt;ffigen&lt;/code&gt; to create the configuration required for testing from the above &lt;code&gt;yaml&lt;/code&gt; map. Since the pubspec file has the property &lt;code&gt;ffigen&lt;/code&gt; defined inside it, we straight away refer to that and specify the output type to be &lt;code&gt;YamlMap&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: For the NSTimeZone, we specified the ffigen configuration inside the pubspec.yaml&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, we use the &lt;code&gt;&lt;a href="https://pub.dev/documentation/ffigen/latest/ffigen/parse.html" rel="noreferrer noopener"&gt;parse&lt;/a&gt;&lt;/code&gt; to generate the bindings. The output from this step is compared against the strings, for instance&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'class TimeZoneLibrary{'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'static NSTimeZone? getLocalTimeZone('&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because once we run the test using&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;dart&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ffi_2_18_test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dart&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;It generates the config file during the runtime and this gets compared with the strings inside the test.&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2ABhhVE230XuwSS9jKtS381w.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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2ABhhVE230XuwSS9jKtS381w.png" alt="Test passed using FFIGen"&gt;&lt;/a&gt;Test passed using FFIGen&lt;/p&gt;


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/flutter_programs/tree/master/ffi_2_18"&gt;&lt;em&gt;Source code&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>productivity</category>
      <category>dart</category>
      <category>programming</category>
    </item>
    <item>
      <title>Using Redis for Caching (2023)</title>
      <dc:creator>aseem wangoo</dc:creator>
      <pubDate>Thu, 20 Oct 2022 06:29:20 +0000</pubDate>
      <link>https://forem.com/aseemwangoo/using-redis-for-caching-2022-2og5</link>
      <guid>https://forem.com/aseemwangoo/using-redis-for-caching-2022-2og5</guid>
      <description>&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;We will cover briefly:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;Caching APIs (Go) using Redis&lt;/li&gt;
&lt;li&gt;Redis Subscription using Pub/Sub&lt;/li&gt;
&lt;li&gt;Calling API using React&lt;/li&gt;
&lt;/ol&gt;



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

&lt;h3&gt;What is Redis?&lt;/h3&gt;

&lt;p&gt;Redis, which stands for &lt;strong&gt;Re&lt;/strong&gt;mote &lt;strong&gt;Di&lt;/strong&gt;ctionary &lt;strong&gt;S&lt;/strong&gt;erver, is a fast, open source, in-memory, key-value data store. It delivers sub-millisecond response times, enabling millions of requests per second for real-time applications.&lt;/p&gt;

&lt;p&gt;Redis is a key-value-based &lt;a href="https://databasecamp.de/en/data/nosql-databases" rel="noreferrer noopener"&gt;NoSQL&lt;/a&gt; database that stores data in memory, i.e. in RAM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases of Redis&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caching&lt;/li&gt;
&lt;li&gt;Geospatial&lt;/li&gt;
&lt;li&gt;Chat, messaging, and queues&lt;/li&gt;
&lt;li&gt;Gaming leaderboards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Advantages of Redis&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple, fast, and easy to use&lt;/li&gt;
&lt;li&gt;Supports a variety &lt;a href="https://redis.io/docs/data-types/tutorial/" rel="noreferrer noopener"&gt;of data structures&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Allows storing key and value pairs as large as &lt;code&gt;512 MB&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;High availability using &lt;a href="https://redis.io/topics/sentinel" rel="noreferrer noopener"&gt;Redis Sentinel&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disadvantages of Redis&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires huge RAM (although depends on the type of application)&lt;/li&gt;
&lt;li&gt;Failover happens if the master at least &lt;code&gt;1&lt;/code&gt; slave&lt;/li&gt;
&lt;li&gt;Data can only be accessed via keys&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Setting up Redis &lt;/h4&gt;

&lt;p&gt;We will setup &lt;a href="https://redis.io/download/" rel="noreferrer noopener"&gt;Redis&lt;/a&gt; using &lt;a href="https://hub.docker.com/_/redis/" rel="noreferrer noopener"&gt;Docker&lt;/a&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;docker run -d -p 6379:6379 --name redis redis&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nowadays there are some hosting providers such as &lt;a href="https://aws.amazon.com/redis/" rel="noreferrer noopener"&gt;AWS&lt;/a&gt;, &lt;a href="https://redislabs.com/" rel="noreferrer noopener"&gt;Redis Labs&lt;/a&gt;, or &lt;a href="https://upstash.com/?utm_source=goredis" rel="noreferrer noopener"&gt;Upstash&lt;/a&gt; that provide Redis on the cloud.&lt;/p&gt;

&lt;p&gt;There are many ways of connecting to &lt;a href="https://redis.io/docs/clients/" rel="noreferrer noopener"&gt;Redis&lt;/a&gt;. In our case, we will be using the &lt;code&gt;&lt;a href="https://redis.io/topics/rediscli" rel="noreferrer noopener"&gt;RedisCLI&lt;/a&gt;&lt;/code&gt; Since we have the docker setup ready, let's connect.&lt;/p&gt;

&lt;p&gt;Here is an example of using the &lt;code&gt;RedisCLI&lt;/code&gt; tool to set, get and delete a value from the Redis&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="s"&gt;docker exec -it redis redis-cli&lt;/span&gt;
&lt;span class="s"&gt;127.0.0.1:6379&amp;gt; set key value&lt;/span&gt;
&lt;span class="s"&gt;OK&lt;/span&gt;
&lt;span class="s"&gt;127.0.0.1:6379&amp;gt; get key&lt;/span&gt;
&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value"&lt;/span&gt;
&lt;span class="s"&gt;127.0.0.1:6379&amp;gt; del key&lt;/span&gt;
&lt;span class="s"&gt;(integer) &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="s"&gt;127.0.0.1:6379&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some other useful commands&lt;/p&gt;

&lt;p&gt;&lt;code&gt;keys&lt;/code&gt; *: for finding all the keys&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FLUSHALL&lt;/code&gt; : delete all keys from all databases.&lt;br&gt;&lt;code&gt;FLUSHDB&lt;/code&gt; : delete all keys from the currently selected DB.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EXPIRE&lt;/code&gt; key 120: key will be deleted in &lt;code&gt;120&lt;/code&gt;seconds&lt;/p&gt;

&lt;h3&gt;Caching APIs (Go) using Redis&lt;/h3&gt;

&lt;p&gt;There are multiple clients available in &lt;a href="https://redis.io/docs/clients/#go" rel="noreferrer noopener"&gt;&lt;strong&gt;Go&lt;/strong&gt;&lt;/a&gt; for implementing Redis. However, in this article, we will be using &lt;code&gt;&lt;a href="https://github.com/go-redis/redis" rel="noreferrer noopener"&gt;Go-redis&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go-Redis&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go-Redis is a type-safe, Redis client library for Go. &lt;/li&gt;
&lt;li&gt;It is a Redis client able to support a Redis cluster and is designed to store and update slot info automatically with a cluster change.&lt;/li&gt;
&lt;li&gt;It supports features like &lt;code&gt;&lt;a href="https://redis.uptrace.dev/guide/go-redis-pubsub.html" rel="noreferrer noopener"&gt;Pub/Sub&lt;/a&gt;&lt;/code&gt; &lt;code&gt;&lt;a href="https://redis.uptrace.dev/guide/go-redis-sentinel.html" rel="noreferrer noopener"&gt;Sentinel&lt;/a&gt;&lt;/code&gt;, and pipelining&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Create APIs using Gorilla Mux&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We will be using &lt;a href="https://github.com/gorilla/mux" rel="noreferrer noopener"&gt;Gorilla Mux&lt;/a&gt; to create the APIs locally&lt;/li&gt;
&lt;li&gt;It implements a request router and dispatcher to match the incoming requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install it using&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gorilla&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mux&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;&lt;li&gt;We will register the following endpoints:&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;GET /users/:id&lt;/code&gt; — to get a user’s information based on the id. Sample response&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"116c24b1-9425-4fe4-aec2-86ba7384733e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;     
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"a3fa13d4-67a9-4ae6-9713-dce7043844d7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GET /users — returns the users present in the database. Sample response&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"116c24b1-9425-4fe4-aec2-86ba7384733e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;ul&gt;
&lt;li&gt;Next, we create the router instance using the &lt;code&gt;mux.NewRouter()&lt;/code&gt; and assign the above-created routes to the respective handlers&lt;/li&gt;
&lt;li&gt;Each of the corresponding handlers is passed ResponseWriter and Request as parameters, which help in returning the desired response to the client.&lt;/li&gt;
&lt;li&gt;We then specify the server details using &lt;code&gt;http.Server&lt;/code&gt; for running the HTTP server&lt;/li&gt;
&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;         &lt;span class="s"&gt;":8081"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;WriteTimeout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;ReadTimeout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;code&gt;Handler&lt;/code&gt; : This is the object that responds to the incoming HTTP requests (which we created above)&lt;/p&gt;





&lt;p&gt;&lt;code&gt;Addr&lt;/code&gt; : This specifies the TCP address for the server to listen on, which by default is &lt;code&gt;80&lt;/code&gt; &lt;/p&gt;





&lt;p&gt;&lt;code&gt;WriteTimeout&lt;/code&gt; : Maximum duration before timing out the writes of the response&lt;/p&gt;





&lt;p&gt;&lt;code&gt;ReadTimeout&lt;/code&gt; : Maximum duration for reading the entire incoming request&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;Finally, we run the server using &lt;code&gt;ListenAndServe&lt;/code&gt; which listens on the network address specified in the &lt;code&gt;Addr&lt;/code&gt; and serves the requests based on the &lt;code&gt;Handler&lt;/code&gt; &lt;/li&gt;&lt;/ul&gt;





&lt;h4&gt;Setting up Postgres&lt;/h4&gt;





&lt;p&gt;We will be using Postgres for our database. Install it using docker with the following&lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;docker run \&lt;/span&gt;
  &lt;span class="s"&gt;-d \&lt;/span&gt;                                     
  &lt;span class="s"&gt;-e POSTGRES_HOST_AUTH_METHOD=trust \&lt;/span&gt;
  &lt;span class="s"&gt;-e POSTGRES_USER=user \&lt;/span&gt;
  &lt;span class="s"&gt;-e POSTGRES_PASSWORD=password \&lt;/span&gt;
  &lt;span class="s"&gt;-e POSTGRES_DB=dbname \&lt;/span&gt;
  &lt;span class="s"&gt;-p 5432:5432 \&lt;/span&gt;
  &lt;span class="s"&gt;postgres&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;ul&gt;&lt;li&gt;Verify if the new container is created and running at 0.0.0.0:5432&lt;code&gt;docker ps -a&lt;/code&gt; For managing the database from the browser, install &lt;a href="https://www.pgadmin.org/download/" rel="noreferrer noopener"&gt;pgAdmin&lt;/a&gt; and connect to it using the above credentials, if all is good, you should see&lt;/li&gt;&lt;/ul&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2ACazxSZgKc64-lbsmCw5C0Q.png" alt="Postgres database"&gt;Postgres database





&lt;p&gt;We will create a table called &lt;code&gt;users&lt;/code&gt; which will have the following schema&lt;/p&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2ASx3U9aMu4V2wtT2vFoCVtQ.png" alt="Users table "&gt;Users table 





&lt;p&gt;Let’s insert some dummy data using &lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;updated_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid_generate_v4&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s1"&gt;'alice'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;ANY&lt;/span&gt; &lt;span class="n"&gt;ERROR&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt; &lt;span class="n"&gt;THIS&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"uuid-ossp"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;For connecting to Postgres using &lt;code&gt;Go&lt;/code&gt; we will install &lt;a href="github.com/jackc/pgx/v4" rel="noreferrer noopener"&gt;this&lt;/a&gt; Here is the snippet&lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"127.0.0.1"&lt;/span&gt;
&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"5432"&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"user"&lt;/span&gt;
&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"password"&lt;/span&gt;
&lt;span class="n"&gt;dbname&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"dbname"&lt;/span&gt;
&lt;span class="n"&gt;psqlInfo&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"host=%s port=%s user=%s password=%s dbname=%s sslmode=disable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dbname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"postgres"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;psqlInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
   &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error in connection : %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;Here is the struct for the &lt;code&gt;users&lt;/code&gt; &lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Users&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;ID&lt;/span&gt;          &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;
 &lt;span class="n"&gt;Name&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"name"`&lt;/span&gt;
 &lt;span class="n"&gt;Age&lt;/span&gt;         &lt;span class="kt"&gt;int&lt;/span&gt;       &lt;span class="s"&gt;`json:"age"`&lt;/span&gt;
 &lt;span class="n"&gt;CreatedTime&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"created_time"`&lt;/span&gt;
 &lt;span class="n"&gt;UpdatedTime&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"updated_time"`&lt;/span&gt;
 &lt;span class="n"&gt;Source&lt;/span&gt;      &lt;span class="kt"&gt;string&lt;/span&gt;    &lt;span class="s"&gt;`json:"source"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;API and get users by id API are created, we will use the Gorilla Mux to create a &lt;code&gt;localhost&lt;/code&gt; server and listen to the endpoints&lt;/p&gt;





&lt;h4&gt;Caching APIs&lt;/h4&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AjI76sdMEWFSYzPI4bt_Ftg.png" alt="Redis between DB and client"&gt;Redis between DB and client





&lt;p&gt;For connecting to the &lt;code&gt;Redis&lt;/code&gt; we create a Redis Client using &lt;code&gt;&lt;a href="https://github.com/go-redis/redis/blob/v8.11.5/redis.go#L546" rel="noreferrer noopener"&gt;NewClient&lt;/a&gt;&lt;/code&gt; We specify the address at which the Redis exists&lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;        &lt;span class="s"&gt;"127.0.0.1:6379"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;          &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;DialTimeout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;ReadTimeout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&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;ul&gt;&lt;li&gt;The configuration options are available through the &lt;code&gt;redis.Options&lt;/code&gt; parameter.&lt;/li&gt;&lt;/ul&gt;





&lt;p&gt;&lt;code&gt;Addr&lt;/code&gt; : String of host and the port address, since we are hosting Redis locally, the value is &lt;code&gt;127.0.0.1&lt;/code&gt; and by default, Redis runs on the port &lt;code&gt;6379&lt;/code&gt; &lt;/p&gt;





&lt;p&gt;&lt;code&gt;DB&lt;/code&gt; : The database which will the selected after connecting to the server. By choosing &lt;code&gt;0&lt;/code&gt; we mean to use the default database.&lt;/p&gt;





&lt;p&gt;&lt;code&gt;DialTimeout&lt;/code&gt; : In case our connection to the Redis server gets broken, we specify the timeout for establishing the new connection&lt;/p&gt;





&lt;p&gt;&lt;code&gt;ReadTimeout&lt;/code&gt; : This allows putting a timeout for the socket reads. In case any of the Redis server requests reach this timeout, the command calling it will fail instead of blocking the server.&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;To check if we connected to the server, we call &lt;code&gt;&lt;a href="https://pkg.go.dev/github.com/go-redis/redis/v8#Client.Ping" rel="noreferrer noopener"&gt;Ping&lt;/a&gt;&lt;/code&gt; using the client we created above. If there is no error, that implies we are connected to the Redis server.&lt;/li&gt;
&lt;li&gt;Finally, we return the Redis client which internally may have zero or more connections.&lt;/li&gt;
&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ping&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;strong&gt;Get and Set Keys&lt;/strong&gt;&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;The use case we would be following is whenever the front end asks for the details of a particular user, we would fetch it from the API and then cache it. &lt;/li&gt;
&lt;li&gt;Subsequent requests for the particular user would be served from the cache until the cache key expires (which we set to &lt;code&gt;20 seconds&lt;/code&gt; )&lt;/li&gt;
&lt;li&gt;We will be making use of &lt;code&gt;&lt;a href="https://github.com/go-redis/redis/blob/v8.11.5/commands.go#L890" rel="noreferrer noopener"&gt;Set&lt;/a&gt;&lt;/code&gt; to set the value in the cache&lt;/li&gt;
&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;SetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;structs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;blockquote&gt;&lt;p&gt;Note: Here we are taking the &lt;code&gt;user&lt;/code&gt;struct as input. We are then converting the Go struct into JSON (aka marshaling) since JSON is a language-independent data format.&lt;/p&gt;&lt;/blockquote&gt;





&lt;ul&gt;
&lt;li&gt;We are setting the key pair with an optional expiration parameter of &lt;code&gt;20 seconds&lt;/code&gt; This means the key will automatically expire in the given duration.&lt;/li&gt;
&lt;li&gt;In case there is no expiration parameter, it means &lt;code&gt;Zero expiration&lt;/code&gt; meaning the key has no expiration time.&lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;Get keys&lt;/strong&gt;&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;We will be making use of &lt;code&gt;&lt;a href="https://github.com/go-redis/redis/blob/v8.11.5/commands.go#L784" rel="noreferrer noopener"&gt;Get&lt;/a&gt;&lt;/code&gt; for retrieving the value of the key&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;structs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;structs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
 &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;ul&gt;
&lt;li&gt;The response is in the form of a string and then we convert the byte data into the original &lt;code&gt;user&lt;/code&gt; struct (aka unmarshalling)&lt;/li&gt;
&lt;li&gt;Inside this function, we additionally add a Redis publisher (which we will see in the next section).&lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;Calling APIs&lt;/strong&gt;&lt;/p&gt;





&lt;p&gt;We have this API endpoint hosted locally &lt;code&gt;GET /users/:id&lt;/code&gt; — to get a user’s information based on the id.&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;Once the client calls this endpoint, we first check in case the value for this request can be served from the cache.&lt;/li&gt;&lt;/ul&gt;





&lt;blockquote&gt;&lt;p&gt;Note: In case the data exists inside the cache, we set the &lt;code&gt;source: "cache"&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;





&lt;ul&gt;&lt;li&gt;Logically, the first request will always hit the server, hence the time taken for getting the response will be more.&lt;/li&gt;&lt;/ul&gt;





&lt;blockquote&gt;&lt;p&gt;Note: For getting the value from the server, we set the &lt;code&gt;&lt;em&gt;source: "API"&lt;/em&gt;&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
 &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"cache"&lt;/span&gt;
  &lt;span class="n"&gt;renderJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;GetUserByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;renderJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"API"&lt;/span&gt;
 &lt;span class="n"&gt;renderJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&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;ul&gt;
&lt;li&gt;As we can see in the above snippet, we first invoke &lt;code&gt;redis.GetUser&lt;/code&gt; to check the cache.&lt;/li&gt;
&lt;li&gt;This function checks for the id inside the cache, if the id is present, it returns the value.&lt;/li&gt;
&lt;li&gt;If the result fails, the function returns null and we proceed to invoke the API &lt;code&gt;GetUserByID&lt;/code&gt; which hits our Postgres database&lt;/li&gt;
&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"116c24b1-9425-4fe4-aec2-86ba7384733e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"API"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;s how it looks when the key is not present in Redis&lt;/p&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AST5YLQ6W1fmUkL52fBeiMQ.png" alt="Key not present in Redis"&gt;Key not present in Redis





&lt;ul&gt;&lt;li&gt;The result from the API is then cached in Redis, so the subsequent requests are now served by the cache (until &lt;code&gt;20 seconds&lt;/code&gt; which is the key expiration duration)&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"116c24b1-9425-4fe4-aec2-86ba7384733e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"cache"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;This is how it looks when the key is present in Redis&lt;/p&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AX6MOmVp3Y1CFqgjKCUSMCw.png" alt=""&gt;Key present in Redis












&lt;h4&gt;Redis Subscription using Pub/Sub&lt;/h4&gt;





&lt;ul&gt;
&lt;li&gt;In the field of software engineering, publish-subscribe is a pattern where senders (publishers) categorize the messages into channels without knowing if there may be any subscribers.&lt;/li&gt;
&lt;li&gt;On the other hand, subscribers show interest in one or more channels and only receive messages that are of interest, without knowing if there may be any publishers.&lt;/li&gt;
&lt;li&gt;This decoupling of publishers and subscribers enhances greater scalability.&lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;Redis Pub/Sub&lt;/strong&gt;&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;We will be using Redis for pub/sub, however, there are various other alternatives like Apache Kafka, Google cloud Pub/Sub, etc&lt;/li&gt;
&lt;li&gt;In order to subscribe to channels, for instance, &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt; the client uses &lt;code&gt;&lt;a href="https://redis.io/commands/subscribe" rel="noreferrer noopener"&gt;SUBSCRIBE&lt;/a&gt;&lt;/code&gt; providing the names of the channels:&lt;/li&gt;
&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;SUBSCRIBE foo bar&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;Messages sent by other clients to these channels will be pushed by Redis to all the subscribed clients.&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;Once we have a Redis client subscribing to a channel, that client can no longer execute any other operations except unsubscribing from the current channel or subscribing to more channels.&lt;/li&gt;&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;Go-Redis Publisher&lt;/strong&gt;&lt;/p&gt;





&lt;p&gt;&lt;code&gt;Go-redis&lt;/code&gt; allows to publish messages and subscribe to channels. It also automatically re-connects to Redis Server when there is a network error.&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;Inside our get user function, we will create a publisher, using &lt;code&gt;&lt;a href="https://github.com/go-redis/redis/blob/v8.11.5/commands.go#L3172" rel="noreferrer noopener"&gt;redis.Publish(&lt;/a&gt;)&lt;/code&gt;. This function takes two arguments, the name of the &lt;strong&gt;channel&lt;/strong&gt; to which we want to send the message and the &lt;strong&gt;message&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In our case, we set the channel name to &lt;code&gt;send-user-name&lt;/code&gt; and the payload is the response from &lt;code&gt;redis.GetUser&lt;/code&gt; (see above)&lt;/li&gt;
&lt;li&gt;We are sending the marshaled payload to the channel using &lt;code&gt;Publish&lt;/code&gt; This is because it allows transferring the data as &lt;code&gt;[]byte&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Since we are using a User struct, it can be encoded into a &lt;code&gt;[]byte&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Sample payload we are sending using pub/sub&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;"116c24b1-9425-4fe4-aec2-86ba7384733e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s"&gt;"age"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="s"&gt;"source"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;"cache"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// Publish using Redis PubSub&lt;/span&gt;
&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"send-user-name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;strong&gt;Go-Redis Subscriber&lt;/strong&gt;&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;We create a subscriber using the &lt;code&gt;&lt;a href="https://github.com/go-redis/redis/blob/v8.11.5/redis.go#L686" rel="noreferrer noopener"&gt;redis.Subscribe()&lt;/a&gt;&lt;/code&gt; function. &lt;/li&gt;
&lt;li&gt;We will have one argument, the &lt;strong&gt;channel&lt;/strong&gt; we want to subscribe to, which in our case is &lt;code&gt;send-user-name&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Subscribe subscribes to the client to the specified channels. Since this method does not wait on a response from Redis, so the subscription may not be active immediately.&lt;/li&gt;
&lt;li&gt;We create a new file that connects to the same Redis instance and calls the following&lt;/li&gt;
&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;topic&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;redisClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"send-user-name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
 &lt;span class="c"&gt;// Unmarshal the data into the user&lt;/span&gt;
 &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnmarshalBinary&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Payload&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User: %v having age: %v and id: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received message from "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Channel&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" channel."&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;ul&gt;
&lt;li&gt;The result of the &lt;code&gt;subscribe&lt;/code&gt; is a &lt;code&gt;PubSub&lt;/code&gt; and we extract the channel property out of this object&lt;/li&gt;
&lt;li&gt;This Channel returns a Go channel for concurrently receiving messages. If the channel is full for 30 seconds the message is dropped.&lt;/li&gt;
&lt;li&gt;We loop over the channel and extract the data from it, which is of the type &lt;code&gt;Message&lt;/code&gt; Each message object comprises of&lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;&lt;code&gt;Channel&lt;/code&gt; : This is the channel name&lt;/p&gt;





&lt;p&gt;&lt;code&gt;Payload&lt;/code&gt; : The marshaled data received in the channel&lt;/p&gt;





&lt;p&gt;&lt;code&gt;Pattern&lt;/code&gt; : Pattern for the message&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;The data received inside the message can be fetched using &lt;code&gt;msg.Payload&lt;/code&gt; Since its marshaled, we will unmarshal it using the &lt;code&gt;UnmarshalBinary&lt;/code&gt; and transform back into &lt;code&gt;User&lt;/code&gt; struct.&lt;/li&gt;
&lt;li&gt;Finally, we can access the struct properties and print inside the console. We also print the message’s channel name, just for fun!!&lt;/li&gt;
&lt;/ul&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AlTOAAsbWv6_FAvcXgBuJMA.png" alt="Redis subscriber"&gt;Redis subscriber





&lt;p&gt;Here, we get the message channel name &lt;code&gt;send-user-name&lt;/code&gt; and the user details for &lt;code&gt;Bob&lt;/code&gt; &lt;/p&gt;





&lt;h4&gt;Calling API using React&lt;/h4&gt;





&lt;p&gt;In the above section, we created and hosted the APIs locally using &lt;a href="https://github.com/gorilla/mux" rel="noreferrer noopener"&gt;Gorilla Mux&lt;/a&gt;. We will now consume these APIs from the front end using React&lt;/p&gt;





&lt;p&gt;We will be using Axios for calling the APIs. Let’s install this dependency. &lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;ul&gt;
&lt;li&gt;Axios is a lightweight HTTP client which makes calling requests very intuitive. It is similar to the JavaScript &lt;code&gt;Fetch API&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;It works well with JSON data and does the heavy lifting of setting the request headers.&lt;/li&gt;
&lt;li&gt;It has better error handling for accessing the response and integrates well with async-await syntax.&lt;/li&gt;
&lt;li&gt;It can be used on the server as well as the client.&lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;Integrate into React&lt;/strong&gt;&lt;/p&gt;





&lt;p&gt;We will be using the hooks &lt;code&gt;useEffect&lt;/code&gt; and &lt;code&gt;useState&lt;/code&gt; A &lt;code&gt;hook&lt;/code&gt;is a special function that lets you “hook into” React features.&lt;/p&gt;





&lt;p&gt;&lt;strong&gt;useEffect&lt;/strong&gt;&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;Using this Hook, we instruct React that our components need to do something after rendering. By default, &lt;code&gt;useEffect&lt;/code&gt; runs after each render of the component where it’s called.&lt;/li&gt;
&lt;li&gt;A common use of this hook is to fetch data and display it.&lt;/li&gt;
&lt;li&gt;React remembers the function you passed, and invokes it later after the DOM updates.&lt;/li&gt;
&lt;/ul&gt;





&lt;blockquote&gt;&lt;p&gt;Note: We have an empty array at the end of the useEffect Hook for making sure the internal function inside renders only once.&lt;/p&gt;&lt;/blockquote&gt;





&lt;ul&gt;&lt;li&gt;If we want our effects to run less often, we provide the second argument (which is an array of values). These can be considered as the dependencies for the effect and if any changes (since the last time), the effect runs again.&lt;/li&gt;&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;useState&lt;/strong&gt;&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;It is a way of adding a state to the components and &lt;code&gt;preserve&lt;/code&gt;some values between the function call. &lt;/li&gt;
&lt;li&gt;In general, variables “disappear” when the function exits but state variables are preserved by React.&lt;/li&gt;
&lt;li&gt;This state can be an array, object, number, boolean, etc.&lt;/li&gt;
&lt;li&gt;The argument passed to the &lt;code&gt;useState()&lt;/code&gt; is the initial state. &lt;/li&gt;
&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fetchedData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setFetchedData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&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;getData&lt;/span&gt; &lt;span class="o"&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;data&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;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:8081/users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setFetchedData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nf"&gt;getData&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;ul&gt;
&lt;li&gt;To make a &lt;code&gt;GET&lt;/code&gt; request using Axios we use the &lt;code&gt;.get()&lt;/code&gt; method. The response is returned as an object.&lt;/li&gt;
&lt;li&gt;We use the &lt;code&gt;.data&lt;/code&gt; property from the response to get the requested data and set it inside the hook using the &lt;code&gt;setFetchedData&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;Request responses:&lt;/strong&gt;&lt;/p&gt;





&lt;p&gt;When the page loads for the first time, the API hits our backend. The result &lt;code&gt;fetchedData&lt;/code&gt; is then displayed on the page. &lt;/p&gt;





&lt;blockquote&gt;&lt;p&gt;Notice, source: API &lt;/p&gt;&lt;/blockquote&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2ASlPKGGzgF8GVq0ZoCdEcNg.png" alt="Source: API"&gt;Source: API





&lt;p&gt;And on the next request, the API hits our cache, displayed with &lt;code&gt;source:cache&lt;/code&gt;&lt;/p&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AmY3AfhgxZeApZ3VAUwmc1w.png" alt="Source: Cache"&gt;Source: Cache



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


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/golang-programs"&gt;&lt;em&gt;Source code for Go&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/expriments_with_react"&gt;&lt;em&gt;Source code for React&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>go</category>
      <category>programming</category>
    </item>
    <item>
      <title>Using MVVM in Flutter (2022)</title>
      <dc:creator>aseem wangoo</dc:creator>
      <pubDate>Sun, 04 Sep 2022 01:03:34 +0000</pubDate>
      <link>https://forem.com/aseemwangoo/using-mvvm-in-flutter-2022-11bg</link>
      <guid>https://forem.com/aseemwangoo/using-mvvm-in-flutter-2022-11bg</guid>
      <description>&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;We will cover briefly:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;What is MVVM&lt;/li&gt;
&lt;li&gt;Using MVVM in Flutter&lt;/li&gt;
&lt;li&gt;Extending MVVM with Repository and Services&lt;/li&gt;
&lt;/ol&gt;



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

&lt;h3&gt;What is MVVM&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Model-View-ViewModel (MVVM)&lt;/strong&gt; is a software architectural pattern that supports the separation of the UI (which is &lt;strong&gt;View&lt;/strong&gt;) from the development of the business logic or the backend logic (&lt;strong&gt;Model&lt;/strong&gt;). The view model inside MVVM is the bridge responsible for the conversion of data in a way that behaves in accordance with the changes happening on the UI&lt;/p&gt;

&lt;p&gt;In addition, to know about the responsibilities of the three components, it’s also important to understand how the components interact with each other. At the highest level, &lt;em&gt;the view “knows about” the view model&lt;/em&gt;, and &lt;em&gt;the view model “knows about” the model&lt;/em&gt;, but &lt;em&gt;the model is unaware of the view model&lt;/em&gt;, and the &lt;em&gt;view model is unaware of the view&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2APlj_xKz_2EwTrXQz.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2APlj_xKz_2EwTrXQz.png" alt="MVVM Architecture"&gt;&lt;/a&gt;MVVM Architecture&lt;/p&gt;

&lt;p&gt;There are several advantages of using MVVM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Separation of Concerns&lt;/strong&gt;: It is a design principle for separating a computer program into distinct sections such that each section addresses a separate concern. A concern is anything that matters in providing a solution to a problem.&lt;/li&gt;
&lt;li&gt;Improved Testability&lt;/li&gt;
&lt;li&gt;Defined Project Structure&lt;/li&gt;
&lt;li&gt;Parallel development of UI&lt;/li&gt;
&lt;li&gt;Abstract the View, thus reducing the quantity of business logic required in the code behind it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some disadvantages of using MVVM:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has a slightly steep learning curve. How all the layers work together may take some time to understand.&lt;/li&gt;
&lt;li&gt;It adds a lot of extra classes, so it’s not ideal for low-complexity projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since architectural or design patterns are platform-agnostic, they can be used with any framework, in our case &lt;strong&gt;Flutter&lt;/strong&gt;.&lt;/p&gt;

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

&lt;h4&gt;Components&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Model: &lt;/strong&gt;This is basically the domain model or the model which represents the data from your backend (aka data access layer). Models hold information, but typically don’t handle behavior. They don’t format information or influence how data appears. The Model in the MVVM design pattern represents the actual data that will be used in application development&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;View: &lt;/strong&gt;This is basically the only part of the application users actually interact with. For instance, the user presses the button, scrolls the list, edits the settings, etc and these events are then forwarded to the view model which then does the processing and returns the expected user response (which is some form of UI). It’s important to remember the &lt;strong&gt;View&lt;/strong&gt; isn’t responsible here for handling the state.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;A &lt;/strong&gt;&lt;code&gt;View&lt;/code&gt;&lt;strong&gt; should be as dumb as possible. &lt;/strong&gt;Never put your business logic in&lt;strong&gt; &lt;/strong&gt;&lt;code&gt;Views&lt;/code&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;View Model: &lt;/strong&gt;The ViewModel acts as an intermediate between the &lt;strong&gt;View&lt;/strong&gt; and the &lt;strong&gt;Model&lt;/strong&gt;, in such a way that it provides data to the UI. The ViewModel may also expose methods for helping to maintain the View’s state, update the model based on the action’s on a View, and trigger events on the View. For &lt;strong&gt;Flutter, &lt;/strong&gt;we have a listener called &lt;code&gt;&lt;a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html" rel="noreferrer noopener"&gt;ChangeNotifier&lt;/a&gt;&lt;/code&gt; that allows ViewModel to inform or update the View whenever the data get updated.&lt;/p&gt;

&lt;p&gt;The ViewModel has basically two responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it reacts to user inputs (e.g. by changing the model, initiating network requests, or routing to different screens)&lt;/li&gt;
&lt;li&gt;it offers output data that the View can subscribe to&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;&lt;p&gt;In summary, the ViewModel sits behind the UI layer. It exposes data needed by a View and can be viewed as the source our Views go to for both data and actions.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h4&gt;What is ChangeNotifier?&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html" rel="noreferrer noopener"&gt;ChangeNotifier&lt;/a&gt; is a class that provides change notifications to its listeners.&lt;/p&gt;

&lt;p&gt;As per the official &lt;a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html" rel="noreferrer noopener"&gt;documentation&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;A class that can be extended or mixed in that provides a change notification API using &lt;a href="https://api.flutter.dev/flutter/dart-ui/VoidCallback.html" rel="noreferrer noopener"&gt;VoidCallback&lt;/a&gt; for notifications.&lt;/p&gt;&lt;/blockquote&gt;

&lt;blockquote&gt;&lt;p&gt;It is O(1) for adding listeners and O(N) for removing listeners and dispatching notifications (where N is the number of listeners).&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;There are several ways to consume the change notifier in Flutter.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using &lt;code&gt;.addListener&lt;/code&gt; method, as the ChangeNotifier is a type of &lt;a href="https://api.flutter.dev/flutter/foundation/Listenable-class.html" rel="noreferrer noopener"&gt;Listenable&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Using the combination of &lt;code&gt;ChangeNotifierProvider&lt;/code&gt;, Consumer, and Provider. These all capabilities are provided to us by the &lt;a href="https://pub.dev/packages/provider" rel="noreferrer noopener"&gt;Provider&lt;/a&gt; package.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;We will use approach 2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the real world, other classes can &lt;em&gt;listen&lt;/em&gt; to an &lt;code&gt;ChangeNotifier&lt;/code&gt; object. When the change notifier gets updated values, it can call a method called &lt;code&gt;&lt;a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier/notifyListeners.html" rel="noreferrer noopener"&gt;notifyListeners&lt;/a&gt;&lt;/code&gt;and then any of its listeners will receive the updated val&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ChangeNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;increaseAge&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="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;notifyListeners&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="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ChangeNotifierProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;create:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;name:&lt;/span&gt; &lt;span class="s"&gt;"Joe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;age:&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Inside the app, any class that listens to this &lt;code&gt;Person&lt;/code&gt; will be notified in case the &lt;code&gt;age&lt;/code&gt; changes. Internally, &lt;code&gt;notifyListeners&lt;/code&gt; calls the registered listeners.&lt;/p&gt;

&lt;h3&gt;Using MVVM in Flutter&lt;/h3&gt;

&lt;p&gt;Flutter is declarative in nature. This means that Flutter builds UI by overriding your build methods to reflect the current state of your app:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;UI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;According to the &lt;a href="https://docs.flutter.dev/development/data-and-backend/state-mgmt/ephemeral-vs-app" rel="noreferrer noopener"&gt;Flutter documentation&lt;/a&gt;, the state is described as “ data you need to rebuild your UI at any point in time.”&lt;/p&gt;

&lt;p&gt;A state can either be contained in a single widget, known as a local state. Flutter provides inbuilt classes and methods to deal with self-contained states like &lt;code&gt;StatefulWidget&lt;/code&gt; and &lt;code&gt;setState&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, a state that has to be shared across different widgets is known as an app state. It is at this point we introduce state management tools.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;We will be using &lt;a href="https://pub.dev/packages/provider" rel="noreferrer noopener"&gt;Provider&lt;/a&gt; for the state management.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Let’s say you were to architect an application that includes only the below screen. How would you do?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hint: Using MVVM&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AKG0NtOrb3RIKXR4HJ2Amfw.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AKG0NtOrb3RIKXR4HJ2Amfw.png" alt="Sample Screen"&gt;&lt;/a&gt;Sample Screen&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Each screen should comprise its own folder. Create a folder called &lt;code&gt;home&lt;/code&gt; which contains a view called &lt;code&gt;home_view&lt;/code&gt;
&lt;/li&gt;&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;Naming convention&lt;/strong&gt;: Each screen is called view and the file is suffixed with &lt;code&gt;_view&lt;/code&gt; The view will be listening to the changes happening on the view model, using the &lt;code&gt;&lt;a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html" rel="noreferrer noopener"&gt;Consumer&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;Each view should have a view model associated with it. Create a file called &lt;code&gt;home_view_model&lt;/code&gt; which will be responsible for accepting the user interactions, processing them by running some business logic, and finally responding back.&lt;/li&gt;&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;Naming convention&lt;/strong&gt;: Each screen has a view model associated with it and the file is suffixed with &lt;code&gt;_view_model&lt;/code&gt; The view model notifies the changes to the UI (if any) using the &lt;code&gt;&lt;a href="https://api.flutter.dev/flutter/foundation/ChangeNotifier/notifyListeners.html" rel="noreferrer noopener"&gt;notifyListeners&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;Assuming the button calls some API (more on that later) and responds back with some response. This response should be converted as a model suffixed with &lt;code&gt;_model&lt;/code&gt; and returned from the view model to the view.&lt;/li&gt;&lt;/ul&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A7kmY0bEok_LIUyU9Iv8akA.png" alt="MVVM Project Structure"&gt;MVVM Project Structure





&lt;p&gt;This is the basics of MVVM, as we can see in the screenshot above. This can be replicated for all the screens of your app. Now, let’s see slight addition on top of this structure.&lt;/p&gt;





&lt;h3&gt;Extending MVVM with Repository and Services&lt;/h3&gt;





&lt;p&gt;In the real world, our app needs to interact with APIs or 3rd party integrated services. So here we introduce something called as &lt;code&gt;Repository&lt;/code&gt; .&lt;/p&gt;





&lt;p&gt;A repository pattern provides an abstraction of data so that your application can work with a simple abstraction that has an interface. Using this pattern can help achieve loose coupling. If implemented correctly, the Repository pattern can be a great way to ensure you follow the &lt;strong&gt;Single Responsibility Principle&lt;/strong&gt; for your data access code&lt;/p&gt;





&lt;p&gt;Some benefits of using the Repository pattern:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;Separate the business logic for accessing external services.&lt;/li&gt;
&lt;li&gt;Makes mocking easier and allows to do unit tests.&lt;/li&gt;
&lt;li&gt;We can easily switch data sources without doing time-consuming code changes&lt;/li&gt;
&lt;/ol&gt;





&lt;p&gt;Some disadvantages of using the Repository pattern:&lt;/p&gt;





&lt;ol&gt;&lt;li&gt;Adds another layer of abstraction which adds a certain level of complexity making it overkill for small applications.&lt;/li&gt;&lt;/ol&gt;





&lt;p&gt;Continuing with the previous example, let’s say our button needs to call an API, let’s implement it using &lt;code&gt;Repository&lt;/code&gt; pattern.&lt;/p&gt;





&lt;p&gt;Dart has no interfaces like Java but we can create it with an abstract class. We begin by creating an abstract class that defines the interface for our &lt;code&gt;home_repo&lt;/code&gt;&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CarouselModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;


&lt;blockquote&gt;&lt;p&gt;This abstract class helps to create a boundary, and we are free to work on either side of that boundary. We could work on implementing the home repository (&lt;code&gt;recommended&lt;/code&gt;), or we could just use the implementation directly in our app (&lt;code&gt;not recommended&lt;/code&gt;).&lt;/p&gt;&lt;/blockquote&gt;





&lt;p&gt;Here, the &lt;code&gt;HomeRepository&lt;/code&gt; has only one method which is &lt;code&gt;fetchData&lt;/code&gt; and this method returns the response as a model called &lt;code&gt;CarouselModel&lt;/code&gt; &lt;/p&gt;





&lt;p&gt;Next, let’s implement the &lt;code&gt;HomeRepository&lt;/code&gt; &lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeRepositoryImpl&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;HomeRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CarouselModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;milliseconds:&lt;/span&gt; &lt;span class="mi"&gt;1800&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;rootBundle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'assets/data/first_screen.json'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;carouselModelFromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&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;Inside the method &lt;code&gt;fetchData&lt;/code&gt;we introduce a delay and then load the data from the assets which is a JSON file. This delay is basically a substitute for calling the API, &lt;em&gt;but I hope I am able to convey my thoughts to the reader.&lt;/em&gt;&lt;/p&gt;





&lt;p&gt;As your application grows, you may find yourself adding more and more methods to a given repository. In this scenario, consider creating multiple repositories, and keeping related methods together.&lt;/p&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2Aq1BNWS5-00kEkAVE3ob9qw.png" alt="Repository Pattern"&gt;Repository Pattern





&lt;p&gt;So till now, we have&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;carousel_model&lt;/code&gt; representing the &lt;strong&gt;Model (M)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;home_view&lt;/code&gt; representing the &lt;strong&gt;View (V)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;home_view_model&lt;/code&gt; representing the &lt;strong&gt;View Model (VM)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;home_repo&lt;/code&gt; representing the &lt;strong&gt;Repository&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Register the Repository&lt;/h4&gt;

&lt;p&gt;Since our repository is ready, now we need to figure out how to register it and make it available inside our app. This is the time we introduce another concept called DI aka Dependency Injection. We make use of the package &lt;code&gt;&lt;a href="https://pub.dev/packages/get_it" rel="noreferrer noopener"&gt;get_it&lt;/a&gt;&lt;/code&gt; As per the documentation:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;This is a simple Service Locator for Dart and Flutter projects with some additional goodies highly inspired by &lt;a href="https://github.com/reactiveui/splat" rel="noreferrer noopener"&gt;Splat&lt;/a&gt;. It can be used instead of &lt;code&gt;InheritedWidget&lt;/code&gt; or &lt;code&gt;Provider&lt;/code&gt; to access objects e.g. from your UI.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;GetIt is super fast&lt;/strong&gt; because it uses just an &lt;code&gt;Map&amp;lt;Type&amp;gt;&lt;/code&gt; inside which makes access to it &lt;strong&gt;O(1). &lt;/strong&gt;GetIt itself is a singleton so you can access it from everywhere using its &lt;code&gt;instance&lt;/code&gt; property (see below).&lt;/p&gt;

&lt;p&gt;We install &lt;code&gt;get_it&lt;/code&gt; it by including it inside the &lt;code&gt;pubspec.yaml&lt;/code&gt; as&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="nl"&gt;dependencies:&lt;/span&gt;
  &lt;span class="nl"&gt;get_it:&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mf"&gt;7.2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Typically at the start of your app, you register the types that you want later access from anywhere in your app. After that, you can access instances of the registered types by calling the &lt;code&gt;locator&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;The nice thing is you can register an interface or abstract class together with a concrete implementation. When accessing the instance you always ask for the interface/abstract class type. This makes it easy to switch the implementation by just switching the concrete type at registration time.&lt;/p&gt;

&lt;p&gt;We create a file called as &lt;code&gt;locator.dart&lt;/code&gt; inside which we will instantiate the object of &lt;code&gt;get_it&lt;/code&gt; &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;GetIt&lt;/span&gt; &lt;span class="n"&gt;locator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetIt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setupLocator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HomeRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HomeRepoImpl&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="c1"&gt;// Alternatively you could write it&lt;/span&gt;
  &lt;span class="n"&gt;GetIt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;I&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HomeRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;HomeRepoImpl&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;As Dart supports global variables we assign the GetIt instance to a global variable to make access to it as easy as possible. &lt;/p&gt;

&lt;p&gt;Although GetIt is a singleton we will assign its instance to a global variable &lt;code&gt;locator&lt;/code&gt; to minimize the code for accessing GetIt. Any call to &lt;code&gt;locator&lt;/code&gt; in any package of a project will get the same instance of &lt;code&gt;GetIt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, we use the &lt;code&gt;locator&lt;/code&gt; and use the &lt;code&gt;registerFactory&lt;/code&gt; to register our &lt;code&gt;HomeRepository&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider as an alternative to GetIt&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The provider is a powerful alternative to GetIt. But there are some reasons why people use GetIt for Dependency injection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provider needs a &lt;code&gt;BuildContext&lt;/code&gt; to access the registered objects, so you can’t use it inside business objects outside the Widget tree or in a pure dart package.&lt;/li&gt;
&lt;li&gt;The provider adds its own Widget classes to the widget tree that are no GUI elements but are needed to access the in Provider registered objects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Testing Repository&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can implement unit testing for different elements of your Flutter applications, such as widgets, controllers, models, services, and repositories. It’s possible to unit-test repository-based Flutter codebases with the following strategies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement a mock repository class and test the logic&lt;/li&gt;
&lt;li&gt;You don’t need to implement mock classes by yourself — the &lt;a href="https://pub.dev/packages/mockito" rel="noreferrer noopener"&gt;Mockito package&lt;/a&gt; helps you to generate them quickly and &lt;a href="https://medium.com/flutter-community/using-mockito-in-flutter-cd015d338277?source=your_stories_page-------------------------------------" rel="noreferrer noopener"&gt;automatically&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Integrate Repository in ViewModel&lt;/h4&gt;

&lt;p&gt;Now comes the time to use the Dependency Injection. But before that let’s see what is it.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;When class A uses some functionality of class B, then its said that class A has a dependency of class B.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Before we can use methods of other classes, we first need to create the object of that class (i.e. class A needs to create an instance of class B).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, transferring the task of creating the object to someone else and directly using the dependency is called dependency injection.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2A0r7__ZZKUzZLQbt_.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2A0r7__ZZKUzZLQbt_.png" alt="Dependency Injection"&gt;&lt;/a&gt;Dependency Injection&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits of using DI&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Supports Unit testing.&lt;/li&gt;
&lt;li&gt;Boilerplate code is reduced, as initializing of dependencies is done by another component (&lt;code&gt;locator&lt;/code&gt; in our case)&lt;/li&gt;
&lt;li&gt;Enables loose coupling.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Drawbacks of using DI&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It’s complex to learn, and if overused can lead to management issues and other problems.&lt;/li&gt;
&lt;li&gt;Many compile time errors are pushed to run-time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Coming back to our application, let’s see how we integrate.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeViewModel&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;ChangeNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;HomeViewModel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;homeRepo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;HomeRepository&lt;/span&gt; &lt;span class="n"&gt;homeRepo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Here, we create a constructor inside our &lt;code&gt;HomeViewModel&lt;/code&gt; and specify the &lt;code&gt;homeRepo&lt;/code&gt; as our required parameter. This way we direct that whosoever needs access to our view model will first have to pass the &lt;code&gt;homeRepo&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Initialize the service locator&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You need to register the services on app startup, so you can do that in &lt;code&gt;&lt;em&gt;main.dart&lt;/em&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Replace the standard&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;with the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'locator.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// INIT SERVICE LOCATOR  &lt;/span&gt;
  &lt;span class="n"&gt;setupLocator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;This will register any services you have with GetIt before the widget tree gets built.&lt;/p&gt;

&lt;p&gt;And if we recall, our &lt;code&gt;homeRepo&lt;/code&gt; was registered inside the &lt;code&gt;locator&lt;/code&gt; So in order to declare our view model, we follow this&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="n"&gt;setupLocator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;MultiProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;providers:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;ChangeNotifierProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;create:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HomeViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;repo:&lt;/span&gt; &lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HomeRepo&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;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;MainApp&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Inside our &lt;code&gt;main&lt;/code&gt; we call the &lt;code&gt;setupLocator&lt;/code&gt; which is the method that comprises all the registered dependencies under &lt;code&gt;locator.dart&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Next, inside our &lt;a href="https://pub.dev/documentation/provider/latest/provider/MultiProvider-class.html" rel="noreferrer noopener"&gt;MultiProvider&lt;/a&gt;, we specify the &lt;code&gt;HomeViewModel&lt;/code&gt; under the &lt;a href="https://pub.dev/documentation/provider/latest/provider/ChangeNotifierProvider-class.html" rel="noreferrer noopener"&gt;ChangeNotifierProvider&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;ChangeNotifierProvider creates a ChangeNotifier using &lt;code&gt;create&lt;/code&gt; and automatically disposes it when it is removed from the widget tree.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h4&gt;Using ViewModel inside the View&lt;/h4&gt;

&lt;p&gt;We have our repository registered and passed as a required parameter to our view model. Let’s see how to use the view model inside our view.&lt;/p&gt;

&lt;p&gt;There are two ways to access the view model inside the view&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using the &lt;code&gt;Consumer&amp;lt;T&amp;gt;&lt;/code&gt; widget.&lt;/li&gt;
&lt;li&gt;Using the &lt;code&gt;Provider.of&amp;lt;T&amp;gt;(context)&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;late&lt;/span&gt; &lt;span class="n"&gt;HomeViewModel&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;viewModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HomeViewModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;listen:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;WidgetsBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addPostFrameCallback&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We instantiate the &lt;code&gt;viewModel&lt;/code&gt; using &lt;strong&gt;Provider. of &lt;/strong&gt;inside the &lt;code&gt;home_view&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Provider.of&amp;lt;T&amp;gt;(context)&lt;/code&gt; is used when you need to access the dependency but you don’t want to make any changes to the User Interface. We simply set the &lt;code&gt;listen: false&lt;/code&gt; signifying that we don’t need to listen to updates from the ChangeNotifier. The &lt;code&gt;listen: false&lt;/code&gt; parameter is used to specify whenever you're using Provider to fetch an instance and call a method on that instance. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: We can also use the below&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;viewModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HomeViewModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;For reacting to the changes which happen to viewModel we use the Consumer when we want to rebuild the widgets when a value changes. It is a must to provide the type  so that the Provider can understand which dependency you are referring to.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HomeViewModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="c1"&gt;// YOUR WIDGET                     &lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="c1"&gt;// SOME EXPENSIVE WIDGET&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://pub.dev/documentation/provider/latest/provider/Consumer-class.html" rel="noreferrer noopener"&gt;Consumer&lt;/a&gt; widget doesn’t do any fancy work. It just calls &lt;a href="https://pub.dev/documentation/provider/latest/provider/Provider/of.html" rel="noreferrer noopener"&gt;Provider.of&lt;/a&gt; in a new widget, and delegates its &lt;code&gt;build&lt;/code&gt; implementation to the &lt;a href="https://pub.dev/documentation/provider/latest/provider/Consumer/builder.html" rel="noreferrer noopener"&gt;builder&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Consumer widget takes two parameters, the &lt;code&gt;builder&lt;/code&gt; parameter and the &lt;code&gt;child&lt;/code&gt; parameter (optional). The &lt;code&gt;child&lt;/code&gt; parameter is an expensive widget that does not get affected by any Change in the ChangeNotifier.&lt;/p&gt;

&lt;p&gt;This builder can be called multiple times (such as when the provided value change) and that is where we can rebuild our UI. The Consumer widget has two main purposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It allows obtaining a value from a provider when we don’t have a &lt;a href="https://api.flutter.dev/flutter/widgets/BuildContext-class.html" rel="noreferrer noopener"&gt;BuildContext&lt;/a&gt; that is a descendant of said provider, and therefore cannot use &lt;a href="https://pub.dev/documentation/provider/latest/provider/Provider/of.html" rel="noreferrer noopener"&gt;Provider. of&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It helps with performance optimization by providing more granular rebuilds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Unit tests for the view model (Optional)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can mock dependencies by creating an alternative implementation of a class by making use of the &lt;a href="https://pub.dev/packages/mockito" rel="noreferrer noopener"&gt;Mockito package&lt;/a&gt; as a shortcut.&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AraBWlTIpC0H5EKFM.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AraBWlTIpC0H5EKFM.png" alt="MVVM Architecture + Repository"&gt;&lt;/a&gt;MVVM Architecture + Repository&lt;/p&gt;

&lt;h4&gt;What are Services&lt;/h4&gt;

&lt;p&gt;Services are normal Dart classes that are written to do some specialized task in your app. The purpose of a service is to isolate a task, especially third-party packages that are volatile, and hide its implementation details from the rest of the app.&lt;/p&gt;

&lt;p&gt;Some common examples you might create a service to handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using a 3rd party package, for instance, read and write to local storage (shared preferences)&lt;/li&gt;
&lt;li&gt;Using Cloud Providers like Firebase or some other third-party package.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s say you’re using &lt;a href="https://pub.dev/packages/package_info_plus" rel="noreferrer noopener"&gt;package_info&lt;/a&gt; to get the package details of your app.&lt;/p&gt;

&lt;p&gt;You use the package directly inside the app and after some time you found an even great package. You go through and replace all the references of &lt;code&gt;package_info&lt;/code&gt;with the new package &lt;code&gt;some_great_package&lt;/code&gt;. This was surely &lt;strong&gt;a waste of your time and effort&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s say the product owners found, that no user was using this feature, instead, they request a new feature. You go through and remove all the references with the &lt;code&gt;some_great_package&lt;/code&gt; This was again &lt;strong&gt;a waste of your time and effort&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The point is when you have tight coupling to some function scattered around your code, it makes it difficult and error-prone to change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clean coding takes upfront time and effort but will save you more time and effort in the long run&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is where &lt;code&gt;services&lt;/code&gt; come in. You make a new class and call it something like &lt;code&gt;PackageInfoService&lt;/code&gt;. The rest of the classes in the app don’t know how it works internally. They just call methods on the service to get the result.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PackageInfoService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;appVersion&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PackageInfoServiceImpl&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;PackageInfoService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;appVersion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;packageInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;PackageInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromPlatform&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;packageInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;packageInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buildNumber&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;'v&lt;/span&gt;&lt;span class="si"&gt;$version&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;$build&lt;/span&gt;&lt;span class="s"&gt;)'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;This makes it easy to change. If you want to switch &lt;code&gt;package_info&lt;/code&gt; to a&lt;code&gt;some_great_package&lt;/code&gt; just alter the code inside the service class. Updating the service code automatically affects everywhere the service is used inside the app.&lt;/li&gt;
&lt;li&gt;Supports swapping around implementations. You can create a “fake” implementation that just returns hard-coded data, while the other team is finalizing/developing the service implementation.&lt;/li&gt;
&lt;li&gt;Sometimes the implementation may rely on other services. For example, you &lt;code&gt;xyzService&lt;/code&gt; might use a service for making a network call to get other types of data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Register your service&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using a service locator like GetIt is a convenient way to provide services throughout your app&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We use the &lt;code&gt;locator&lt;/code&gt; to register our &lt;code&gt;PackageInfoService&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;We will be registering &lt;code&gt;PackageInfoService&lt;/code&gt; as a lazy singleton. It only gets initialized when it’s first used. If you want it to be initialized on app startup, then use &lt;code&gt;registerSingleton()&lt;/code&gt; it instead. Since it’s a singleton, you’ll always have the same instance of your service.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setupLocator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerLazySingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PackageInfoService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="n"&gt;PackageInfoServiceImpl&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;&lt;strong&gt;Using the service&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since we registered the service using the GetIt, we can get a reference to the service from anywhere in the code&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;PackageInfoService&lt;/span&gt; &lt;span class="n"&gt;packageService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PackageInfoService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Then you can use it within that class like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;packageService.getSomeValue()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;packageService.doSomething(someValue)&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Unit tests for the service (Optional)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can mock dependencies by creating an alternative implementation of the service class by making use of the &lt;a href="https://pub.dev/packages/mockito" rel="noreferrer noopener"&gt;Mockito package&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Brief:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;repository&lt;/code&gt; is for accessing objects in a collection-like manner.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;service&lt;/code&gt; is a class with methods for executing business logic, that may coordinate various other services (such as multiple repositories) to perform a single action or get a single result.&lt;/li&gt;
&lt;/ul&gt;

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


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/dynamism"&gt;&lt;em&gt;Source code.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>productivity</category>
      <category>programming</category>
      <category>dart</category>
    </item>
    <item>
      <title>Google Pay in Flutter</title>
      <dc:creator>aseem wangoo</dc:creator>
      <pubDate>Sat, 20 Aug 2022 03:36:45 +0000</pubDate>
      <link>https://forem.com/aseemwangoo/google-pay-in-flutter-3mfh</link>
      <guid>https://forem.com/aseemwangoo/google-pay-in-flutter-3mfh</guid>
      <description>&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;We will cover briefly:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;What is Google Pay&lt;/li&gt;
&lt;li&gt;Integration of Google Pay&lt;/li&gt;
&lt;li&gt;Payment results&lt;/li&gt;
&lt;li&gt;UI elements&lt;/li&gt;
&lt;/ol&gt;



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

&lt;h3&gt;What is Google Pay&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Google Pay&lt;/strong&gt; (known as &lt;strong&gt;G Pay&lt;/strong&gt;) is a &lt;a href="https://en.wikipedia.org/wiki/Digital_wallet" rel="noreferrer noopener"&gt;digital wallet&lt;/a&gt; platform and &lt;a href="https://en.wikipedia.org/wiki/E-commerce_payment_system" rel="noreferrer noopener"&gt;online payment&lt;/a&gt; system developed by Google to power in-app, online, and in-person &lt;a href="https://en.wikipedia.org/wiki/Contactless_payment" rel="noreferrer noopener"&gt;contactless purchases&lt;/a&gt; on mobile devices. Users in the United States and India can also use an iOS device, albeit with limited functionality. In addition to this, the service also supports passes such as coupons, boarding passes, campus ID cards, car keys, event tickets, movie tickets, public transportation tickets, store cards, health records, and loyalty cards.&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AKs13MatS9oAHG1pK" 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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AKs13MatS9oAHG1pK" alt="Google Pay logo"&gt;&lt;/a&gt;Google Pay logo&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;How it works&lt;/strong&gt;&lt;/h4&gt;

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

&lt;p&gt;Inside the app, when a user taps the Google Pay button, they see a payment sheet that displays the payment methods saved to their Google Account. Users can quickly select a payment method, add an optional shipping address, or add new information before finalizing the payment.&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2ArZOj9-Q1oGbxo7qLKWHbfg.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2ArZOj9-Q1oGbxo7qLKWHbfg.png" alt="Google Pay payment flow"&gt;&lt;/a&gt;Google Pay payment flow&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user taps the G Pay button and sees a payment sheet with a list of supported payment methods.&lt;/li&gt;
&lt;li&gt;The user selects a payment method and G Pay returns a payment token for the selected method to the app.&lt;/li&gt;
&lt;li&gt;The app submits the payment token to the backend&lt;/li&gt;
&lt;li&gt;The backend processes the purchase and sends the payment token to the Payment Service Provider (PSP)&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;G Pay&lt;/strong&gt; integrates with &lt;a href="https://developers.google.com/pay/api#participating-processors" rel="noreferrer noopener"&gt;these payment processors&lt;/a&gt; (PSP).&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;Integration of Google Pay&lt;/h3&gt;

&lt;p&gt;We will be looking to the &lt;a href="https://pub.dev/packages/pay" rel="noreferrer noopener"&gt;pay&lt;/a&gt; package for integration of Google Pay. This package takes care of both &lt;a href="https://www.apple.com/sg/apple-pay/" rel="noreferrer noopener"&gt;Apple Pay&lt;/a&gt; and &lt;a href="https://pay.google.com/" rel="noreferrer noopener"&gt;Google Pay&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Under the hood, this package uses the &lt;a href="https://developers.google.com/pay/api" rel="noreferrer noopener"&gt;Google Pay API&lt;/a&gt;. The things required to set up the Pay API will eventually be required to integrate the &lt;a href="https://pub.dev/packages/pay" rel="noreferrer noopener"&gt;pay&lt;/a&gt; package&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;Setup:&lt;/strong&gt;&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Check out their integration requirements &lt;a href="https://developers.google.com/pay/api/android/overview" rel="noreferrer noopener"&gt;here&lt;/a&gt;. It basically mentions their environments, brand guidelines, and other stuff.&lt;/li&gt;
&lt;li&gt;Check out their request for production access &lt;a href="https://developers.google.com/pay/api/android/guides/test-and-deploy/request-prod-access" rel="noreferrer noopener"&gt;here&lt;/a&gt;, wherein you set up access to Google Wallet API and other checklists.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;&lt;p&gt;Now comes the setting up of your code.&lt;/p&gt;&lt;/blockquote&gt;

&lt;ul&gt;&lt;li&gt;Internally Google API requires the following Gradle dependency (&lt;strong&gt;from android native&lt;/strong&gt;) which is handled by the &lt;/li&gt;&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s"&gt;"com.google.android.gms:play-services-wallet:18.0.0"&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Hence, we need to change the following in the &lt;code&gt;build.gradle&lt;/code&gt; of your app&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="n"&gt;minSdkVersion&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;
&lt;span class="n"&gt;compileSdkVersion&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;


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

&lt;/div&gt;

&lt;ul&gt;&lt;li&gt;Include the &lt;a href="https://pub.dev/packages/pay" rel="noreferrer noopener"&gt;package&lt;/a&gt; inside your &lt;code&gt;pubspec.yaml&lt;/code&gt;
&lt;/li&gt;&lt;/ul&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="c1"&gt;# pubspec.yaml&lt;/span&gt;
&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pay&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.0.10&lt;/span&gt;


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

&lt;/div&gt;


&lt;p&gt;ess to the &lt;a href="https://pub.dev/documentation/pay/latest/pay/GooglePayButton-class.html" rel="noreferrer noopener"&gt;GooglePayButton&lt;/a&gt; and the &lt;a href="https://pub.dev/documentation/pay/latest/pay/ApplePayButton-class.html" rel="noreferrer noopener"&gt;ApplePayButton&lt;/a&gt;&lt;/p&gt;





&lt;h4&gt;GooglePayButton&lt;/h4&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AnemAUFeDd-dH97qmeOecTg.png" alt="Google Pay Button"&gt;Google Pay Button





&lt;p&gt;It’s a widget to show the Google Pay button according to the rules and constraints specified in &lt;a href="https://pub.dev/documentation/pay/latest/pay/PayButton-class.html" rel="noreferrer noopener"&gt;PayButton&lt;/a&gt;.&lt;/p&gt;





&lt;p&gt;This widget provides an alternative UI-based integration path that wraps the API calls of the payment libraries and includes them as part of the lifecycle of the widget. Hence:&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;The widget only shows if the &lt;a href="https://pub.dev/documentation/pay/latest/pay/Pay/userCanPay.html" rel="noreferrer noopener"&gt;Pay.userCanPay&lt;/a&gt; method returns true.&lt;/li&gt;&lt;/ul&gt;





&lt;p&gt;For instance, in case the code was running on iOS, then instead &lt;strong&gt;ApplePayButton&lt;/strong&gt; will be shown (provided you have set up the &lt;a href="https://developer.apple.com/documentation/passkit/apple_pay/setting_up_apple_pay_requirements" rel="noreferrer noopener"&gt;ApplePay configuration&lt;/a&gt;).&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;And tapping the button automatically triggers the &lt;a href="https://pub.dev/documentation/pay/latest/pay/Pay/showPaymentSelector.html" rel="noreferrer noopener"&gt;Pay.showPaymentSelector&lt;/a&gt; method which starts the payment process.&lt;/li&gt;&lt;/ul&gt;





&lt;p&gt;This is what the &lt;strong&gt;GooglePayButton&lt;/strong&gt; looks like.&lt;/p&gt;





&lt;blockquote&gt;&lt;p&gt;Note: GooglePayButton&lt;/p&gt;&lt;/blockquote&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;GooglePayButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;paymentConfigurationAsset:&lt;/span&gt; &lt;span class="s"&gt;'google_pay_config.json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;paymentItems:&lt;/span&gt; &lt;span class="n"&gt;_paymentItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;GooglePayButtonStyle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;black&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;type:&lt;/span&gt; &lt;span class="n"&gt;GooglePayButtonType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;margin:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;top:&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;onPaymentResult:&lt;/span&gt; &lt;span class="n"&gt;onGooglePayResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;loadingIndicator:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;CircularProgressIndicator&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;h4&gt;PaymentConfiguration&lt;/h4&gt;





&lt;p&gt;In the above snippet, we see &lt;code&gt;PaymentConfiguration&lt;/code&gt; which is a required parameter. This parameter holds the information about a payment transaction.&lt;/p&gt;





&lt;p&gt;It loads the configuration information needed for the payment transaction, which is based on the source. There are 2 options available for this:&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;from a remote server&lt;/li&gt;&lt;/ul&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;PaymentConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromJsonString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;'{"provider": "apple_pay", "data": {}}'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;


&lt;ul&gt;&lt;li&gt; folder like this&lt;/li&gt;&lt;/ul&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A73ep_gQo_uxMH9ixuyp5EQ.png" alt="PaymentConfiguration from asset"&gt;PaymentConfiguration from asset





&lt;p&gt;&lt;strong&gt;Inside PaymentConfiguration&lt;/strong&gt;&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;The PaymentConfiguration is a JSON in which each parameter stands for a request object as per the Google Pay&lt;/li&gt;&lt;/ul&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"google_pay"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"TEST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"apiVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"apiVersionMinor"&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="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"allowedPaymentMethods"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"CARD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"tokenizationSpecification"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"PAYMENT_GATEWAY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"gateway"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"gatewayMerchantId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"gatewayMerchantId"&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"allowedCardNetworks"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="s2"&gt;"VISA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="s2"&gt;"MASTERCARD"&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"allowedAuthMethods"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="s2"&gt;"PAN_ONLY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="s2"&gt;"CRYPTOGRAM_3DS"&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"billingAddressRequired"&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="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"billingAddressParameters"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"FULL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"phoneNumberRequired"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"merchantInfo"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"merchantId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"01234567890123456789"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"merchantName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Example Merchant Name"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"transactionInfo"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"countryCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"US"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"currencyCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;n either be &lt;strong&gt;apple_pay&lt;/strong&gt; or &lt;strong&gt;google_pay&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;data&lt;/code&gt; : This is the core of the PaymentRequest which is a JSONObject itself&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;environment&lt;/code&gt; : This can either be &lt;strong&gt;TEST &lt;/strong&gt;or &lt;strong&gt;PRODUCTION&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a Test Card Suite provided by Google, which can only be used inside the &lt;strong&gt;TEST &lt;/strong&gt;environment. For getting access to these test cards, join &lt;a href="https://groups.google.com/forum/#!forum/googlepay-test-mode-stub-data" rel="noreferrer noopener"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The test environment supports the &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visa, Mastercard, Discover, and Amex card networks&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PAN_ONLY&lt;/code&gt; and &lt;code&gt;CRYPTOGRAM_3DS&lt;/code&gt; authentication methods&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;apiVersion&lt;/code&gt; : The value is &lt;code&gt;2&lt;/code&gt; for this specification.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apiVersionMinor&lt;/code&gt; : The value is &lt;code&gt;0&lt;/code&gt; for this specification.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;allowedPaymentMethods&lt;/code&gt; : This is of type &lt;strong&gt;PaymentMethod&lt;/strong&gt; and specifies the support for one or more payment methods supported by the G Pay API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;PaymentMethod&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This comprises 3 properties:&lt;/p&gt;

&lt;ol&gt;&lt;li&gt;
&lt;code&gt;type&lt;/code&gt; : &lt;strong&gt;CARD &lt;/strong&gt;is the only supported value for this parameter&lt;/li&gt;&lt;/ol&gt;





&lt;p&gt;2. &lt;code&gt;tokenizationSpecification&lt;/code&gt; This is of type &lt;strong&gt;TokenizationSpecification &lt;/strong&gt;and has two properties&lt;/p&gt;





&lt;p&gt;&lt;strong&gt;TokenizationSpecification&lt;/strong&gt;&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt; : For &lt;code&gt;CARD&lt;/code&gt; payment method, use PAYMENT_GATEWAY.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;parameters&lt;/code&gt; : Comprises a Gateway object which has two properties &lt;strong&gt;gateway&lt;/strong&gt; and &lt;strong&gt;gatewayMerchantId.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;





&lt;blockquote&gt;&lt;p&gt;Note: The values for Gateway depend on the supported &lt;a href="https://developers.google.com/pay/api/android/reference/request-objects#gateway" rel="noreferrer noopener"&gt;gateway&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;





&lt;p&gt;3. &lt;code&gt;parameters&lt;/code&gt; This is of type &lt;strong&gt;CardParameter &lt;/strong&gt;and has &lt;strong&gt;2 required&lt;/strong&gt; and &lt;strong&gt;5 optional&lt;/strong&gt; parameters&lt;/p&gt;





&lt;p&gt;&lt;strong&gt;CardParameter&lt;/strong&gt;&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;
&lt;code&gt;allowedAuthMethods&lt;/code&gt; (&lt;strong&gt;required&lt;/strong&gt;): A string array of fields that are supported to authenticate a card transaction. &lt;strong&gt;PAN_ONLY&lt;/strong&gt; and &lt;strong&gt;CRYPTOGRAM_3DS&lt;/strong&gt;
&lt;/li&gt;&lt;/ul&gt;





&lt;blockquote&gt;&lt;p&gt;Note: We can only use these 2 under TEST environment&lt;/p&gt;&lt;/blockquote&gt;





&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;allowedCardNetworks&lt;/code&gt; (&lt;strong&gt;required&lt;/strong&gt;): One or more card networks that you and Google Pay API support. eg &lt;strong&gt;AMEX, DISCOVER, INTERAC, JCB, MASTERCARD, VISA&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;billingAddressRequired&lt;/code&gt; : Set to &lt;code&gt;true&lt;/code&gt; if you require a billing address. This can increase friction.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;billingAddressParameters&lt;/code&gt; : This is of type &lt;strong&gt;BillingAddressParameters &lt;/strong&gt;and has 2 parameters&lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;BillingAddressParameters&lt;/strong&gt;&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;format&lt;/code&gt; : Billing address format which is required to complete the transaction. eg &lt;strong&gt;MIN(&lt;/strong&gt;Name, country code, and postal code&lt;strong&gt;)&lt;/strong&gt; and &lt;strong&gt;FULL &lt;/strong&gt;(long list of parameters)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;phoneNumberRequired&lt;/code&gt; : Set to &lt;code&gt;true&lt;/code&gt; if a phone number is required to process the transaction.&lt;/li&gt;
&lt;/ul&gt;





&lt;ul&gt;&lt;li&gt;
&lt;code&gt;merchantInfo&lt;/code&gt; : This &lt;strong&gt;MerchantInfo&lt;/strong&gt; object provides information about the merchant that requests payment data and comprises of &lt;/li&gt;&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;merchantName&lt;/strong&gt;: This name is rendered in the payment sheet. In the &lt;code&gt;TEST&lt;/code&gt; environment, or if a merchant isn't recognized, a “Pay Unverified Merchant” message is displayed on the payment sheet.&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;
&lt;code&gt;transactionInfo&lt;/code&gt; : This &lt;strong&gt;TransactionInfo&lt;/strong&gt; object is used to present a payment authorization dialog. It comprises of&lt;/li&gt;&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;currencyCode (required) : &lt;/strong&gt;ISO 4217 Alphabetic currency code&lt;/p&gt;





&lt;p&gt;&lt;strong&gt;countryCode: &lt;/strong&gt;ISO 3166–1 alpha-2 country code where the transaction is processed.&lt;/p&gt;





&lt;h3&gt;Payment Results&lt;/h3&gt;





&lt;p&gt;Once the G Pay button is clicked, it triggers the presentation of the payment sheet. Once the user makes a selection, the sheet closes a&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"apiVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"apiVersionMinor"&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="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"paymentMethodData"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"YOUR CARD DESCRIPTION"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"info"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"billingAddress"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"address1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"YOUR ADDRESS1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"address2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"YOUR ADDRESS2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"address3"&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="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"administrativeArea"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"YOUR AREA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"countryCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"YOUR COUNTRY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"locality"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"YOUR LOCALITY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"YOUR NAME"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"phoneNumber"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"YOUR PHONE NUMBER"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"postalCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt;YOUR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;POSTAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;CODE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"sortingCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"cardDetails"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="err"&gt;YOUR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;CARD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;DETAILS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"cardNetwork"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"VISA"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tokenizationData"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"examplePaymentMethodToken"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"PAYMENT_GATEWAY"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"CARD"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


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

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ion&lt;/code&gt; : The value is &lt;code&gt;2&lt;/code&gt; for this specification&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apiVersionMinor&lt;/code&gt; : The value is &lt;code&gt;0&lt;/code&gt; for this specification&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;paymentMethodData&lt;/code&gt; : This value is of type &lt;strong&gt;PaymentMethodData &lt;/strong&gt;and comprises 4 parameters&lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;&lt;strong&gt;PaymentMethodData&lt;/strong&gt;&lt;/p&gt;





&lt;p&gt;If the selection is successful, the result is fulfilled with a &lt;a href="https://developers.google.com/pay/api/android/reference/object#PaymentData" rel="noreferrer noopener"&gt;PaymentData&lt;/a&gt; object including relevant information about the payment method selected:&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt; : PaymentMethod type which was selected in the G Pay payment sheet&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt; : This contains the user-facing message describing the payment method&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tokenizationData&lt;/code&gt; : This value is of type &lt;strong&gt;PaymentMethodTokentizationData &lt;/strong&gt;and consists of 2 parameters&lt;/li&gt;
&lt;/ul&gt;





&lt;p&gt;&lt;code&gt;type&lt;/code&gt; : Type of tokenization applied to the selected payment method&lt;/p&gt;





&lt;p&gt;&lt;code&gt;token&lt;/code&gt; : Generated payment method token. eg &lt;strong&gt;PAYMENT_GATEWAY&lt;/strong&gt;, &lt;strong&gt;DIRECT&lt;/strong&gt;&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;
&lt;code&gt;info&lt;/code&gt; : This comprises 3 parameters &lt;strong&gt;billingAddress, cardDetails, &lt;/strong&gt;and &lt;strong&gt;cardNetwork&lt;/strong&gt;
&lt;/li&gt;&lt;/ul&gt;





&lt;p&gt;The billing address is present in the form of an &lt;a href="https://developers.google.com/pay/api/android/reference/response-objects#Address" rel="noreferrer noopener"&gt;Address Object&lt;/a&gt;. CardDetails are present in a string that represents the details of the card. This value is commonly the last four digits of the selected payment account number. &lt;/p&gt;





&lt;p&gt;CardNetwork is also a string that represents the payment card network of the selected payment. This value is one of the values present inside the format of &lt;code&gt;allowedCardNetworks&lt;/code&gt; in &lt;a href="https://developers.google.com/pay/api/android/reference/request-objects#CardParameters" rel="noreferrer noopener"&gt;CardParameters&lt;/a&gt;.&lt;/p&gt;





&lt;h4&gt;After Payment Result&lt;/h4&gt;





&lt;p&gt;You can now use this payment method information to perform the actual transaction. For instance, you can get the &lt;code&gt;tokenizationData&lt;/code&gt; from the above response and extract the &lt;code&gt;token&lt;/code&gt; from it.&lt;/p&gt;





&lt;p&gt;Then, use this token to perform payment through your payment gateway. Check out the &lt;a href="https://developers.google.com/pay/api/#participating-google-pay-processors" rel="noreferrer noopener"&gt;list of supported processors&lt;/a&gt; to find out more about specific implementation details on each processor.&lt;/p&gt;





&lt;h3&gt;UI Elements&lt;/h3&gt;





&lt;p&gt;GooglePayButton exposes one of the parameters called &lt;code&gt;type&lt;/code&gt; (which is an enum) inside its definition. We can play with this param in order to display the Button as per the requirements. Following are the options provided:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;GooglePayButtonType.pay (this is the default value)&lt;/li&gt;
&lt;li&gt;GooglePayButtonType.book&lt;/li&gt;
&lt;li&gt;GooglePayButtonType.buy&lt;/li&gt;
&lt;li&gt;GooglePayButtonType.checkout&lt;/li&gt;
&lt;li&gt;GooglePayButtonType.donate&lt;/li&gt;
&lt;li&gt;GooglePayButtonType.order&lt;/li&gt;
&lt;li&gt;GooglePayButtonType.plain&lt;/li&gt;
&lt;li&gt;GooglePayButtonType.subscribe&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For instance, in case you want the type to be &lt;code&gt;GooglePayButtonType.subscribe&lt;/code&gt; then the result would be&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AY3Mt4ZVjyKWXGIKTQdMwDg.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AY3Mt4ZVjyKWXGIKTQdMwDg.png" alt="Subscribe with GPay"&gt;&lt;/a&gt;Subscribe with GPay&lt;/p&gt;

&lt;p&gt;If you prefer to have more control over each individual request and the button separately, you can instantiate a payment client and add the buttons to your layout independently, using &lt;a href="https://pub.dev/documentation/pay_android/latest/pay_android/RawGooglePayButton-class.html" rel="noreferrer noopener"&gt;RawGooglePayButton&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;RawGooglePayButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="n"&gt;onGooglePayPressed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;GooglePayButtonStyle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;type:&lt;/span&gt; &lt;span class="n"&gt;GooglePayButtonType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;plain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The result of this button is&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AT8ZGoo2ZCW2fAhGzXD_DQQ.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AT8ZGoo2ZCW2fAhGzXD_DQQ.png" alt="RawGooglePayButton"&gt;&lt;/a&gt;RawGooglePayButton&lt;/p&gt;

&lt;p&gt;Once the user clicks this button, you can initiate the request using the &lt;a href="https://pub.dev/documentation/pay/latest/pay/Pay/Pay.withAssets.html" rel="noreferrer noopener"&gt;Pay.withAssets&lt;/a&gt; which is an alternative to a &lt;a href="https://pub.dev/documentation/pay/latest/pay/Pay-class.html" rel="noreferrer noopener"&gt;Pay&lt;/a&gt; object with&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// PayClient&lt;/span&gt;
&lt;span class="n"&gt;Pay&lt;/span&gt; &lt;span class="n"&gt;_payClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Pay&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withAssets&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="s"&gt;'YOUR_GOOGLE_PAY_JSON_FILE'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;// On the Button Pressed&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onGooglePayPressed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&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="n"&gt;_payClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;showPaymentSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;provider:&lt;/span&gt; &lt;span class="n"&gt;PayProvider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;google_pay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;paymentItems:&lt;/span&gt; &lt;span class="n"&gt;_paymentItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The response which is the Google Pay token can be sent to your server / PSP&lt;/p&gt;

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


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/dynamism/tree/feature/gpay"&gt;&lt;em&gt;Source code.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>productivity</category>
      <category>programming</category>
      <category>dart</category>
    </item>
    <item>
      <title>How to add Flutter to Android App</title>
      <dc:creator>aseem wangoo</dc:creator>
      <pubDate>Thu, 19 May 2022 08:39:18 +0000</pubDate>
      <link>https://forem.com/aseemwangoo/how-to-add-flutter-to-android-app-41jg</link>
      <guid>https://forem.com/aseemwangoo/how-to-add-flutter-to-android-app-41jg</guid>
      <description>&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;We will cover briefly:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;Adding flutter to the existing android app&lt;/li&gt;
&lt;li&gt;Adding flutter to the new android app (Compose)&lt;/li&gt;
&lt;/ol&gt;





&lt;blockquote&gt;&lt;p&gt;Note: This article assumes the reader knows about android&lt;/p&gt;&lt;/blockquote&gt;



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

&lt;h4&gt;Add to App&lt;/h4&gt;

&lt;p&gt;It’s sometimes not practical to rewrite your entire application in Flutter. For those situations, Flutter can be integrated into your existing application piecemeal, as a library or module. That module can then be imported into your Android or iOS app to render a part of your app’s UI in Flutter.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;add-to-app&lt;/code&gt; feature supports integrating multiple instances of any screen size. Having multiple Flutter instances allows each instance to maintain an independent application and UI state while using minimal memory resources. See more on the &lt;a href="https://docs.flutter.dev/development/add-to-app/multiple-flutters" rel="noreferrer noopener"&gt;multiple Flutters&lt;/a&gt; page.&lt;/p&gt;

&lt;h4&gt;Adding flutter to the existing android app&lt;/h4&gt;

&lt;p&gt;Flutter 3 was announced on 11th May 2022. There was a talk called &lt;a href="https://youtu.be/w_ezWG1yKQQ?t=874" rel="noreferrer noopener"&gt;What’s New In Flutter&lt;/a&gt; in which the speaker showed an application called &lt;a href="https://github.com/flutter/put-flutter-to-work" rel="noreferrer noopener"&gt;Put Flutter to Work&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AQzTLD5GxRRIlbby2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AQzTLD5GxRRIlbby2.gif" alt="Put Flutter to Work"&gt;&lt;/a&gt;Put Flutter to Work&lt;/p&gt;

&lt;p&gt;We will be adding the &lt;a href="https://github.com/flutter/put-flutter-to-work/tree/main/flutter_nps" rel="noreferrer noopener"&gt;flutter feedback screen&lt;/a&gt; to the &lt;a href="https://github.com/flutter/put-flutter-to-work/tree/main/newsfeed_android" rel="noreferrer noopener"&gt;android app&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Begin&lt;/h4&gt;

&lt;p&gt;Let’s open the app’s &lt;code&gt;&lt;a href="https://github.com/flutter/put-flutter-to-work/blob/main/newsfeed_android/app/build.gradle" rel="noreferrer noopener"&gt;build.gradle&lt;/a&gt;&lt;/code&gt; and see the section under &lt;code&gt;repositories&lt;/code&gt; &lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;repositories&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;google&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;mavenCentral&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;storageUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://storage.googleapis.com"&lt;/span&gt;
    &lt;span class="n"&gt;maven&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="s1"&gt;'../../flutter_nps/build/host/outputs/repo'&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;maven&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="s2"&gt;"$storageUrl/download.flutter.io"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We see the project depends upon a local path inside the &lt;strong&gt;flutter_nps&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The same is observed if we open the project’s &lt;code&gt;&lt;a href="https://github.com/flutter/put-flutter-to-work/blob/main/newsfeed_android/build.gradle" rel="noreferrer noopener"&gt;build.gradle&lt;/a&gt;&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;The project also depends upon the following flutter specific dependencies&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;debugImplementation&lt;/span&gt; &lt;span class="s1"&gt;'com.example.flutter_nps:flutter_debug:1.0'&lt;/span&gt;
&lt;span class="n"&gt;profileImplementation&lt;/span&gt; &lt;span class="s1"&gt;'com.example.flutter_nps:flutter_profile:1.0'&lt;/span&gt;
&lt;span class="n"&gt;releaseImplementation&lt;/span&gt;&lt;span class="s1"&gt;'com.example.flutter_nps:flutter_release:1.0'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As of now, the path &lt;code&gt;flutter_nps/build/host/outputs/repo&lt;/code&gt; doesn’t exist in our machine, let’s investigate the &lt;strong&gt;flutter_nps&lt;/strong&gt; project now&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;Add the Flutter module as a dependency&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;There are two ways to add the Flutter module as a dependency on your existing app. We will be going with the &lt;strong&gt;AAR (Android Archive)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The AAR mechanism creates generic Android AARs as intermediaries that package your Flutter module. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This packages your Flutter library as a generic local Maven repository composed of AARs and POMs artifacts.&lt;/li&gt;
&lt;li&gt;We have the following folder structure for the &lt;strong&gt;flutter_nps&lt;/strong&gt; app&lt;/li&gt;
&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AtW6twLv4gG021SBlA4Vteg.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AtW6twLv4gG021SBlA4Vteg.png" alt="Flutter_nps project"&gt;&lt;/a&gt;Flutter_nps project&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;We use the following command for generating the AAR&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;flutter build aar&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which also shows us the on-screen instructions to integrate&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AWqp8TvQksLIBOXWjkDFedQ.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AWqp8TvQksLIBOXWjkDFedQ.png" alt="Flutter AAR integration steps"&gt;&lt;/a&gt;Flutter AAR integration steps&lt;/p&gt;

&lt;p&gt;and now if we run our android app, it should work…🎉🎉🎉🎉&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The android app which was used in the above section doesn’t use the Compose. In the next section, we will integrate Flutter in a Compose app&lt;/p&gt;&lt;/blockquote&gt;

&lt;h4&gt;Adding flutter to the new android app (Compose)&lt;/h4&gt;

&lt;p&gt;In this section, we will create a &lt;a href="https://github.com/AseemWangoo/AddFlutter" rel="noreferrer noopener"&gt;new android app&lt;/a&gt; but with Compose Activity.&lt;/p&gt;

&lt;h4&gt;Begin&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Create &lt;code&gt;New Project&lt;/code&gt; and Select &lt;code&gt;EmptyComposeActivity&lt;/code&gt; and this will create a Compose project&lt;/li&gt;
&lt;li&gt;We create a &lt;a href="https://github.com/AseemWangoo/AddFlutter/blob/master/app/src/main/java/com/example/addflutter/components/SimpleButtonComponent.kt" rel="noreferrer noopener"&gt;button component&lt;/a&gt; on the main screen&lt;/li&gt;
&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2ALB6TUuioXrqRenaYktoOQQ.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2ALB6TUuioXrqRenaYktoOQQ.png" alt="Compose Button"&gt;&lt;/a&gt;Compose Button&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Let’s open the app’s &lt;code&gt;&lt;a href="https://github.com/AseemWangoo/AddFlutter/blob/master/app/build.gradle" rel="noreferrer noopener"&gt;build.gradle&lt;/a&gt;&lt;/code&gt; and under &lt;code&gt;repositories&lt;/code&gt; add the following&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;repositories&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;google&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;mavenCentral&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;storageUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://storage.googleapis.com"&lt;/span&gt;
    &lt;span class="n"&gt;maven&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="s1"&gt;'../../flutter_nps/build/host/outputs/repo'&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;maven&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="s2"&gt;"$storageUrl/download.flutter.io"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and also add the above to the project’s &lt;code&gt;&lt;a href="https://github.com/AseemWangoo/AddFlutter/blob/master/build.gradle" rel="noreferrer noopener"&gt;build.gradle&lt;/a&gt;&lt;/code&gt; &lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Inside the &lt;code&gt;dependencies&lt;/code&gt; of app &lt;code&gt;&lt;a href="https://github.com/AseemWangoo/AddFlutter/blob/master/app/build.gradle" rel="noreferrer noopener"&gt;build.gradle&lt;/a&gt;&lt;/code&gt; add the following&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;debugImplementation&lt;/span&gt; &lt;span class="s1"&gt;'com.example.flutter_nps:flutter_debug:1.0'&lt;/span&gt;
&lt;span class="n"&gt;profileImplementation&lt;/span&gt; &lt;span class="s1"&gt;'com.example.flutter_nps:flutter_profile:1.0'&lt;/span&gt;
&lt;span class="n"&gt;releaseImplementation&lt;/span&gt;&lt;span class="s1"&gt;'com.example.flutter_nps:flutter_release:1.0'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;&lt;p&gt;Note: Try removing the &lt;code&gt;profileImplementation&lt;/code&gt; in case the gradle gives any errors&lt;/p&gt;&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;The above steps implies that our new project requires the AAR from the &lt;a href="https://github.com/flutter/put-flutter-to-work/tree/main/flutter_nps" rel="noreferrer noopener"&gt;flutter_nps&lt;/a&gt; (since we are reusing the same flutter project).&lt;/li&gt;
&lt;li&gt;The steps for building the AAR remain the same as we saw in the above section.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, we create the &lt;a href="https://github.com/AseemWangoo/AddFlutter/blob/master/app/src/main/java/com/example/addflutter/Application.kt" rel="noreferrer noopener"&gt;Application class&lt;/a&gt; which extends the &lt;code&gt;Application&lt;/code&gt; Also, register this inside our &lt;a href="https://github.com/AseemWangoo/AddFlutter/blob/master/app/src/main/AndroidManifest.xml" rel="noreferrer noopener"&gt;Manifest.xml&lt;/a&gt; under &lt;code&gt;android:name="&amp;lt;YOUR APPLICATION CLASS&amp;gt;"&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddFlutterApplication&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;flutterEngine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FlutterEngine&lt;/span&gt;
    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;FLUTTER_ENGINE_NAME&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"nps_flutter_engine_name"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;flutterEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FlutterEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;flutterEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dartExecutor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executeDartEntrypoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;DartExecutor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DartEntrypoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nc"&gt;FlutterEngineCache&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FLUTTER_ENGINE_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flutterEngine&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;ul&gt;
&lt;li&gt;We initialize the &lt;code&gt;&lt;a href="https://api.flutter.dev/javadoc/io/flutter/embedding/engine/FlutterEngine.html" rel="noreferrer noopener"&gt;FlutterEngine&lt;/a&gt;&lt;/code&gt; which is the container through which Dart code can be run in an Android application&lt;/li&gt;
&lt;li&gt;To start running Dart and/or Flutter within this &lt;code&gt;FlutterEngine&lt;/code&gt;, we get a reference to this engine's &lt;code&gt;&lt;a href="https://api.flutter.dev/javadoc/io/flutter/embedding/engine/dart/DartExecutor.html" rel="noreferrer noopener"&gt;DartExecutor&lt;/a&gt;&lt;/code&gt; and then use &lt;code&gt;&lt;a href="https://api.flutter.dev/javadoc/io/flutter/embedding/engine/dart/DartExecutor.html#executeDartEntrypoint%28io.flutter.embedding.engine.dart.DartExecutor.DartEntrypoint%29" rel="noreferrer noopener"&gt;DartExecutor.executeDartEntrypoint(DartExecutor.DartEntrypoint)&lt;/a&gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Finally, we cache the flutter engine to be used by the FlutterActivity&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FlutterEngineCache&lt;/code&gt; is useful for storing pre-warmed &lt;code&gt;&lt;a href="https://api.flutter.dev/javadoc/io/flutter/embedding/engine/FlutterEngine.html" rel="noreferrer noopener"&gt;FlutterEngine&lt;/a&gt;&lt;/code&gt; instances. The ID of a given &lt;code&gt;&lt;a href="https://api.flutter.dev/javadoc/io/flutter/embedding/engine/FlutterEngine.html" rel="noreferrer noopener"&gt;FlutterEngine&lt;/a&gt;&lt;/code&gt; can be any string&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since we are going to launch a Flutter activity, we will need to register it as an activity under &lt;a href="https://github.com/AseemWangoo/AddFlutter/blob/master/app/src/main/AndroidManifest.xml" rel="noreferrer noopener"&gt;Manifest.xml&lt;/a&gt; (otherwise it gives an error…)&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt;
  &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"io.flutter.embedding.android.FlutterActivity"&lt;/span&gt;
          &lt;span class="na"&gt;android:configChanges=&lt;/span&gt;&lt;span class="s"&gt;"orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|s creenLayout"&lt;/span&gt;
  &lt;span class="na"&gt;android:hardwareAccelerated=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
  &lt;span class="na"&gt;android:windowSoftInputMode=&lt;/span&gt;&lt;span class="s"&gt;"adjustResize"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At last, we need to launch the FlutterActivity.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;We do so by calling the &lt;code&gt;startActivity&lt;/code&gt; from the &lt;code&gt;context&lt;/code&gt; &lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nc"&gt;FlutterActivity&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withCachedEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AddFlutterApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FLUTTER_ENGINE_NAME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&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;ul&gt;&lt;li&gt;This &lt;code&gt;withCachedEngine&lt;/code&gt; can be used to configure an Intent to launch a FlutterActivity that internally uses an existing FlutterEngine that is cached and is identified using the cached engine ID (which is the same we used while registering inside the Application).&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;and now if we run our new android app, we see it working…🎉🎉🎉🎉&lt;/p&gt;

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


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/AddFlutter"&gt;&lt;em&gt;Source code.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>flutter</category>
      <category>programming</category>
      <category>android</category>
    </item>
    <item>
      <title>Unit testing in React</title>
      <dc:creator>aseem wangoo</dc:creator>
      <pubDate>Fri, 22 Apr 2022 09:56:49 +0000</pubDate>
      <link>https://forem.com/aseemwangoo/unit-testing-in-react-p23</link>
      <guid>https://forem.com/aseemwangoo/unit-testing-in-react-p23</guid>
      <description>&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;We will cover briefly:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;Write unit tests for components&lt;/li&gt;
&lt;li&gt;Snapshot Testing with Jest&lt;/li&gt;
&lt;/ol&gt;



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

&lt;h3&gt;About Unit Testing&lt;/h3&gt;

&lt;p&gt;Unit testing is a testing method that tests an individual software unit in isolation. This involves verifying the &lt;em&gt;output&lt;/em&gt; of a function or component for a given &lt;em&gt;input&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In terms of React components, this means checking that the component&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;renders as expected for the specified props.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;The main goal is to write tests that verify whether our component works as expected.&lt;/p&gt;

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

&lt;h4&gt;Intro to Jest&lt;/h4&gt;

&lt;p&gt;We will make use of &lt;a href="https://jestjs.io/" rel="noreferrer noopener"&gt;jest&lt;/a&gt; in order to test our react components. As per the documentation&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Jest is a JavaScript testing framework designed to ensure correctness of any JavaScript codebase. It allows you to write tests with an approachable, familiar and feature-rich API that gives you results quickly.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Let's see how to install it&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Install the following dev dependencies&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;renderer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;&lt;p&gt;Note: Make sure your &lt;code&gt;react&lt;/code&gt; and &lt;code&gt;react-test-renderer&lt;/code&gt; are using the same version&lt;/p&gt;&lt;/blockquote&gt;

&lt;h4&gt;Write unit tests for components&lt;/h4&gt;

&lt;p&gt;We will start by creating a simple text component, which looks like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2Am4j4_6bdvWhoOevKV4wtTg.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2Am4j4_6bdvWhoOevKV4wtTg.png" alt="Simple Text Component"&gt;&lt;/a&gt;Simple Text Component&lt;/p&gt;

&lt;p&gt;It takes in a parameter &lt;code&gt;text&lt;/code&gt; and displays using the &lt;code&gt;h3&lt;/code&gt; style tag onto the screen. &lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Take note of the &lt;strong&gt;data-testid. &lt;/strong&gt;This will be used for testing this component&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Let’s test this component now,&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;We create a folder called &lt;code&gt;__tests__&lt;/code&gt; which is present inside the &lt;code&gt;components&lt;/code&gt; folder. Inside this, we create component-specific folders&lt;/li&gt;&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AEX_1LanSBv46PnJajCH9_Q.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AEX_1LanSBv46PnJajCH9_Q.png" alt="Folder structure"&gt;&lt;/a&gt;Folder structure&lt;/p&gt;

&lt;p&gt;We have all the components under &lt;code&gt;components&lt;/code&gt; and all the tests under &lt;code&gt;__tests__&lt;/code&gt; This way we can create subfolders per component.&lt;/p&gt;

&lt;p&gt;eg: For &lt;code&gt;components/Text&lt;/code&gt; we have the corresponding test under &lt;code&gt;components/__tests__/Text&lt;/code&gt; folder&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;All the tests should be comprised of the convention &lt;code&gt;&amp;lt;TestName&amp;gt;.test.js&lt;/code&gt; This helps jest to understand the test files&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;So our test file would be &lt;code&gt;Text.test.js&lt;/code&gt; &lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Next, we import the package &lt;code&gt;&lt;em&gt;testing-library/react&lt;/em&gt;&lt;/code&gt;&lt;em&gt; &lt;/em&gt;along with the jest as&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cleanup&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="s2"&gt;@testing-library/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Text&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../Text/Text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@testing-library/jest-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;&lt;p&gt;Note: we also need to import the component which we want to test. In our case, it's the &lt;code&gt;Text&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;ul&gt;&lt;li&gt;This is how our test looks like&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;should render text component&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="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Text&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;var&lt;/span&gt; &lt;span class="nx"&gt;textElem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByTestId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;textElem&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeInTheDocument&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;&lt;strong&gt;test&lt;/strong&gt;: This creates a test closure, and takes in the par&lt;em&gt;am&lt;/em&gt; &lt;code&gt;name&lt;/code&gt; (name of your test) and param &lt;code&gt;fn&lt;/code&gt; (function for your test)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;render&lt;/strong&gt;: This comes from the &lt;code&gt;&lt;em&gt;testing-library/react&lt;/em&gt;&lt;/code&gt;It renders into a container that is appended to the document body. &lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;In our case, we render the &lt;code&gt;Text&lt;/code&gt; component&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;screen&lt;/strong&gt;: This can be thought of as a &lt;code&gt;document.body&lt;/code&gt;, which has every query that is bounded to the component you rendered in the previous call&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;We assigned a &lt;strong&gt;data-testid &lt;/strong&gt;to our Text component, and we try to get that using &lt;a href="https://testing-library.com/docs/queries/bytestid/" rel="noreferrer noopener"&gt;getByTestId&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Finally, we use &lt;code&gt;expect&lt;/code&gt; and &lt;code&gt;toBeInTheDocument&lt;/code&gt; to test that the element is present inside the rendered document. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&lt;a href="https://testing-library.com/docs/ecosystem-jest-dom" rel="noreferrer noopener"&gt;jest-dom&lt;/a&gt;&lt;/code&gt; utility library provides the &lt;code&gt;.toBeInTheDocument()&lt;/code&gt; matcher, which can be used to assert that an element is in the body of the document, or not.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Run the tests using&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AIeMq8iA5SIWoriit8pSmVw.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AIeMq8iA5SIWoriit8pSmVw.png" alt="Results from the unit test"&gt;&lt;/a&gt;Results from the unit test&lt;/p&gt;

&lt;p&gt;And, we wrote our first test 🎉🎉🎉&lt;/p&gt;

&lt;h3&gt;Snapshot Testing with Jest&lt;/h3&gt;

&lt;p&gt;Snapshot tests are a very useful tool whenever you want to make sure your UI does not change unexpectedly.&lt;/p&gt;

&lt;p&gt;Any snapshot test case renders a UI component, takes a snapshot, then compares it to a reference snapshot file stored alongside the test. The test will fail if the two snapshots do not match: either the change is unexpected, or the reference snapshot needs to be updated as per the new version of the UI component.&lt;/p&gt;

&lt;p&gt;Let’s test our &lt;code&gt;Text&lt;/code&gt; component.&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AI5lep5PgozgmaUq7efYmng.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AI5lep5PgozgmaUq7efYmng.png" alt="Snapshot testing with Jest"&gt;&lt;/a&gt;Snapshot testing with Jest&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;We will be making use of our &lt;code&gt;&lt;em&gt;react-test-renderer&lt;/em&gt;&lt;/code&gt;&lt;em&gt; &lt;/em&gt;library which we installed in the previous step.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Instead of rendering the graphical UI, which would require building the entire app, we can use a test renderer to quickly generate a serializable value for your React tree.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We use &lt;code&gt;renderer&lt;/code&gt; to create the &lt;code&gt;Text&lt;/code&gt; component&lt;/li&gt;
&lt;li&gt;Next, we save the response in the JSON using &lt;code&gt;toJSON&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Finally, we use the &lt;code&gt;expect&lt;/code&gt; to compare the result using &lt;code&gt;&lt;a href="http://This%20ensures%20that%20a%20value%20matches%20the%20most%20recent%20snapshot" rel="noreferrer noopener"&gt;toMatchSnapshot&lt;/a&gt; &lt;/code&gt;which ensures that the value matches the most recent snapshot.&lt;/li&gt;
&lt;li&gt;Run the tests using&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AXYLwJo4g0AAoojYNm1wh3w.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AXYLwJo4g0AAoojYNm1wh3w.png" alt="Snapshot testing in React"&gt;&lt;/a&gt;Snapshot testing in React&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Note: There will be no snapshots present when you run the snapshot tests for the first time. The console will tell to generate the snapshots &lt;/p&gt;&lt;/blockquote&gt;

&lt;ul&gt;&lt;li&gt;The snapshots are generated inside the &lt;code&gt;__snapshots__&lt;/code&gt; folder as &lt;/li&gt;&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AAmK8noXVKTy8hDuhdlww-Q.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AAmK8noXVKTy8hDuhdlww-Q.png" alt="Snapshots generated"&gt;&lt;/a&gt;Snapshots generated&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/expriments_with_react"&gt;&lt;em&gt;Source code.&lt;/em&gt;&lt;/a&gt;


&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Website: &lt;/em&gt;&lt;/strong&gt;&lt;a href="https://funwithreact.web.app/" rel="noreferrer noopener"&gt;&lt;strong&gt;&lt;em&gt;https://funwithreact.web.app/&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Using compose destinations</title>
      <dc:creator>aseem wangoo</dc:creator>
      <pubDate>Tue, 12 Apr 2022 14:47:15 +0000</pubDate>
      <link>https://forem.com/aseemwangoo/using-compose-destinations-158d</link>
      <guid>https://forem.com/aseemwangoo/using-compose-destinations-158d</guid>
      <description>&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;We will cover briefly:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;Current navigation in compose&lt;/li&gt;
&lt;li&gt;Using compose destinations&lt;/li&gt;
&lt;li&gt;(Optional) Modify existing test cases&lt;/li&gt;
&lt;/ol&gt;



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

&lt;h3&gt;Current navigation in compose&lt;/h3&gt;

&lt;p&gt;We get &lt;a href="https://developer.android.com/jetpack/compose/navigation" rel="noreferrer noopener"&gt;Compose Navigation&lt;/a&gt; from the Jetpack Compose. It provides a &lt;a href="https://developer.android.com/guide/navigation" rel="noreferrer noopener"&gt;Navigation component&lt;/a&gt; that allows you to navigate between different composable.&lt;/p&gt;

&lt;p&gt;Let’s see it in action using our code example.&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A2Y5SI5C5ax2oHHP0ywpodQ.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A2Y5SI5C5ax2oHHP0ywpodQ.png" alt="Navigation Component"&gt;&lt;/a&gt;Navigation Component&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We have our &lt;code&gt;NavigationComponent&lt;/code&gt; which is composable. You can assume this file contains all the routes in our app. As we can see, there are 3 routes here namely : &lt;code&gt;Auth&lt;/code&gt; &lt;code&gt;Home&lt;/code&gt; and &lt;code&gt;AddTodo&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The starting or the first route is the &lt;code&gt;Auth&lt;/code&gt; and based on some logic(&lt;a href="https://proandroiddev.com/google-signin-compose-a9afa67b7519" rel="noreferrer noopener"&gt;Sign in Google logic in our case&lt;/a&gt;) it redirects to the &lt;code&gt;Home&lt;/code&gt; while passing an object &lt;code&gt;user&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;All our routes need a Navigation Controller. The &lt;code&gt;NavController&lt;/code&gt; is the central API for the Navigation component. It keeps track of the back stack of the screens in your app and the state of each screen.&lt;/li&gt;
&lt;li&gt;We create a &lt;code&gt;NavController&lt;/code&gt; by using the &lt;code&gt;rememberNavController()&lt;/code&gt; method and pass it in our Views&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;navController&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;rememberNavController&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;Creating NavHost&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Each &lt;code&gt;NavController&lt;/code&gt; must be associated with a &lt;code&gt;NavHost&lt;/code&gt; composable. The &lt;code&gt;NavHost&lt;/code&gt; links the &lt;code&gt;NavController&lt;/code&gt; with a navigation graph that specifies the composable destinations that you should be able to navigate between.&lt;/li&gt;
&lt;li&gt;In order to tie this everything, we place the above &lt;code&gt;NavigationComponent&lt;/code&gt; inside our main activity&lt;/li&gt;
&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AR6rClCdKYOmR1c_FfDYXgw.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AR6rClCdKYOmR1c_FfDYXgw.png" alt="Main Activity"&gt;&lt;/a&gt;Main Activity&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;For navigating a route, we use the &lt;code&gt;navigate()&lt;/code&gt; method. &lt;code&gt;navigate()&lt;/code&gt; takes a single &lt;code&gt;String&lt;/code&gt; parameter that represents the destination’s route.&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Navigate to some screen&lt;/span&gt;
&lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"screen_route"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Pop everything up to the "home" destination off the back stack before&lt;/span&gt;
&lt;span class="c1"&gt;// navigating to the "friendslist" destination&lt;/span&gt;
&lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"friendslist"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;popUpTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"home"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Pop everything up to and including the "home" destination off&lt;/span&gt;
&lt;span class="c1"&gt;// the back stack before navigating to the "friendslist" destination&lt;/span&gt;
&lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"friendslist"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;popUpTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"home"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;inclusive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;Passing custom arguments&lt;/h4&gt;

&lt;ul&gt;&lt;li&gt;In order to do this, you add argument placeholders to your route, similar to how you &lt;a href="https://developer.android.com/guide/navigation/navigation-deep-link#implicit" rel="noreferrer noopener"&gt;add arguments to a deep link&lt;/a&gt;
&lt;/li&gt;&lt;/ul&gt;





&lt;pre&gt;&lt;code&gt;navController.navigate(Destinations.Home.replace("{user}",userJson))&lt;/code&gt;&lt;/pre&gt;





&lt;p&gt;By default, all arguments are parsed as strings. Next, you should extract the &lt;code&gt;NavArguments&lt;/code&gt; from the &lt;code&gt;NavBackStackEntry&lt;/code&gt; that is available in the lambda of the &lt;code&gt;composable()&lt;/code&gt; function.&lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;composable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Destinations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;backStackEntry&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;userJson&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;backStackEntry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// DO YOUR PROCESSING AND CONVERT TO USER OBJECT&lt;/span&gt;
    &lt;span class="nc"&gt;HomeView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userModel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userObject&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;If you are still reading, you may have realized is it too much work? And I agree with you. There is some boilerplate code, especially in the case of passing the custom arguments. &lt;em&gt;Well, can this be improved? Yes!!!&lt;/em&gt;&lt;/p&gt;





&lt;h3&gt;Using compose destinations&lt;/h3&gt;





&lt;p&gt;Forget about the previous section, and start afresh. Assume you need to implement navigation inside your app.&lt;/p&gt;





&lt;blockquote&gt;&lt;p&gt;Introducing &lt;a href="https://github.com/raamcosta/compose-destinations" rel="noreferrer noopener"&gt;Compose Destinations&lt;/a&gt;. As per the documentation&lt;/p&gt;&lt;/blockquote&gt;





&lt;p&gt;&lt;strong&gt;Compose Destination&lt;/strong&gt;: A KSP library that processes annotations and generates code that uses Official Jetpack Compose Navigation under the hood. It hides the complex, non-type-safe and boilerplate code you would have to write otherwise. Most APIs are either the same as with the Jetpack Components or inspired by them.&lt;/p&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2Aowdq1scPQ9KhUZR5.png" alt="Compose Destination"&gt;Compose Destination





&lt;h4&gt;Setup&lt;/h4&gt;





&lt;ul&gt;&lt;li&gt;Install the dependencies inside &lt;code&gt;build.gradle&lt;/code&gt; of your app&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="n"&gt;ksp&lt;/span&gt; &lt;span class="s1"&gt;'io.github.raamcosta.compose-destinations:ksp:1.4.2-beta'&lt;/span&gt;
&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'io.github.raamcosta.compose-destinations:core:1.4.2-beta'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;ul&gt;&lt;li&gt;Add the following inside the plugin of &lt;code&gt;build.gradle&lt;/code&gt;
&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="n"&gt;plugins&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="s1"&gt;'com.google.devtools.ksp'&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s1"&gt;'1.6.10-1.0.2'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;blockquote&gt;&lt;p&gt;Note: Compose Destinations takes advantage of annotation processing (using KSP) to improve the usability of Compose Navigation.&lt;/p&gt;&lt;/blockquote&gt;





&lt;ul&gt;&lt;li&gt;Include a kotlin block that defines the &lt;code&gt;sourceSets&lt;/code&gt; for the generated code inside your &lt;code&gt;build.gradle&lt;/code&gt;
&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;sourceSets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;debug&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;srcDir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"build/generated/ksp/debug/kotlin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;release&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;srcDir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"build/generated/ksp/release/kotlin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h4&gt;Implement Navigation&lt;/h4&gt;





&lt;p&gt;So you still have the routes : &lt;code&gt;Auth&lt;/code&gt; &lt;code&gt;Home&lt;/code&gt; and &lt;code&gt;AddTodo&lt;/code&gt; Now let’s see how to implement navigation. You have your existing composables. Let’s annotate them&lt;/p&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AlDsWlflc4xJPGKc0_YXwZA.png" alt="Compose Destination Annotation"&gt;Compose Destination Annotation





&lt;ul&gt;
&lt;li&gt;We use the &lt;code&gt;Destination&lt;/code&gt; annotation which comes from the &lt;a href="https://github.com/raamcosta/compose-destinations" rel="noreferrer noopener"&gt;Compose Destinations&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;We mark our AuthScreen with &lt;code&gt;start = True&lt;/code&gt; which implies this destination is the start destination of the navigation graph&lt;/li&gt;
&lt;li&gt;Next, we change the type of our &lt;code&gt;navController&lt;/code&gt; to &lt;code&gt;DestinationsNavigator&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;&lt;p&gt;DestinationsNavigator is a wrapper interface to NavController.&lt;/p&gt;&lt;/blockquote&gt;

&lt;ul&gt;&lt;li&gt;For the other screens, let’s say AddTodo, we simply annotate it&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Destination&lt;/span&gt;
&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;AddTodoView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DestinationsNavigator&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;ul&gt;&lt;li&gt;Let’s run the command below which generates all the Destinations&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./gradlew clean build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the result is a success, you should see the generated code inside the &lt;code&gt;build/generated/ksp/debug/kotlin&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2ActCumI3xUMtYzMePrreA9A.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2ActCumI3xUMtYzMePrreA9A.png" alt="Generated Destinations using Compose Destinations"&gt;&lt;/a&gt;Generated Destinations using Compose Destinations&lt;/p&gt;

&lt;h4&gt;Using NavHost&lt;/h4&gt;

&lt;p&gt;In case you realized, we no longer need the &lt;code&gt;NavigationComponent&lt;/code&gt; class.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;One final thing remaining is to add the &lt;code&gt;NavHost&lt;/code&gt; inside our &lt;code&gt;MainActivity&lt;/code&gt;
&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ComponentActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;setContent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;AppTheme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nc"&gt;DestinationsNavHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;navGraph&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NavGraphs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;ul&gt;
&lt;li&gt;Our &lt;code&gt;DestinationsNavHost&lt;/code&gt; includes the destinations of navGraph. It includes all the composables annotated with &lt;code&gt;Destination&lt;/code&gt; inside NavGraphs generated file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;NavGraphs&lt;/code&gt; is a generated file that describes your navigation graphs and their destinations. By default, all destinations belong to the &lt;code&gt;NavGraphs.root&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Finally, for navigating to screens we still follow the same convention, but now we have the Destinations (like &lt;code&gt;AddTodoViewDestination&lt;/code&gt; etc) mapped to each of the views.&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Navigate to add view screen&lt;/span&gt;
&lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AddTodoViewDestination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Pop everything up to and including the "auth" destination off&lt;/span&gt;
&lt;span class="c1"&gt;// the back stack before navigating to the "Home" destination&lt;/span&gt;
&lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HomeViewDestination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;popUpTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AuthScreenDestination&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;routeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;inclusive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;Passing custom arguments&lt;/h4&gt;

&lt;p&gt;Here’s why this gets interesting. Let’s see a case, for example, we have an Auth screen and we need to pass the user object to our Home screen.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Let’s create a &lt;a href="https://developer.android.com/guide/navigation/navigation-kotlin-dsl#custom-types" rel="noreferrer noopener"&gt;Parcelable&lt;/a&gt; class &lt;code&gt;GoogleUserModel&lt;/code&gt; This class basically contains the username and the email of the person once they &lt;a href="https://proandroiddev.com/google-signin-compose-a9afa67b7519" rel="noreferrer noopener"&gt;signed in from google&lt;/a&gt;
&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;GoogleUserModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;ul&gt;&lt;li&gt;We modify our &lt;code&gt;Home&lt;/code&gt; composable as below&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Destination&lt;/span&gt;
&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;HomeView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DestinationsNavigator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;userModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoogleUserModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;We add the parcelable class&lt;code&gt;GoogleUserModel&lt;/code&gt; to the parameters and next, we again need to run our build command which updates the generated destination for the &lt;code&gt;HomeView&lt;/code&gt;&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;Inside our &lt;code&gt;AuthView&lt;/code&gt; once we get the required data from the API, we create the &lt;code&gt;GoogleUserModel&lt;/code&gt; and pass it to the &lt;code&gt;HomeViewDestination&lt;/code&gt;
&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;HomeViewDestination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;GoogleUserModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;popUpTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AuthScreenDestination&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;routeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;inclusive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;After we navigate to &lt;code&gt;HomeView&lt;/code&gt; we pop the routes, including &lt;code&gt;AuthView&lt;/code&gt; by specifying the &lt;code&gt;AuthScreenDestination&lt;/code&gt; inside the popUpTo.&lt;/p&gt;





&lt;h3&gt;Modify existing test cases&lt;/h3&gt;





&lt;p&gt;We created some tests based on the &lt;code&gt;NavigationComponent&lt;/code&gt; (when we were using it) but since we longer have it with us, we make use of the &lt;code&gt;DestinationsNavigator&lt;/code&gt;&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;Since &lt;code&gt;DestinationsNavigator&lt;/code&gt; is an interface, we create our own &lt;code&gt;DestinationsNavigatorImpl&lt;/code&gt; the class.&lt;/li&gt;
&lt;li&gt;Our &lt;strong&gt;DestinationsNavigatorImpl&lt;/strong&gt; simply extends from the &lt;strong&gt;DestinationsNavigator&lt;/strong&gt; class and we override all the methods from the &lt;code&gt;DestinationsNavigator&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AQDJ09H4BtMynWLQ9je4mwQ.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AQDJ09H4BtMynWLQ9je4mwQ.png" alt="DestinationsNavigatorImpl"&gt;&lt;/a&gt;DestinationsNavigatorImpl&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Next, we simply replace the &lt;code&gt;&lt;a href="https://developer.android.com/reference/kotlin/androidx/navigation/testing/TestNavHostController" rel="noreferrer noopener"&gt;TestNavHostController&lt;/a&gt;&lt;/code&gt; with the &lt;code&gt;DestinationsNavigatorImpl&lt;/code&gt; inside our &lt;a href="https://levelup.gitconnected.com/testing-in-compose-d09b59337e4e" rel="noreferrer noopener"&gt;existing tests&lt;/a&gt;,&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PREVIOUS&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;TestNavHostController&lt;/span&gt;
&lt;span class="c1"&gt;// NOW&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;navController&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DestinationsNavigatorImpl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We replace &lt;code&gt;NavigationComponent&lt;/code&gt;with &lt;code&gt;DestinationsNavHost&lt;/code&gt; inside our tests&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;composeTestRule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

     &lt;span class="c1"&gt;// PREVIOUS &lt;/span&gt;
     &lt;span class="nc"&gt;NavigationComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

     &lt;span class="c1"&gt;// NOW&lt;/span&gt;
     &lt;span class="nc"&gt;DestinationsNavHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;navGraph&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NavGraphs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&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;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/WGcknKt0jkE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/hands_on_kotlin"&gt;&lt;em&gt;Source code.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>programming</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Deploy lambda using serverless</title>
      <dc:creator>aseem wangoo</dc:creator>
      <pubDate>Tue, 05 Apr 2022 15:08:34 +0000</pubDate>
      <link>https://forem.com/aseemwangoo/deploy-lambda-using-serverless-p35</link>
      <guid>https://forem.com/aseemwangoo/deploy-lambda-using-serverless-p35</guid>
      <description>&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kziPr3-e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;We will cover briefly:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;Options for deploying lambda&lt;/li&gt;
&lt;li&gt;Setup serverless&lt;/li&gt;
&lt;li&gt;Create lambda (upload image to s3 bucket) using serverless&lt;/li&gt;
&lt;li&gt;Deploy lambda using serverless&lt;/li&gt;
&lt;/ol&gt;



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

&lt;h3&gt;Options for deploying lambda&lt;/h3&gt;

&lt;p&gt;As of writing this article, there are &lt;strong&gt;two ways&lt;/strong&gt; of deploying lambdas onto AWS&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SnWRIPr4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AWvQBPtKe5MJ0FGKsvseYIQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SnWRIPr4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AWvQBPtKe5MJ0FGKsvseYIQ.png" alt="Deploy lambda using serverless" width="696" height="336"&gt;&lt;/a&gt;Deploy lambda using serverless&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html" rel="noreferrer noopener"&gt;&lt;strong&gt;Using AWS SAM&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;The AWS Serverless Application Model (AWS SAM) is an open-source framework that you can use to build &lt;a href="https://aws.amazon.com/serverless/" rel="noreferrer noopener"&gt;serverless applications&lt;/a&gt; on AWS&lt;/p&gt;

&lt;p&gt;One of the key benefits of &lt;strong&gt;SAM &lt;/strong&gt;is &lt;strong&gt;Local debugging and testing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It lets you locally build, test, and debug serverless applications that are defined by AWS SAM templates. which helps you catch issues upfront by providing parity with the actual Lambda execution environment&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href="https://www.serverless.com/" rel="noreferrer noopener"&gt;&lt;strong&gt;Using serverless&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Develop, deploy, troubleshoot, and secure your serverless applications with radically less overhead and cost by using the Serverless Framework. The Serverless Framework consists of an open-source CLI.&lt;/p&gt;

&lt;p&gt;Serverless allows us to focus on the code, while it takes care of the setting up policies, and provisioning of required infrastructure onto AWS&lt;/p&gt;

&lt;h3&gt;Setup serverless&lt;/h3&gt;

&lt;p&gt;To install &lt;code&gt;serverless&lt;/code&gt;, follow &lt;a href="https://www.serverless.com/framework/docs/getting-started" rel="noreferrer noopener"&gt;here&lt;/a&gt;. Personally, I configured using the below&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;npm install -g serverless&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Once installed you can access it by typing &lt;code&gt;sls&lt;/code&gt; on your terminal&lt;/li&gt;
&lt;li&gt;We now have access to multiple templates by this command&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;sls create --help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will focus on the Go specific one, which is &lt;code&gt;aws-go-dep&lt;/code&gt; Let's use this template to create a simple lambda. The final command for that is&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;sls create --template aws-go-dep --path upload-s3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--template&lt;/code&gt; is used to specify the template name&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--path&lt;/code&gt; &lt;strong&gt;(Optional)&lt;/strong&gt; is used to specify the directory in which your code is to be placed&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;We should see a folder structure like this&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hsAFo4Uj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AXlUZ6DCr_GLUY4MLBBjs3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hsAFo4Uj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AXlUZ6DCr_GLUY4MLBBjs3w.png" alt="Golang serverless folder structure" width="650" height="598"&gt;&lt;/a&gt;Golang serverless folder structure&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;By default, the &lt;code&gt;aws-go-dep&lt;/code&gt; a template gives us two &lt;code&gt;http (GET)&lt;/code&gt;based endpoints, which can be seen in the &lt;code&gt;serverless.yml&lt;/code&gt;
&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bin/hello&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/hello&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
  &lt;span class="na"&gt;world&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bin/world&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/world&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;The equivalent files correspond to &lt;code&gt;hello/main.go&lt;/code&gt; and &lt;code&gt;world/main.go&lt;/code&gt; &lt;/p&gt;





&lt;ul&gt;&lt;li&gt;In case you see errors, try to run the following commands&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SOME&lt;/span&gt; &lt;span class="n"&gt;NAME&lt;/span&gt; &lt;span class="n"&gt;HERE&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;tidy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;This will help in setting the &lt;code&gt;go.mod&lt;/code&gt; which is required for any go program&lt;/p&gt;





&lt;h3&gt;Create lambda (upload image to s3 bucket) using serverless&lt;/h3&gt;





&lt;p&gt;We will modify our lambda to upload an image to an S3 bucket.&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;We delete the unnecessary endpoints from the &lt;code&gt;serverless.yml&lt;/code&gt; and unwanted folders like &lt;code&gt;hello/main.go&lt;/code&gt; and &lt;code&gt;world/main.go&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Create a new folder called &lt;code&gt;upload&lt;/code&gt; and inside it creates a file &lt;code&gt;main.go&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cVy1aSk_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AIcqK4hy3lI9FcxU4beWXiw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cVy1aSk_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AIcqK4hy3lI9FcxU4beWXiw.png" alt="Our final upload lambda structure" width="544" height="430"&gt;&lt;/a&gt;Our final upload lambda structure&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;We will define a request body struct that will accept &lt;code&gt;filename&lt;/code&gt; and the &lt;code&gt;body&lt;/code&gt; as input. (Note: the body would be the base64 encoder of an image)&lt;/li&gt;&lt;/ul&gt;

&lt;blockquote&gt;&lt;p&gt;For getting the base64 of any image, &lt;a href="https://base64.guru/converter/encode/image" rel="noreferrer noopener"&gt;check here&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ImageRequestBody&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;FileName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"filename"`&lt;/span&gt;
 &lt;span class="n"&gt;Body&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"body"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will parse the body from the input and decode it using &lt;code&gt;DecodeString&lt;/code&gt; which returns the bytes represented by the base64 string&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;decoded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StdEncoding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DecodeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bodyRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All our image-related functions are inside &lt;a href="https://github.com/AseemWangoo/golang-programs/blob/master/upload-s3/upload/structs.go" rel="noreferrer noopener"&gt;img_utils.go&lt;/a&gt;. After decoding the image into bytes from the previous step, we now take those bytes and form a temporary file&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;imageUpload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;tmpFileName&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`/tmp/%s`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bodyRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;fileErr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmpFileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c"&gt;// CALL THE UPLOAD FUNCTION&lt;/span&gt;
  &lt;span class="n"&gt;UploadImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmpFileName&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;In the first line, we are specifying the file at a location &lt;code&gt;tmp&lt;/code&gt; . This is an important step and as per AWS documentation&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;The Lambda execution environment provides a file system for your code to use at /&lt;strong&gt;tmp&lt;/strong&gt;. This space has a fixed size of 512 MB. Each time a new execution environment is created, this area is deleted.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Next, we write the file with the bytes using &lt;code&gt;WriteFile&lt;/code&gt; &lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;WriteFile&lt;/strong&gt; writes data to a file named by filename. If the file does not exist, WriteFile creates it with permissions perm (before umask); otherwise WriteFile truncates it before writing, without changing permissions.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;So now we have our temporary file created!&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Now we will upload the file, onto the AWS S3 bucket. For that, we will be using the &lt;a href="https://github.com/aws/aws-sdk-go" rel="noreferrer noopener"&gt;AWS GO SDK&lt;/a&gt; and in case you don’t have it installed follow this&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;sdk&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will pass our file to the &lt;a href="https://github.com/AseemWangoo/golang-programs/blob/master/upload-s3/upload/upload_s3.go" rel="noreferrer noopener"&gt;upload function&lt;/a&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;uploadToS3Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fileName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;bucketName&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bucket_name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"us-east-2"&lt;/span&gt;
 &lt;span class="n"&gt;conf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Region&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="n"&gt;sess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;uploader&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s3manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewUploader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;upParams&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;s3manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UploadInput&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;uploader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;upParams&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;ul&gt;&lt;li&gt;We need to specify the region using &lt;code&gt;aws.Config&lt;/code&gt; . In our case it was us-east-2.&lt;/li&gt;&lt;/ul&gt;

&lt;ul&gt;&lt;li&gt;We need to specify the region using &lt;code&gt;aws.Config&lt;/code&gt; . In our case it was us-east-2.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;session.Newsession&lt;/code&gt; returns a new Session created from SDK defaults, config files, environment, and user-provided config files.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;aws-sdk-go&lt;/code&gt; gives us &lt;code&gt;s3Manager&lt;/code&gt; which helps in uploading the file. It takes in&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Bucket&lt;/code&gt; : Your AWS bucket name, in my case I get from &lt;code&gt;serverless.yml &lt;/code&gt;environment variable&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Key&lt;/code&gt; : Object key for which the PUT action was initiated. In our case, it's the filename.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Body&lt;/code&gt; : What is the body payload to send to S3. In our case, it's the file itself&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, using the above parameters, we call the &lt;code&gt;Uploader.Upload&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;We return the response from the &lt;code&gt;main.go&lt;/code&gt; back to the caller&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Deploy lambda using serverless&lt;/h3&gt;

&lt;p&gt;Till now we were creating our lambda, but now it's time to deploy it onto AWS.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Let’s revisit our &lt;code&gt;serverless.yml&lt;/code&gt; and make some changes&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;functions&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;upload&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;upload&lt;/span&gt;
    &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
      &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;httpApi&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
          &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;uploadImage&lt;/span&gt;
          &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We add in the post endpoint &lt;code&gt;uploadImage&lt;/code&gt; for our lambda&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Next, since we are using the S3 bucket from inside lambda, we will add some IAMRoleStatements&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;s3Bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-bucket--aseem&lt;/span&gt;

&lt;span class="na"&gt;iamRoleStatements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
      &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;s3:*&lt;/span&gt;
      &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:s3:::${self:custom.s3Bucket}/*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This specifies the bucket name using &lt;code&gt;s3Bucket&lt;/code&gt; and allows executing the operations on this bucket&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Finally, for specifying the environment variables, we make use of&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;bucket_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-bucket--aseem&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will create a &lt;code&gt;&lt;a href="https://github.com/AseemWangoo/golang-programs/blob/master/upload-s3/Makefile" rel="noreferrer noopener"&gt;Makefile&lt;/a&gt;&lt;/code&gt; and put the following&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clean build&lt;/span&gt;
 &lt;span class="s"&gt;sls deploy --verbose&lt;/span&gt;
&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="s"&gt;sls remove&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will help in easing the lambda deployment, by simply calling&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;make deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything was successful, you should see something like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RF_rPvGc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2A2A91zXbPpcGTtomCRq4hnA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RF_rPvGc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2A2A91zXbPpcGTtomCRq4hnA.png" alt="Deploy lambda using serverless" width="880" height="471"&gt;&lt;/a&gt;Deploy lambda using serverless&lt;/p&gt;

&lt;p&gt;For removing the lambda, we can call&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;make remove&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For testing the lambda, use the&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&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;'{"filename": "xyz.png", "body": "BASE_64_ENCODING_OF_AN_IMAGE"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&amp;lt;YOUR_LAMBDA_URL&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WCV3X-ji--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2APuQQSVHG8Dd-GJTPivTSPw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WCV3X-ji--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2APuQQSVHG8Dd-GJTPivTSPw.png" alt="Image uploaded to S3" width="880" height="165"&gt;&lt;/a&gt;Image uploaded to S3&lt;/p&gt;


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/golang-programs"&gt;&lt;em&gt;Source code.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kziPr3-e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>aws</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Using Mockito in Flutter</title>
      <dc:creator>aseem wangoo</dc:creator>
      <pubDate>Mon, 28 Mar 2022 15:30:49 +0000</pubDate>
      <link>https://forem.com/aseemwangoo/using-mockito-in-flutter-3d01</link>
      <guid>https://forem.com/aseemwangoo/using-mockito-in-flutter-3d01</guid>
      <description>&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;We will cover briefly:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;Setup Mockito&lt;/li&gt;
&lt;li&gt;Mocking repository using Mockito&lt;/li&gt;
&lt;li&gt;Write unit tests for repository&lt;/li&gt;
&lt;li&gt;Write unit tests for the view model&lt;/li&gt;
&lt;li&gt;(Optional) Code coverage&lt;/li&gt;
&lt;/ol&gt;



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

&lt;h3&gt;Setup Mockito&lt;/h3&gt;

&lt;p&gt;There are often times when unit tests depend on classes that fetch data from live web services or databases. This is inconvenient for a few reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calling live services or databases slows down test execution.&lt;/li&gt;
&lt;li&gt;It is difficult to test all possible success and failure scenarios by using a live web service or database.&lt;/li&gt;
&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AOAL7zVW-0YNdZcV2.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AOAL7zVW-0YNdZcV2.png" alt="Mockito"&gt;&lt;/a&gt;Mockito&lt;/p&gt;

&lt;p&gt;You can mock dependencies by creating an alternative implementation of a class. by making use of the &lt;a href="https://pub.dev/packages/mockito" rel="noreferrer noopener"&gt;Mockito package&lt;/a&gt; as a shortcut.&lt;/p&gt;

&lt;p&gt;Following is the general idea behind &lt;strong&gt;Mockito&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Rather than relying on a live web service or database, you can “mock” these dependencies. Mocks allow emulating a live web service or database and return specific results depending on the situation.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;We use the &lt;code&gt;&lt;a href="https://pub.dev/packages/mockito" rel="noreferrer noopener"&gt;mockito&lt;/a&gt;&lt;/code&gt; package for writing unit tests and for generating the implementation it relies on &lt;code&gt;&lt;a href="https://pub.dev/packages/build_runner" rel="noreferrer noopener"&gt;build_runner&lt;/a&gt;&lt;/code&gt;. Add the plugins to your &lt;code&gt;pubspec.yaml&lt;/code&gt; file&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pubspec.yaml&lt;/span&gt;
&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mockito&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^5.1.0&lt;/span&gt;
&lt;span class="na"&gt;dev_dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build_runner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.1.7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;&lt;p&gt;Detailed description &lt;a href="https://pub.dev/packages/mockito" rel="noreferrer noopener"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;Mocking repository using Mockito&lt;/h3&gt;

&lt;p&gt;Before starting this, let's see the architecture which we used for our app&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AvupA5B_V6h6uFSj0ahm5iQ.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AvupA5B_V6h6uFSj0ahm5iQ.png" alt="The architecture used in the app"&gt;&lt;/a&gt;The architecture used in the app&lt;/p&gt;

&lt;p&gt;For each of the screens, we have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/AseemWangoo/dynamism/blob/master/lib/home/repository/home_repo.dart" rel="noreferrer noopener"&gt;&lt;strong&gt;Repository&lt;/strong&gt;&lt;/a&gt;: Which handles our business logic&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/AseemWangoo/dynamism/blob/master/lib/home/view_models/home.viewmodel.dart" rel="noreferrer noopener"&gt;&lt;strong&gt;ViewModel&lt;/strong&gt;&lt;/a&gt;: Bridge between the UI and the repository&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/AseemWangoo/dynamism/blob/master/lib/home/view/home.view.dart" rel="noreferrer noopener"&gt;&lt;strong&gt;View&lt;/strong&gt;&lt;/a&gt;: Actual screen visible to the user&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/AseemWangoo/dynamism/blob/master/lib/home/model/carousel.model.dart" rel="noreferrer noopener"&gt;&lt;strong&gt;Model&lt;/strong&gt;&lt;/a&gt;: Response being cast to models, in order to be consumed in the view.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Repository tests using Mockito&lt;/h4&gt;

&lt;ul&gt;&lt;li&gt;This is what our &lt;a href="https://github.com/AseemWangoo/dynamism/blob/master/lib/home/repository/home_repo.dart" rel="noreferrer noopener"&gt;home repository &lt;/a&gt;looks like,&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeRepo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CarouselModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeRepoImpl&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;HomeRepo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CarouselModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;milliseconds:&lt;/span&gt; &lt;span class="mi"&gt;1800&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt;  &lt;span class="n"&gt;rootBundle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'assets/data/first_screen.json'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;carouselModelFromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&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;In the above snippet, we are creating a manual delay in order to simulate the network delay, and afterward, we simply fetch our JSON file (present under the assets).&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;For mocking our repository, we first create a file &lt;code&gt;home_repo_test.dart&lt;/code&gt;under test folder as below&lt;/li&gt;&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AWZzvyfRal0p12vA_O9j-HQ.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AWZzvyfRal0p12vA_O9j-HQ.png" alt="Repository testing using Mockito"&gt;&lt;/a&gt;Repository testing using Mockito&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Note: The tests should follow &lt;code&gt;test/folder_name/&amp;lt;name&amp;gt;_test.dart&lt;/code&gt; pattern&lt;/p&gt;&lt;/blockquote&gt;

&lt;ul&gt;&lt;li&gt;Inside the file, we add the annotation &lt;code&gt;@GenerateMocks([HomeRepoTest])&lt;/code&gt; to the main function to generate a &lt;code&gt;MockHomeRepoTest&lt;/code&gt; class with &lt;code&gt;mockito&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;

&lt;blockquote&gt;&lt;p&gt;By annotating a library element (such as a test file’s &lt;code&gt;main&lt;/code&gt; function, or a class) with &lt;code&gt;@GenerateMocks&lt;/code&gt;, you are directing Mockito's code generation to write a mock class for each "real" class listed, in a new library.&lt;/p&gt;&lt;/blockquote&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// IMPORTS OMITTED FOR BREVITY&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomeRepoTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;HomeRepo&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nd"&gt;@GenerateMocks&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;HomeRepoTest&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;HomeRepoTest&lt;/strong&gt;: The mock class which will be referred to in the generated class&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MockHomeRepoTest&lt;/strong&gt;: The generated mock class which implements the functions inside the &lt;code&gt;HomeRepo&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, generate the mocks running the following command:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;flutter&lt;/span&gt; &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;build_runner&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generated mocks will be located in &lt;code&gt;home_repo_test.mocks.dart&lt;/code&gt;. Import this file to use them inside your test file.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;We should see something like this if all the above steps were done correctly&lt;/li&gt;&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A-wQjuyaBqzevSXZhrbvu1A.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A-wQjuyaBqzevSXZhrbvu1A.png" alt="Mockito generated class"&gt;&lt;/a&gt;Mockito generated class&lt;/p&gt;

&lt;h3&gt;Write unit tests for repository&lt;/h3&gt;

&lt;p&gt;Let’s write the unit tests for the repository now, with all the necessary setup done in the previous step.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;We will initialize our mock repository inside the &lt;code&gt;setUpAll&lt;/code&gt;
&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="kd"&gt;late&lt;/span&gt; &lt;span class="n"&gt;MockHomeRepoTest&lt;/span&gt; &lt;span class="n"&gt;homeRepo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;setUpAll&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;homeRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MockHomeRepoTest&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'test fetchData'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CarouselModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;homeRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenAnswer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;homeRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isA&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CarouselModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;());&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'test fetchData throws Exception'&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;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;homeRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenAnswer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;homeRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;throwsException&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;ul&gt;&lt;li&gt;We have two tests inside the repository: For the first one, we use the &lt;code&gt;&lt;a href="https://pub.dev/documentation/mockito/latest/mockito/when.html" rel="noreferrer noopener"&gt;when&lt;/a&gt;&lt;/code&gt;, &lt;code&gt;&lt;a href="https://pub.dev/documentation/mockito/latest/mockito/PostExpectation/thenAnswer.html" rel="noreferrer noopener"&gt;thenAnswer&lt;/a&gt;&lt;/code&gt;APIs provide a stubbing mechanism. Once stubbed, the method will always return the stubbed value regardless of how many times it is called.&lt;/li&gt;&lt;/ul&gt;





&lt;blockquote&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/mockito/latest/mockito/when.html" rel="noreferrer noopener"&gt;&lt;strong&gt;when&lt;/strong&gt;&lt;/a&gt;: Creates a stub method response. Mockito will store the fake call and pair the exact arguments given with the response. The response generators from Mockito include&lt;code&gt;thenReturn&lt;/code&gt;, &lt;code&gt;thenAnswer&lt;/code&gt;, and &lt;code&gt;thenThrow&lt;/code&gt;.&lt;/p&gt;&lt;/blockquote&gt;





&lt;blockquote&gt;&lt;p&gt;&lt;a href="https://pub.dev/documentation/mockito/latest/mockito/PostExpectation/thenAnswer.html" rel="noreferrer noopener"&gt;&lt;strong&gt;thenAnswer&lt;/strong&gt;&lt;/a&gt;: Stores a function which is called when this method stub is called. The function will be called, and the return value will be returned.&lt;/p&gt;&lt;/blockquote&gt;





&lt;p&gt;We return the &lt;code&gt;CarouselModel&lt;/code&gt; from the stub and use the &lt;strong&gt;expect&lt;/strong&gt; to assert that &lt;code&gt;actual&lt;/code&gt; matches &lt;code&gt;matcher&lt;/code&gt;.&lt;/p&gt;





&lt;p&gt;In our case, we expect it to be of type &lt;code&gt;CarouselModel&lt;/code&gt; using &lt;a href="https://api.flutter.dev/flutter/package-matcher_matcher/isA.html" rel="noreferrer noopener"&gt;isA&lt;/a&gt;&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;For the second test, we throw an Exception from the stub. We expect the &lt;code&gt;actual&lt;/code&gt; matches &lt;code&gt;throwsException&lt;/code&gt; which is a matcher for functions that throw Exception.&lt;/li&gt;&lt;/ul&gt;





&lt;h3&gt;Write unit tests for the view model&lt;/h3&gt;





&lt;p&gt;We will first initialize our mock home repository and the view model inside the &lt;code&gt;setUpAll&lt;/code&gt;&lt;/p&gt;





&lt;p&gt;We pass in the Mock repository &lt;code&gt;MockHomeRepoTest&lt;/code&gt;to our view model, as it expects the repository as a required parameter.&lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;late&lt;/span&gt; &lt;span class="n"&gt;MockHomeRepoTest&lt;/span&gt; &lt;span class="n"&gt;homeRepo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;late&lt;/span&gt; &lt;span class="n"&gt;HomeViewModel&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;setUpAll&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;homeRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MockHomeRepoTest&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;viewModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HomeViewModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;repo:&lt;/span&gt; &lt;span class="n"&gt;homeRepo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'test fetchData'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CarouselModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;homeRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenAnswer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;model&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="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;homeModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&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;ul&gt;&lt;li&gt;In the test above, we use the &lt;code&gt;&lt;a href="https://pub.dev/documentation/mockito/latest/mockito/when.html" rel="noreferrer noopener"&gt;when&lt;/a&gt;&lt;/code&gt;, &lt;code&gt;&lt;a href="https://pub.dev/documentation/mockito/latest/mockito/PostExpectation/thenAnswer.html" rel="noreferrer noopener"&gt;thenAnswer&lt;/a&gt;&lt;/code&gt;APIs&lt;/li&gt;&lt;/ul&gt;





&lt;p&gt;We call the &lt;code&gt;homeRepo.fetchData()&lt;/code&gt; using the &lt;code&gt;&lt;a href="https://pub.dev/documentation/mockito/latest/mockito/when.html" rel="noreferrer noopener"&gt;when&lt;/a&gt;&lt;/code&gt; and return the stub response as the &lt;code&gt;CarouselModel&lt;/code&gt;&lt;/p&gt;





&lt;p&gt;Next, we call the actual function &lt;code&gt;fetchData()&lt;/code&gt; from inside the view model using &lt;code&gt;viewModel.fetchData()&lt;/code&gt;&lt;/p&gt;





&lt;p&gt;Finally, we expect it to be of type &lt;code&gt;CarouselModel&lt;/code&gt; in the matcher, since we are setting the response from the repository to the model.&lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// HomeViewModel&lt;/span&gt;
&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;_homeModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetchData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;notifyListeners&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h3&gt;Code coverage&lt;/h3&gt;





&lt;p&gt;In case you are using Android Studio, you can simply right-click on the test and &lt;strong&gt;run tests with Coverage&lt;/strong&gt;&lt;/p&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AS9Zl-URbtNFqI3oDTjzMYA.png" alt="Code Coverage using Android Studio"&gt;Code Coverage using Android Studio





&lt;p&gt;For VSCode, install the following extensions&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=Flutterando.flutter-coverage" rel="noreferrer noopener"&gt;Flutter Coverage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters" rel="noreferrer noopener"&gt;Coverage Gutters&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Execute the following command&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;flutter&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;coverage&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will generate the &lt;code&gt;lcov.info&lt;/code&gt;which contains the coverage information.&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AbR1U1PB9zjPSAExubwDH3A.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AbR1U1PB9zjPSAExubwDH3A.png" alt=""&gt;&lt;/a&gt;Code Coverage&lt;/p&gt;

&lt;p&gt;Now, click on the testing icon on the left side of the VSCode and you can see your code coverage. &lt;strong&gt;Good article &lt;/strong&gt;&lt;a href="https://xeladu.medium.com/show-test-coverage-of-a-flutter-app-in-visual-studio-code-7e26c3b94aaf" rel="noreferrer noopener"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2ALk5clSFhqunjsgAZsqpZgQ.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2ALk5clSFhqunjsgAZsqpZgQ.png" alt="Code coverage of view models"&gt;&lt;/a&gt;Code coverage of view models&lt;/p&gt;


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/dynamism"&gt;&lt;em&gt;Source code.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>productivity</category>
      <category>flutter</category>
      <category>programming</category>
    </item>
    <item>
      <title>Using Kafka in 2022</title>
      <dc:creator>aseem wangoo</dc:creator>
      <pubDate>Thu, 10 Mar 2022 03:09:52 +0000</pubDate>
      <link>https://forem.com/aseemwangoo/using-kafka-in-2022-j67</link>
      <guid>https://forem.com/aseemwangoo/using-kafka-in-2022-j67</guid>
      <description>&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;We will cover briefly:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;Intro to Kafka&lt;/li&gt;
&lt;li&gt;Setup Kafka on machine&lt;/li&gt;
&lt;li&gt;Create Kafka Producer&lt;/li&gt;
&lt;li&gt;Create Kafka Consumer&lt;/li&gt;
&lt;li&gt;Running Producer and Consumer&lt;/li&gt;
&lt;/ol&gt;



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

&lt;h4&gt;Intro to Kafka&lt;/h4&gt;

&lt;p&gt;As per the &lt;a href="https://kafka.apache.org/intro" rel="noreferrer noopener"&gt;docs&lt;/a&gt;, Kafka is an event streaming platform that can be used for collecting, processing, storing, and analyzing data at scale. &lt;strong&gt;Kafka &lt;/strong&gt;is used by &lt;a href="https://kafka.apache.org/powered-by" rel="noreferrer noopener"&gt;thousands of companies&lt;/a&gt; including over 60% of the Fortune 100.&lt;/p&gt;

&lt;p&gt;Kafka is known for its excellent performance, low latency, fault tolerance, and high throughput, it’s capable of handling thousands of messages per second.&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AQFtT6kh-s5SfhIWf.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2AQFtT6kh-s5SfhIWf.png" alt="Kafka Overview"&gt;&lt;/a&gt;Kafka Overview&lt;/p&gt;

&lt;p&gt;Usecases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Process payments and financial transactions in real-time,&lt;/li&gt;
&lt;li&gt;Continuously capture and analyze sensor data from IoT devices,&lt;/li&gt;
&lt;li&gt;Collect and immediately react to customer interactions and orders,&lt;/li&gt;
&lt;li&gt;Track and monitor cars, trucks, fleets, and shipments in real-time&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;&lt;strong&gt;Setup Kafka on machine&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;This section will help to set up Kafka on your machine. &lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note: We are using a mac.&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;ul&gt;&lt;li&gt;To install &lt;code&gt;Kafka&lt;/code&gt; follow &lt;a href="https://kafka.apache.org/downloads" rel="noreferrer noopener"&gt;here&lt;/a&gt;. Navigate to the &lt;strong&gt;latest binary downloads&lt;/strong&gt;, as of today, it’s &lt;strong&gt;Scala 2.13, &lt;/strong&gt;and click on the link. It will open another webpage and click the link as below:&lt;/li&gt;&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2ACND4cBRTMob43AdMYHLyOQ.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2ACND4cBRTMob43AdMYHLyOQ.png" alt="Download link for Kafka"&gt;&lt;/a&gt;Download link for Kafka&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Extract the folder and navigate to the folder (&lt;em&gt;Downloads/kafka_2.12–3.1.0&lt;/em&gt;) in our case.&lt;/li&gt;&lt;/ul&gt;

&lt;blockquote&gt;&lt;p&gt;Note: Follow the below terminal commands at the path where you extract the Kafka zip. &lt;/p&gt;&lt;/blockquote&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh bin/zookeeper-server-start.sh config/zookeeper.properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Start Zookeeper&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The above command starts &lt;code&gt;Zookeeper&lt;/code&gt; . It is primarily used to track the status of nodes in the Kafka cluster and maintain a list of Kafka topics and messages.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Note: Starting with v2.8, Kafka can be run without &lt;code&gt;Zookeeper&lt;/code&gt;. However, this update isn’t ready for use in production&lt;/p&gt;&lt;/blockquote&gt;

&lt;blockquote&gt;&lt;p&gt;Keep the above terminal open&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Start Kafka broker service&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Open another terminal at the above path(&lt;em&gt;Downloads/kafka_2.12–3.1.0&lt;/em&gt;) and type&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh bin/kafka-server-start.sh config/server.properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This starts the &lt;code&gt;&lt;em&gt;Kafka Broker&lt;/em&gt;&lt;/code&gt;. A &lt;em&gt;Kafka cluster&lt;/em&gt; is made up of multiple Kafka Brokers. Each Kafka Broker has a unique ID (number). Kafka Brokers contain topic log partitions. Connecting to one broker bootstraps a client to the entire Kafka cluster. A Kafka cluster can have, 10, 100, or 1,000 brokers in a cluster if needed.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Keep this terminal open&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Create a topic&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Open a new terminal at the above path and type&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh bin/kafka-topics.sh &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9092 &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="nt"&gt;--topic&lt;/span&gt; test-topic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kafka produces events across different machines, these events are organized and stored inside &lt;code&gt;topics&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;In the above command, we are saying our &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;server is &lt;code&gt;localhost:9092&lt;/code&gt; and&lt;/li&gt;
&lt;li&gt;topic created is &lt;code&gt;test-topic&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Verify the topic created &lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Open a new terminal at the above path and type&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh bin/kafka-topics.sh &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9092 &lt;span class="nt"&gt;--list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show you the &lt;code&gt;test-topic&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;Create Kafka Producer&lt;/h4&gt;

&lt;blockquote&gt;&lt;p&gt;Note: Kafka Broker should be running in the terminal&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Install dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We will be using &lt;a href="https://www.eclipse.org/downloads/" rel="noreferrer noopener"&gt;Eclipse IDE&lt;/a&gt; for creating our Kafka Producer&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2A6onkDUNIQdfeQlst" 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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F0%2A6onkDUNIQdfeQlst" alt="Kafka Producer"&gt;&lt;/a&gt;Kafka Producer&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a Maven Project using the eclipse.&lt;/li&gt;
&lt;li&gt;Go to the pom.xml, put in the following, and update your maven project&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt; 

   &lt;span class="c"&gt;&amp;lt;!-- Kafka Client --&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.kafka&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;kafka-clients&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.1.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

   &lt;span class="c"&gt;&amp;lt;!-- Simple logging --&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.slf4j&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;slf4j-api&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.0.0-alpha6&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.slf4j&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;slf4j-simple&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.0.0-alpha6&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;     
   &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will add &lt;code&gt;Kafka Client&lt;/code&gt; and &lt;code&gt;slf4j&lt;/code&gt; to our project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create SampleProducer.java&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Create a class called &lt;code&gt;SampleProducer.java&lt;/code&gt;
&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SampleProducer&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;


 &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SampleProducer&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Properties&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Properties&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bootstrap.servers"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"localhost:9092"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key.serializer"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"org.apache.kafka.common.serialization.StringSerializer"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
 &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value.serializer"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"org.apache.kafka.common.serialization.StringSerializer"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kafka.topic"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"test-topic"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="nc"&gt;KafkaProducer&lt;/span&gt; &lt;span class="n"&gt;kafkaProducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KafkaProducer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
    &lt;span class="nc"&gt;ProducerRecord&lt;/span&gt; &lt;span class="n"&gt;producerRecord&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProducerRecord&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test-topic"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"message-"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;kafkaProducer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;producerRecord&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;kafkaProducer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;    
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;We initialize the &lt;code&gt;Properties&lt;/code&gt; with the following keys and values &lt;/p&gt;





&lt;p&gt;&lt;code&gt;bootstrap.servers&lt;/code&gt; : your local server host and port&lt;/p&gt;





&lt;p&gt;&lt;code&gt;key.serializer&lt;/code&gt; : for sending the serialized key over the network. &lt;/p&gt;





&lt;p&gt;&lt;code&gt;value.serializer&lt;/code&gt; : for sending the serialized value over the network.&lt;/p&gt;





&lt;p&gt;&lt;code&gt;kafka.topic&lt;/code&gt; : your Kafka topic&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;Next, we create an instance of &lt;code&gt;KafkaProducer&lt;/code&gt; with the properties (as specified above)&lt;/li&gt;
&lt;li&gt;We need to create a &lt;code&gt;ProducerRecord&lt;/code&gt;for sending the data to the Kafka producer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ProducerRecord takes in the &lt;strong&gt;topic name&lt;/strong&gt;, &lt;strong&gt;key&lt;/strong&gt;, and the &lt;strong&gt;value&lt;/strong&gt; to be sent.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We send the record using &lt;strong&gt;kafkaProducer. &lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;This block of code is placed inside the while loop, and after every 3 seconds, it sends a record to the Kafka broker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Create KafkaProducerRunner.java&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;This will be class that invokes the above &lt;code&gt;SampleProducer&lt;/code&gt;
&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KafkaProducerRunner&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;SampleProducer&lt;/span&gt; &lt;span class="n"&gt;sampleProducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SampleProducer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
 &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h4&gt;Create Kafka Consumer&lt;/h4&gt;





&lt;blockquote&gt;&lt;p&gt;Note: Kafka Broker should be running in the terminal&lt;/p&gt;&lt;/blockquote&gt;





&lt;ul&gt;&lt;li&gt;Create a class called &lt;code&gt;SampleConsumer.java&lt;/code&gt;
&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SampleConsumer&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

 &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SampleConsumer&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Properties&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Properties&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bootstrap.servers"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"localhost:9092"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
  &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kafka.topic"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"test-topic"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
  &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key.deserializer"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"org.apache.kafka.common.serialization.StringDeserializer"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
 &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value.deserializer"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"org.apache.kafka.common.serialization.StringDeserializer"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

 &lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"group.id"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"my-group"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="nc"&gt;KafkaConsumer&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;KafkaConsumer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kafka.topic"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;

       &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;ConsumerRecords&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;poll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofMillis&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
          &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConsumerRecord&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;  &lt;span class="o"&gt;{&lt;/span&gt;
           &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"partition = %s, offset = %d, key = %s, value = %s\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
             &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;partition&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
          &lt;span class="o"&gt;}&lt;/span&gt;
       &lt;span class="o"&gt;}&lt;/span&gt;              

 &lt;span class="o"&gt;}&lt;/span&gt;  
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;We initialize the &lt;code&gt;Properties&lt;/code&gt; with the following keys and values&lt;/p&gt;





&lt;p&gt;&lt;code&gt;bootstrap.servers&lt;/code&gt; : your local server host and port&lt;/p&gt;





&lt;p&gt;&lt;code&gt;kafka.topic&lt;/code&gt; : your Kafka topic&lt;/p&gt;





&lt;p&gt;&lt;code&gt;key.deserializer&lt;/code&gt; : for deserializing the key over the network.&lt;/p&gt;





&lt;p&gt;&lt;code&gt;value.deserializer&lt;/code&gt; : for deserializing the value over the network.&lt;/p&gt;





&lt;p&gt;&lt;code&gt;group.id&lt;/code&gt; : specify the group id, used only on the Consumer side.&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;Next, we create an instance of &lt;code&gt;KafkaConsumer&lt;/code&gt; with the properties (as specified above). This KafkaConsumer consumes the records from a Kafka cluster.&lt;/li&gt;
&lt;li&gt;Next, we subscribe to the topic (which was created in the KafkaProducer) using &lt;code&gt;subscribe&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;We get the data in the form of &lt;code&gt;ConsumerRecords&lt;/code&gt; and we call &lt;code&gt;poll&lt;/code&gt; every 100 ms in an infinite loop.&lt;/li&gt;
&lt;li&gt;For each consumer record, we extract the &lt;strong&gt;partition, offset, key &lt;/strong&gt;and &lt;strong&gt;value&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Create KafkaConsumerRunner.java&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;This will be class that invokes the above &lt;code&gt;SampleConsumer&lt;/code&gt;
&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KafkaConsumerRunner&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;SampleConsumer&lt;/span&gt; &lt;span class="n"&gt;sampleConsumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SampleConsumer&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
 &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;Running Producer and Consumer&lt;/h4&gt;

&lt;p&gt;If you followed the above steps correctly, you should have the below files&lt;/p&gt;

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

&lt;p&gt;Let’s run the &lt;strong&gt;KafkaProducerRunner first, &lt;/strong&gt;we should see something like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A9OKX-3DihIyWCO2-sUXVZA.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A9OKX-3DihIyWCO2-sUXVZA.png" alt="Kafka Producer logs"&gt;&lt;/a&gt;Kafka Producer logs&lt;/p&gt;

&lt;p&gt;Our Producer produces data every 3 seconds.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Let’s run the &lt;strong&gt;KafkaConsumerRunner, &lt;/strong&gt;we should see something like this&lt;/li&gt;&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2ACTrerBBLu3M-W_Dqhskmfw.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2ACTrerBBLu3M-W_Dqhskmfw.png" alt="Kafka Consumer logs"&gt;&lt;/a&gt;Kafka Consumer logs&lt;/p&gt;

&lt;p&gt;Our consumer receives the data, every 3 seconds and we print it onto the console&lt;/p&gt;


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/kafka-example"&gt;&lt;em&gt;Source code.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>productivity</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Dart on AWS Lambda</title>
      <dc:creator>aseem wangoo</dc:creator>
      <pubDate>Wed, 03 Nov 2021 15:33:22 +0000</pubDate>
      <link>https://forem.com/aseemwangoo/dart-on-aws-lambda-1m0i</link>
      <guid>https://forem.com/aseemwangoo/dart-on-aws-lambda-1m0i</guid>
      <description>&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;We will cover briefly:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;Dart runtime for AWS Lambda&lt;/li&gt;
&lt;li&gt;Write lambda (using Dart)&lt;/li&gt;
&lt;li&gt;Adding a POST endpoint&lt;/li&gt;
&lt;li&gt;Deploy lambda on AWS&lt;/li&gt;
&lt;/ol&gt;



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

&lt;h3&gt;Dart runtime for AWS Lambda&lt;/h3&gt;

&lt;p&gt;With the introduction of &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html" rel="noreferrer noopener"&gt;custom AWS Lambda runtimes&lt;/a&gt;, it is possible to implement a runtime in any programming language.&lt;/p&gt;

&lt;p&gt;AWS Lambda provides an HTTP API for &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html" rel="noreferrer noopener"&gt;custom runtimes&lt;/a&gt; to receive invocation events and send response data back within the Lambda &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html" rel="noreferrer noopener"&gt;execution environment&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using the custom AWS Lambda runtime, we can also run Dart on Lambda with the &lt;a href="https://aws.amazon.com/blogs/opensource/introducing-a-dart-runtime-for-aws-lambda/" rel="noreferrer noopener"&gt;recently published runtime&lt;/a&gt; for the Dart programming language. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS released a pub package &lt;code&gt;&lt;a href="https://pub.dev/packages/aws_lambda_dart_runtime" rel="noreferrer noopener"&gt;aws_lambda_dart_runtime&lt;/a&gt;&lt;/code&gt; that packages the dart runtime to build lambda functions with AWS events.&lt;/li&gt;
&lt;li&gt;It shows two ways to deploy the dart based lambda functions&lt;/li&gt;
&lt;/ul&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AXBfz1sa6B7fJoRikUAtOoA.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AXBfz1sa6B7fJoRikUAtOoA.png" alt="Dart based lambda"&gt;&lt;/a&gt;Dart based lambda&lt;/p&gt;

&lt;p&gt;In this article, we will go with the &lt;strong&gt;Serverless Framework&lt;/strong&gt; approach&lt;/p&gt;

&lt;h3&gt;Write lambda (using Dart)&lt;/h3&gt;

&lt;blockquote&gt;&lt;p&gt;Pre-Requisite: You should have the aws cli configured in your machine. Check &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-mac.html" rel="noreferrer noopener"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;We will make use of the &lt;a href="https://www.serverless.com/" rel="noreferrer noopener"&gt;serverless&lt;/a&gt; framework to write lambda functions.&lt;/p&gt;

&lt;p&gt;As per the docs,&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Develop, deploy, troubleshoot and secure your serverless applications with radically less overhead and cost by using the Serverless Framework. The Serverless Framework consists of an open source CLI.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Serverless allows us to focus on the code, while it takes care of the setting up policies, and provisioning of required infrastructure onto AWS.&lt;/p&gt;

&lt;p&gt;To install &lt;code&gt;serverless&lt;/code&gt;, follow &lt;a href="https://www.serverless.com/framework/docs/getting-started" rel="noreferrer noopener"&gt;here&lt;/a&gt;. Personally, I configured using the below&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;npm install -g serverless&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;Setup for Dart&lt;/h4&gt;

&lt;ul&gt;&lt;li&gt;Currently, &lt;code&gt;serverless&lt;/code&gt; has no support for dart, but there is a serverless plugin for Dart applications, called &lt;a href="https://github.com/katallaxie/serverless-dart" rel="noreferrer noopener"&gt;&lt;strong&gt;serverless-dart&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; &lt;/strong&gt;We will install &lt;code&gt;serverless-dart&lt;/code&gt; using&lt;/li&gt;&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;npm i -D serverless-dart&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;&lt;li&gt;Now, this plugin builds the dart lambda using docker, hence we also need to &lt;a href="https://docs.docker.com/get-docker/" rel="noreferrer noopener"&gt;install docker&lt;/a&gt;
&lt;/li&gt;&lt;/ul&gt;





&lt;blockquote&gt;&lt;p&gt;Note: In case something goes wrong, try installing the &lt;code&gt;serverless&lt;/code&gt; framework, see above.&lt;/p&gt;&lt;/blockquote&gt;





&lt;h4&gt;Create a Dart Project&lt;/h4&gt;





&lt;p&gt;Once the above setup is configured, it’s time to create a dart project. We make use of the below&lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;npx serverless install \&lt;/span&gt;
  &lt;span class="s"&gt;--url https://github.com/katallaxie/serverless-aws-dart \&lt;/span&gt;
  &lt;span class="s"&gt;--name hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;This will download the source of a sample Dart application and unpack it as a service named &lt;code&gt;hello&lt;/code&gt; in a directory called &lt;code&gt;hello&lt;/code&gt;&lt;/p&gt;





&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AZAFWU4vsu3P-LzPkl-t62w.png" alt="Structure of the application"&gt;Structure of the application





&lt;ul&gt;
&lt;li&gt;I didn’t need the &lt;code&gt;.github/workflows&lt;/code&gt; hence, deleted the folder.&lt;/li&gt;
&lt;li&gt;If we look into &lt;code&gt;pubspec.yaml&lt;/code&gt; we will see the package &lt;code&gt;aws_lambda_dart_runtime&lt;/code&gt; and &lt;code&gt;build_runner&lt;/code&gt; under dev dependencies. We give both a version number.&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;aws_lambda_dart_runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^1.1.0&lt;/span&gt;
&lt;span class="na"&gt;dev_dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build_runner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we look into the &lt;code&gt;serverless.yml&lt;/code&gt; which is the brain behind this application. We modify the yml file with this&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello&lt;/span&gt;
&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dart&lt;/span&gt;
  &lt;span class="na"&gt;lambdaHashingVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20201221&lt;/span&gt;
  &lt;span class="na"&gt;memorySize&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;
&lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;individually&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-dart&lt;/span&gt;
&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main.hello&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/hello&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GET&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;service&lt;/strong&gt;: Name of the service (&lt;code&gt;hello&lt;/code&gt; in our case)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;functions&lt;/strong&gt;: The functions to be exposed, along with their entry points. We currently have a function called &lt;code&gt;hello&lt;/code&gt; Inside that, we specify the different configurations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;handler&lt;/strong&gt;: This is the AWS registered handler and should be the same as inside our &lt;code&gt;main.dart&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;events&lt;/strong&gt;: The events that trigger this function. This includes &lt;code&gt;http&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;http&lt;/strong&gt;: REST API endpoint (API Gateway v1)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;path&lt;/strong&gt;: Path for this endpoint&lt;code&gt;/hello&lt;/code&gt; and method being &lt;code&gt;GET&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Note: For detailed description: see &lt;a href="https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml" rel="noreferrer noopener"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;h4&gt;Inspecting the main dart&lt;/h4&gt;

&lt;p&gt;We are left with one important file to inspect &lt;code&gt;main.dart&lt;/code&gt; . We will change the contents of the file to below&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// IMPORT OMITTED FOR BREVITY&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;AwsApiGatewayEvent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;helloApiGateway&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'message'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Hello to &lt;/span&gt;&lt;span class="si"&gt;${context.requestId}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'host'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;${event.headers.host}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'userAgent'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;${event.headers.userAgent}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AwsApiGatewayResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nl"&gt;isBase64Encoded:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;statusCode:&lt;/span&gt; &lt;span class="n"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;headers:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"application/json"&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;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;AwsApiGatewayEvent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"main.hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;helloApiGateway&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&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;ul&gt;
&lt;li&gt;Every dart program begins with the call to &lt;code&gt;main&lt;/code&gt;function.&lt;/li&gt;
&lt;li&gt;The methods such as Handler, Runtime, etc are present inside the &lt;code&gt;aws_lambda_dart_runtime&lt;/code&gt; package.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;HelloApiGateway&lt;/h4&gt;

&lt;p&gt;We define a &lt;code&gt;helloApiGateway&lt;/code&gt; which is the handler to be invoked once our API gets hit. This is of the type &lt;code&gt;AwsApiGatewayEvent&lt;/code&gt; and exposes two important fields: &lt;code&gt;Context&lt;/code&gt; and &lt;code&gt;AwsApiGatewayEvent&lt;/code&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Context&lt;/code&gt; contains the Lambda execution context information. It comprises various parameters such as &lt;code&gt;requestId&lt;/code&gt; etc.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AwsApiGatewayEvent&lt;/code&gt; is one of the events supported by the package. An &lt;code&gt;Event&lt;/code&gt; is basically an abstraction for every event that can be ingested by a handler. It comprises of implementations such as &lt;code&gt;AwsCognitoEvent&lt;/code&gt; , &lt;code&gt;AwsS3Event&lt;/code&gt; , &lt;code&gt;AwsKinesisDataStreamEvent&lt;/code&gt; etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our case, we register the event of type &lt;code&gt;AwsApiGatewayEvent&lt;/code&gt; Hence, we can extract the details out of the incoming request. These details include &lt;code&gt;headers&lt;/code&gt; , &lt;code&gt;body&lt;/code&gt; , &lt;code&gt;queryStringParameters&lt;/code&gt; etc&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, for sending the response back to the client, we make use of &lt;code&gt;AwsApiGatewayResponse&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;We specify the &lt;code&gt;body&lt;/code&gt; to the sent, along with the additional parameters such as &lt;code&gt;isBase64Encoded&lt;/code&gt; , &lt;code&gt;statusCode&lt;/code&gt; and &lt;code&gt;headers&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Register HelloApiGateway&lt;/h4&gt;

&lt;p&gt;Once the handler is written, now we need to register it to our &lt;code&gt;Runtime&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is done using &lt;code&gt;registerHandler&lt;/code&gt; which takes in two required parameters: a string name and our gateway&lt;/li&gt;
&lt;li&gt;Under the name, we specify &lt;code&gt;main.hello&lt;/code&gt; (which is the same as specified inside the &lt;code&gt;serverless.yml&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Finally, we call &lt;code&gt;invoke&lt;/code&gt; to run the &lt;code&gt;Runtime&lt;/code&gt; in loop and digest events that are fetched from the API.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Adding a POST Endpoint&lt;/h3&gt;

&lt;p&gt;Inside our &lt;code&gt;serverless.yml&lt;/code&gt; add another endpoint for the post-service&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main.hello&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/hello&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GET&lt;/span&gt;
  &lt;span class="na"&gt;postRequest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main.postRequest&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/postRequest&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;POST&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The post body our API accepts is of the following type&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;BODY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;API&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"aseem"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will create a new endpoint called &lt;code&gt;postApiGateway&lt;/code&gt; which is also of the type &lt;code&gt;AwsApiGatewayEvent&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AwsApiGatewayEvent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;postApiGateway&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;requestBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;requestModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;postRequestModelFromJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;responseBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ResponseModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="s"&gt;'Hello &lt;/span&gt;&lt;span class="si"&gt;${requestModel.name}&lt;/span&gt;&lt;span class="s"&gt; from AWS Lambda!!'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AwsApiGatewayResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;responseModelToJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseBody&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;isBase64Encoded:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;statusCode:&lt;/span&gt; &lt;span class="n"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;headers:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"application/json"&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;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We extract the request body from the &lt;code&gt;event&lt;/code&gt; convert it into a model and extract the name parameter.&lt;/li&gt;
&lt;li&gt;We create &lt;code&gt;ResponseModel&lt;/code&gt; with the message parameter. &lt;/li&gt;
&lt;li&gt;Finally, we convert the model into JSON and send it back as &lt;code&gt;AwsApiGatewayResponse&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside our &lt;strong&gt;main dart, &lt;/strong&gt;we register our post handler as&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AwsApiGatewayEvent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"main.hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;helloApiGateway&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;registerHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AwsApiGatewayEvent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
      &lt;span class="s"&gt;"main.postRequest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;PostRequest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;postApiGateway&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;&lt;p&gt;Note: We specify &lt;code&gt;main.postRequest&lt;/code&gt; (which is the same as specified inside the &lt;code&gt;serverless.yml&lt;/code&gt;)&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;Deploy lambda on AWS&lt;/h3&gt;

&lt;p&gt;Till now, we have created our lambda function using dart. Now it’s time to deploy it. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: Make sure docker is running on your machine&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We will create a &lt;code&gt;Makefile&lt;/code&gt; and inside it put&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;build clean deploy&lt;/span&gt;
&lt;span class="nl"&gt;deploy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="err"&gt;npx&lt;/span&gt; &lt;span class="err"&gt;serverless&lt;/span&gt; &lt;span class="err"&gt;deploy&lt;/span&gt;
&lt;span class="nl"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="err"&gt;npx&lt;/span&gt; &lt;span class="err"&gt;serverless&lt;/span&gt; &lt;span class="err"&gt;remove&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For deploying the lambda, we can call &lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="err"&gt;make&lt;/span&gt; &lt;span class="err"&gt;deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything was successful, you should see something like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A_KnG2B4_NMe9n0khA0Pr7A.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A_KnG2B4_NMe9n0khA0Pr7A.png" alt="Lambda deployed successfully!!"&gt;&lt;/a&gt;Lambda deployed successfully!!&lt;/p&gt;

&lt;p&gt;For removing the lambda, we can call&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="err"&gt;make&lt;/span&gt; &lt;span class="err"&gt;remove&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;&lt;p&gt;Note: In case you don’t want to create a makefile, simply run &lt;code&gt;npx serverless deploy&lt;/code&gt;&lt;/p&gt;&lt;/blockquote&gt;


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://t264fzf6eh.execute-api.us-east-1.amazonaws.com/dev/hello"&gt;&lt;em&gt;Dart Lambda Get endpoint&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/flutter_programs/blob/master/dart_lambda.zip"&gt;&lt;em&gt;Source code.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.buymeacoffee.com%2Fassets%2Fimg%2Fcustom_images%2Forange_img.png" alt="Pass Me A Coffee!!"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>programming</category>
      <category>dart</category>
      <category>aws</category>
    </item>
    <item>
      <title>Supercharge your Kotlin Project</title>
      <dc:creator>aseem wangoo</dc:creator>
      <pubDate>Wed, 20 Oct 2021 15:02:12 +0000</pubDate>
      <link>https://forem.com/aseemwangoo/supercharge-your-kotlin-project-2mcb</link>
      <guid>https://forem.com/aseemwangoo/supercharge-your-kotlin-project-2mcb</guid>
      <description>&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kziPr3-e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;This article shares some tips on things to include inside your kotlin project. We will cover briefly:&lt;/p&gt;





&lt;ol&gt;
&lt;li&gt;Ktlint&lt;/li&gt;
&lt;li&gt;Detekt&lt;/li&gt;
&lt;li&gt;Github workflow&lt;/li&gt;
&lt;/ol&gt;



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

&lt;blockquote&gt;&lt;p&gt;Note: This article assumes the reader knows about Kotlin&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;Ktlint&lt;/h3&gt;

&lt;p&gt;Linting is the process of analyzing code for potential errors and one of the ways we can do that in Kotlin is using &lt;a href="https://ktlint.github.io/" rel="noreferrer noopener"&gt;&lt;strong&gt;Ktlint&lt;/strong&gt;&lt;/a&gt;. As per the documentation:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;a href="https://ktlint.github.io/" rel="noreferrer noopener"&gt;&lt;strong&gt;Ktlint&lt;/strong&gt;&lt;/a&gt; is an anti-bikeshedding Kotlin linter&lt;/p&gt;&lt;/blockquote&gt;

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

&lt;p&gt;There are two ways to integrate Ktlint in a kotlin project. &lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;jlleitschuh&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ktlint-gradle&lt;/span&gt;
&lt;span class="n"&gt;jeremymailen&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;kotlinter-gradle&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will be using &lt;a href="https://github.com/JLLeitschuh/ktlint-gradle" rel="noreferrer noopener"&gt;ktlint-gradle&lt;/a&gt;, which is a wrapper over ktlint.&lt;/p&gt;

&lt;h4&gt;Setup&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Head over to the project-level &lt;a href="https://github.com/AseemWangoo/hands_on_kotlin/blob/master/build.gradle" rel="noreferrer noopener"&gt;build.gradle&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Inside the &lt;code&gt;buildscripts&lt;/code&gt; add the latest version in &lt;code&gt;ext&lt;/code&gt; and add the dependency under &lt;code&gt;dependencies&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// https://github.com/JLLeitschuh/ktlint-gradle/releases&lt;/span&gt;
   &lt;span class="n"&gt;ktlintPluginVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"10.2.0"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="s1"&gt;'com.android.tools.build:gradle:7.0.0'&lt;/span&gt;
    &lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="s2"&gt;"org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32"&lt;/span&gt;

    &lt;span class="err"&gt;##&lt;/span&gt; &lt;span class="n"&gt;KTLINT&lt;/span&gt; &lt;span class="n"&gt;DEPENDENCY&lt;/span&gt;
    &lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="s2"&gt;"org.jlleitschuh.gradle:ktlint-gradle:$ktlintPluginVersion"&lt;/span&gt;    
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the &lt;code&gt;repositories&lt;/code&gt; section, add this&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;repositories&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;google&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;mavenCentral&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="err"&gt;##&lt;/span&gt; &lt;span class="n"&gt;ADDED&lt;/span&gt; &lt;span class="n"&gt;THIS&lt;/span&gt; &lt;span class="n"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;KTLINT&lt;/span&gt;
    &lt;span class="n"&gt;maven&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="s2"&gt;"https://plugins.gradle.org/m2/"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create a separate file for configuring/customizing &lt;code&gt;ktlint&lt;/code&gt;. Create a directory &lt;code&gt;buildscripts&lt;/code&gt;at the project level and inside it, create a new file called &lt;code&gt;&lt;a href="https://github.com/AseemWangoo/hands_on_kotlin/blob/master/buildscripts/ktlint.gradle" rel="noreferrer noopener"&gt;ktlint.gradle&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s2"&gt;"org.jlleitschuh.gradle.ktlint"&lt;/span&gt;
&lt;span class="n"&gt;ktlint&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// https://github.com/pinterest/ktlint/releases&lt;/span&gt;
    &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.42.1"&lt;/span&gt;
    &lt;span class="n"&gt;reporters&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;reporter&lt;/span&gt; &lt;span class="s2"&gt;"plain"&lt;/span&gt;
        &lt;span class="n"&gt;reporter&lt;/span&gt; &lt;span class="s2"&gt;"checkstyle"&lt;/span&gt;
        &lt;span class="n"&gt;reporter&lt;/span&gt; &lt;span class="s2"&gt;"html"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;outputColorName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"RED"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we apply this configuration to all our &lt;code&gt;subprojects&lt;/code&gt; by adding the below inside our project-level &lt;a href="https://github.com/AseemWangoo/hands_on_kotlin/blob/master/build.gradle" rel="noreferrer noopener"&gt;build.gradle&lt;/a&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;subprojects&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;from:&lt;/span&gt; &lt;span class="s2"&gt;"../buildscripts/ktlint.gradle"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;&lt;li&gt;Click &lt;code&gt;Sync Now&lt;/code&gt; If everything is successful, we should see a gradle task called &lt;code&gt;ktlintformat&lt;/code&gt; &lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--miIraSbV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AWnYNJ1vGKehpDZqrmFXgyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--miIraSbV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AWnYNJ1vGKehpDZqrmFXgyw.png" alt="ktlintFormat Gradle task" width="634" height="370"&gt;&lt;/a&gt;ktlintFormat Gradle task&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Note: In case you are not able to see your gradle tasks, check this &lt;a href="https://programmerah.com/gradle-tasks-disappeared-after-upgrading-android-stuido-4-2-29098/" rel="noreferrer noopener"&gt;post&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;ul&gt;&lt;li&gt;After running the task &lt;code&gt;ktlintformat&lt;/code&gt; it outputs the results, (in case of errors, it will show the file which has the details of the files)&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pOaCFrOF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AzsPB0DYfRaEFBxnMve9Dtg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pOaCFrOF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AzsPB0DYfRaEFBxnMve9Dtg.png" alt="ktlintformat errors" width="880" height="120"&gt;&lt;/a&gt;ktlintformat errors&lt;/p&gt;

&lt;p&gt;Click on the &lt;code&gt;.txt&lt;/code&gt; file and correct the errors accordingly.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Note: You will probably have a lot of file changes, since &lt;code&gt;ktlintformat&lt;/code&gt; checks all your project files and corrects them as per the kotlin standard.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;Detekt&lt;/h3&gt;

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

&lt;p&gt;&lt;a href="https://github.com/detekt/detekt" rel="noreferrer noopener"&gt;Detekt&lt;/a&gt; is a static code analysis tool for the &lt;em&gt;Kotlin&lt;/em&gt; programming language. It operates on the abstract syntax tree provided by the Kotlin compiler.&lt;/p&gt;

&lt;p&gt;It analyzes the Kotlin code with multiple rule sets and flags the code that breaks any of its rules.&lt;/p&gt;

&lt;h4&gt;Setup&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Head over to the project-level &lt;a href="https://github.com/AseemWangoo/hands_on_kotlin/blob/master/build.gradle" rel="noreferrer noopener"&gt;build.gradle&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Inside the &lt;code&gt;buildscripts&lt;/code&gt; add the latest version in &lt;code&gt;ext&lt;/code&gt; and add the dependency under &lt;code&gt;dependencies&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// https://github.com/detekt/detekt/releases&lt;/span&gt;
   &lt;span class="n"&gt;detektVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1.17.0"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="s1"&gt;'com.android.tools.build:gradle:7.0.0'&lt;/span&gt;
    &lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="s2"&gt;"org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32"&lt;/span&gt;

    &lt;span class="err"&gt;##&lt;/span&gt; &lt;span class="n"&gt;DETEKT&lt;/span&gt; &lt;span class="n"&gt;DEPENDENCY&lt;/span&gt;
    &lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="s2"&gt;"io.gitlab.arturbosch.detekt:detekt-gradle-    plugin:$detektVersion"&lt;/span&gt;  
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create a separate file for configuring/customizing &lt;code&gt;detekt&lt;/code&gt;. Create a directory &lt;code&gt;buildscripts&lt;/code&gt;at the project level (ignore if you created in the above step) and inside it, create a new file called &lt;code&gt;&lt;a href="https://github.com/AseemWangoo/hands_on_kotlin/blob/master/buildscripts/detekt.gradle" rel="noreferrer noopener"&gt;detekt.gradle&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s2"&gt;"io.gitlab.arturbosch.detekt"&lt;/span&gt;

&lt;span class="n"&gt;detekt&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"${rootProject.projectDir}/config/detekt/detekt.yml"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;reports&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;&lt;p&gt;Note: The config file &lt;code&gt;detekt.yml&lt;/code&gt; doesn’t exist yet, we will see in the later step&lt;/p&gt;&lt;/blockquote&gt;

&lt;ul&gt;&lt;li&gt;Finally, we apply this configuration to all our &lt;code&gt;subprojects&lt;/code&gt; by adding the below inside our project-level &lt;a href="https://github.com/AseemWangoo/hands_on_kotlin/blob/master/build.gradle" rel="noreferrer noopener"&gt;build.gradle&lt;/a&gt;
&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;subprojects&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;from:&lt;/span&gt; &lt;span class="s2"&gt;"../buildscripts/detekt.gradle"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;ul&gt;&lt;li&gt;Click &lt;code&gt;Sync Now&lt;/code&gt; If everything is successful, we should see a gradle task called &lt;code&gt;detektGenerateConfig&lt;/code&gt; and run it&lt;/li&gt;&lt;/ul&gt;





&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7Fr-5wGI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AumyJODh2sYWfrV1fBhijbw.png" alt="detekt generateConfig gradle task" width="762" height="374"&gt;detekt generateConfig gradle task





&lt;ul&gt;&lt;li&gt;After running the task, it generates the config file called &lt;code&gt;detekt.yml&lt;/code&gt; &lt;/li&gt;&lt;/ul&gt;





&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9kKkQPfp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AFU1_dEdG0d-Loq1nfDyj6g.png" alt="detekt config yml" width="552" height="230"&gt;detekt config yml





&lt;p&gt;which comprises of all the configurations, detekt comes with. We can customize it according to our preference.&lt;/p&gt;





&lt;ul&gt;&lt;li&gt;Finally, we run the following in our project&lt;/li&gt;&lt;/ul&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;gradlew&lt;/span&gt; &lt;span class="n"&gt;detekt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;This will show you all the issues inside your project, along with the configuration name.&lt;/p&gt;





&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9vvZw0ZT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2AHh5rG3JD8BaO64mxnHNO1Q.png" alt="detekt issues in project" width="880" height="94"&gt;detekt issues in project





&lt;p&gt;In case, you want to suppress some issue in a file, for instance, the above issues related to &lt;code&gt;MagicNumber&lt;/code&gt; , we can simply go to the file and add&lt;/p&gt;




&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nc"&gt;Suppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MagicNumber"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h3&gt;Github workflow&lt;/h3&gt;



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



&lt;p&gt;We saw in the above steps how to integrate &lt;code&gt;ktlint&lt;/code&gt; and &lt;code&gt;detekt&lt;/code&gt; inside our kotlin project.&lt;/p&gt;





&lt;p&gt;In the last step, we will integrate both with our CI, ensuring the main branch, always remains standardized.&lt;/p&gt;





&lt;ul&gt;
&lt;li&gt;Add a &lt;code&gt;.github&lt;/code&gt; directory inside the project.&lt;/li&gt;
&lt;li&gt;Create a subdirectory &lt;code&gt;workflows&lt;/code&gt; and inside it, create a file called &lt;code&gt;&lt;a href="https://github.com/AseemWangoo/hands_on_kotlin/blob/master/.github/workflows/android_build.yml" rel="noreferrer noopener"&gt;android_build.yml&lt;/a&gt;&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Android Build&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set Up JDK&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.11&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Project&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradlew assemble&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradlew test&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lint Checks&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradlew ktlintCheck detekt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In the last step, we include the &lt;code&gt;ktlintCheck&lt;/code&gt; as well as &lt;code&gt;detekt&lt;/code&gt; Since this job runs on push, we will be sure in case the code is according to our conventions.&lt;/li&gt;
&lt;li&gt;We can also add a branch protection rule for requiring status checks to pass and selecting &lt;code&gt;build&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QxJIv3mm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2ALTwmzsXI-UJrp7xyv27R2A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QxJIv3mm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1600/1%2ALTwmzsXI-UJrp7xyv27R2A.png" alt="Branch protection rule" width="880" height="600"&gt;&lt;/a&gt;Branch protection rule&lt;/p&gt;

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


&lt;p&gt;&lt;a rel="noreferrer noopener" href="https://github.com/AseemWangoo/hands_on_kotlin"&gt;&lt;em&gt;Source code.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In case it helped :)&lt;/em&gt;&lt;br&gt;
&lt;a href="https://www.buymeacoffee.com/aseemwangoo"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kziPr3-e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" width="170" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>computerscience</category>
      <category>kotlin</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
