<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Matt Irby</title>
    <description>The latest articles on DEV Community by Matt Irby (@irby).</description>
    <link>https://dev.to/irby</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%2F544877%2F6447dd0f-ac42-4c59-bffc-003106c0372e.jpeg</url>
      <title>DEV Community: Matt Irby</title>
      <link>https://dev.to/irby</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/irby"/>
    <language>en</language>
    <item>
      <title>SpiceDB HRBAC: A Practical Implementation</title>
      <dc:creator>Matt Irby</dc:creator>
      <pubDate>Tue, 14 Oct 2025 03:53:27 +0000</pubDate>
      <link>https://dev.to/irby/spicedb-hrbac-a-practical-implementation-1lbd</link>
      <guid>https://dev.to/irby/spicedb-hrbac-a-practical-implementation-1lbd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article has some code snippet examples hosted on GitHub. View here: (&lt;a href="https://github.com/irby/spicedb-hrbac-example" rel="noopener noreferrer"&gt;https://github.com/irby/spicedb-hrbac-example&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While working on an internal tool for managing virtual environments, a feature request added into the tool was the ability to share environments with other users. To implement this securely, we needed a way to determine what level of access a given subject (user) had to a particular object (environment or tenant). Given that we may need various roles for a given object (i.e. admin, editor, and viewer), we needed an authorization layer that could handle hierarchical role-based access control (HRBAC).&lt;/p&gt;

&lt;p&gt;To minimize the amount of custom code to handle authorization, we decided to leverage &lt;a href="https://research.google/pubs/zanzibar-googles-consistent-global-authorization-system/" rel="noopener noreferrer"&gt;Google Zanzibar&lt;/a&gt; for a number of reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Zanzibar design favors for quick writes while offering efficient, low-latency lookups&lt;/li&gt;
&lt;li&gt;the graph-based model naturally handles nested roles, group membership, and resource hierarchies&lt;/li&gt;
&lt;li&gt;Zanzibar has been proven to work at scale, lending to an efficient and reliable authorization system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Zanzibar implementation I was particularly drawn to was &lt;a href="https://authzed.com/spicedb" rel="noopener noreferrer"&gt;AuthZed's SpiceDB&lt;/a&gt;. SpiceDB offers a mature, open-source, and actively maintained solution with comprehensive documentation, a flexible and extensible schema model, and Kubernetes support through its dedicated operator, making it straightforward to deploy and manage in production environments.&lt;/p&gt;

&lt;p&gt;There are many great articles written on how to configure SpiceDB to handle complex role-based access control, for example &lt;a href="https://medium.com/@esalamapa/a-taste-of-spicedb-a-practical-guide-to-getting-started-bf63842b1ee6" rel="noopener noreferrer"&gt;this article&lt;/a&gt; goes into great depth to discuss relation-based access control (ReBAC). But, I do want to dive into how one can make a hierarchical role-based access control (HRBAC) possible via SpiceDB.&lt;/p&gt;

&lt;p&gt;I've created a GitHub repository for this example: (&lt;a href="https://github.com/irby/spicedb-hrbac-example" rel="noopener noreferrer"&gt;https://github.com/irby/spicedb-hrbac-example&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Consider the following schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;definition user {}

definition role {
    // A role belongs to a specific tenant
    relation tenant: tenant

    // Users can be assigned to this role
    relation assignee: user

    // Define the hierarchical permissions
    permission admin = assignee
    permission editor = assignee + admin
    permission viewer = assignee + editor
}

definition tenant {
    // Direct role assignments within this tenant
    relation admin_role: role
    relation editor_role: role  
    relation viewer_role: role

    // Computed permissions based on role assignments
    permission admin = admin_role-&amp;gt;assignee
    permission editor = editor_role-&amp;gt;assignee + admin
    permission viewer = viewer_role-&amp;gt;assignee + editor
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this schema, we've defined the following relations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;user&lt;/code&gt; can be assigned to a &lt;code&gt;tenant&lt;/code&gt; via a &lt;code&gt;role&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;role&lt;/code&gt; can be one of the following:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;admin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;editor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;viewer&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;These roles have the following hierarchy

&lt;ul&gt;
&lt;li&gt;an &lt;code&gt;admin&lt;/code&gt; inherently has &lt;code&gt;editor&lt;/code&gt; and &lt;code&gt;viewer&lt;/code&gt; access&lt;/li&gt;
&lt;li&gt;an &lt;code&gt;editor&lt;/code&gt; inherently has &lt;code&gt;viewer&lt;/code&gt; access&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;viewer&lt;/code&gt; only has its own access.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;These roles are tenant-scoped. A role relationship to tenant A is logically separate from a role relationship to tenant B.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;While a relatively simple implementation, this gives us enough flexibility to configure the HRBAC we require for our internal tool. Combined with SpiceDB's robust SDKs and APIs, this proof of concept demonstrates that we can achieve scalable, maintainable authorization without the burden of building and maintaining custom logic from scratch.&lt;/p&gt;

</description>
      <category>spicedb</category>
      <category>go</category>
      <category>security</category>
    </item>
    <item>
      <title>Cryptography – A Gentle Overview (Part 2: Encryption)</title>
      <dc:creator>Matt Irby</dc:creator>
      <pubDate>Sun, 05 Feb 2023 21:24:46 +0000</pubDate>
      <link>https://dev.to/irby/cryptography-a-gentle-overview-part-2-encryption-67k</link>
      <guid>https://dev.to/irby/cryptography-a-gentle-overview-part-2-encryption-67k</guid>
      <description>&lt;h4&gt;
  
  
  Previous Entry
&lt;/h4&gt;

&lt;p&gt;This post is part 2 of a series. Click &lt;a href="https://dev.to/irby/cryptography-a-gentle-overview-j8i"&gt;here&lt;/a&gt; to read the first entry in this series.&lt;/p&gt;

&lt;h2&gt;
  
  
  Symmetric Encryption
&lt;/h2&gt;

&lt;p&gt;In symmetric encryption, the same key is used to encrypt and decrypt. Plaintext is converted into ciphertext using a key and the ciphertext can be converted back to plaintext with the same key. &lt;/p&gt;

&lt;p&gt;Symmetric encryption has been used for thousands of years. A famous example of symmetric encryption is a &lt;a href="https://en.wikipedia.org/wiki/Caesar_cipher" rel="noopener noreferrer"&gt;Caesar cipher&lt;/a&gt;. A Caesar cipher works by shifting characters in a text by a fixed number of positions. When the shift exceeds the bounds of the alphabet, it wraps back around to the start of the alphabet.&lt;/p&gt;

&lt;p&gt;For example, this is an example of a Caesar cipher with a shift of 2.&lt;/p&gt;

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

&lt;p&gt;For example, this is an example of a Caesar decipher with a shift of 2.&lt;/p&gt;

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

&lt;p&gt;While this form of encryption is relatively simple, it is also quite easy to break. By mapping the frequency of commonly used letters (&lt;em&gt;frequency analysis&lt;/em&gt;), it is possible to derive a shift value and keep updating the shift until the ciphertext converts into a readable plaintext.&lt;/p&gt;

&lt;p&gt;Fortunately, other symmetric encryption schemes exist that are much more secure than the Caesar cipher. Some of the first modern symmetric encryption schemes were &lt;a href="https://en.wikipedia.org/wiki/Data_Encryption_Standard" rel="noopener noreferrer"&gt;DES&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Triple_DES" rel="noopener noreferrer"&gt;3DES&lt;/a&gt;, developed in the late 70s / early 80s (they have since been deprecated by NIST). As of this publishing, Advanced &lt;a href="https://en.wikipedia.org/wiki/Advanced_Encryption_Standard" rel="noopener noreferrer"&gt;Encryption Scheme (AES)&lt;/a&gt; remains one of the most popular, widely-used symmetric encryption schemes still used today.&lt;/p&gt;

&lt;p&gt;The challenge of utilizing symmetric encryption to securely communicate with other parties – especially over the internet – is how the key is shared. If Alice creates a key, how can she share the key with Bob without exposing it to a malicious actor, Eve? Another type of cryptographic algorithm is required: &lt;em&gt;asymmetric encryption&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asymmetric Encryption
&lt;/h2&gt;

&lt;p&gt;In asymmetric encryption (also known as &lt;em&gt;public key cryptography&lt;/em&gt;), different keys are required to encrypt and decrypt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public key - used to &lt;em&gt;encrypt&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Private key - used to &lt;em&gt;decrypt&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, if Alice wants to securely send a message to Bob:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alice will use Bob's public key to encrypt a message and send it to Bob&lt;/li&gt;
&lt;li&gt;Bob will use his private key to decrypt Alice's message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since a message encrypted by a public key cannot be decrypted without the private key, it is extremely important that the private key is never shared with anyone.&lt;/p&gt;

&lt;p&gt;Examples of asymmetric encryption algorithms in use today are &lt;a href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)" rel="noopener noreferrer"&gt;RSA&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Elliptic-curve_cryptography" rel="noopener noreferrer"&gt;Elliptic Curve Cryptography (ECC)&lt;/a&gt;. While this blog will not dive into it, these schemes rely on mathematics to create difficult problems to solve, such as prime number factorization or difficulty finding a discrete logarithm for a curve, respectively.&lt;/p&gt;

&lt;p&gt;While asymmetric encryption enables secure communication between two or more parties, it has its limitations. In terms of performance, asymmetric encryption is typically slower than symmetric encryption. This is largely due to the mathematics involved in their implementation as mentioned in the previous paragraph. Additionally, asymmetric encryption is bound on its input size; it cannot operate on large inputs.&lt;/p&gt;

&lt;p&gt;In practical applications, a hybrid approach of using both symmetric and asymmetric encryption is utilized:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encrypt a plaintext T with symmetric encryption to produce a ciphertext C1. Encrypt C1 with asymmetric encryption to produce ciphertext C2.&lt;/li&gt;
&lt;li&gt;Decrypt ciphertext C2 with asymmetric encryption to produce ciphertext C1. Decrypt C1 with symmetric encryption to produce plaintext T.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A famous example of hybrid encryption is the &lt;a href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange" rel="noopener noreferrer"&gt;Diffie-Hellman key exchange protocol&lt;/a&gt;, which describes how two parties can establish a shared symmetric key using their public and private keys. &lt;a href="https://www.youtube.com/watch?v=U62S8SchxX4" rel="noopener noreferrer"&gt;This video&lt;/a&gt; gives a good explanation of how the key exchange protocol works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encryption So Far
&lt;/h2&gt;

&lt;p&gt;So far, we've established that symmetric and asymmetric encryption both offer confidentiality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In symmetric encryption, only those with the shared secret key can read an encrypted message.&lt;/li&gt;
&lt;li&gt;In asymmetric encryption, only the person with the private key can read a message encrypted by the public key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the previous post, I described a CIA triad cryptography can fulfill (confidentiality / integrity / authenticity). What about integrity and authenticity? &lt;/p&gt;

&lt;p&gt;In the next couple of sections, I will describe how hashing could be used to fulfill these missing pillars.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hashing
&lt;/h2&gt;

&lt;p&gt;Hashing is the one-way conversion of a plaintext to a ciphertext (also known as a &lt;em&gt;backdoor function&lt;/em&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A plaintext T1 can be converted to hash H1. H1 cannot be converted back to T1.&lt;/li&gt;
&lt;li&gt;Given a constant plaintext T1, it will always produce hash H1.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A property of hashing is that it is one-to-one, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Given two unique plaintexts T1 and T2, hash(T1) != hash(T2).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some notable hashing algorithms include MD5, SHA (1/256/512) and Bcrypt.&lt;/p&gt;

&lt;p&gt;You may have come across a scenario where you've downloaded a file from the internet and the site you've downloaded the file from provides an MD5 hash of the file. This is to ensure the integrity of the download: the file was downloaded completely and is the correct version of the file you're expecting.&lt;/p&gt;

&lt;p&gt;Another application of hashing is to obscure sensitive information that shouldn't be recovered, such as a password. When a user's password is set, a hash of the password is stored in the database. Then, next time the user logs in, their supplied password is hashed and compared against the stored password hash. This is an example of using hashing to achieve confidentiality.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is beyond the scope of this post, but hashes can utilize &lt;a href="https://en.wikipedia.org/wiki/Salt_(cryptography)" rel="noopener noreferrer"&gt;salting&lt;/a&gt; to achieve unique hashes given a constant input. This is primarily used to produce different password hashes given the same password.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hashing + Encryption
&lt;/h2&gt;

&lt;p&gt;Since anyone can send Bob a message by using his public key, how can Bob validate who sent him a message? If Bob receives a message saying "Send Eve 5 dollars", how can he ensure this message came from Alice and not Eve?&lt;/p&gt;

&lt;p&gt;This is where HMAC (Hash-based Message Authenticator Code) can be used to validate the authenticity of the sender.&lt;/p&gt;

&lt;p&gt;HMAC offers two main functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signing - sign a hash using the &lt;em&gt;private key of the sender&lt;/em&gt; to produce a signature&lt;/li&gt;
&lt;li&gt;Verifying - verify the signature using the &lt;em&gt;public key of the sender&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if Alice wants to send Bob the message "Send Eve 5 dollars":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alice encrypts "Send Eve 5 dollars" with Bob's public key to produce ciphertext C1.&lt;/li&gt;
&lt;li&gt;"Send Eve 5 dollars" is hashed by Alice to produce hash H1
&lt;/li&gt;
&lt;li&gt;Alice will then sign H1 with Alice's private key to produce signature S1.&lt;/li&gt;
&lt;li&gt;Bob receives ciphertext C1 and signature S1.&lt;/li&gt;
&lt;li&gt;Bob decrypts ciphertext C1 with his private key to produce plaintext "Send Eve 5 dollars".&lt;/li&gt;
&lt;li&gt;Bob hashes "Send Eve 5 dollars" to produce hash H2.&lt;/li&gt;
&lt;li&gt;Bob verifies hash H2 was used to produce signature S1 by using Alice's public key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If validation passes, Bob can verify that the message he received from Alice was what was intended (integrity) and that Alice was the one who sent it (authenticity).&lt;/p&gt;

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

&lt;p&gt;Although it is necessary for secure communication, cryptography has a lot of elements at play and can be a complex field. Through the course of this article, we explored the different encryption schemes and how, when combined with hashing, all of these components can be used to verify the confidentiality, integrity and authenticity of our communications.&lt;/p&gt;

&lt;p&gt;As a final note, cryptography is not a perfect field. It relies on mathematics and computational complexity. As computer hardware becomes more efficient and can compute quicker, cryptographic functions that were once considered secure have since become insecure. When deciding on an encryption scheme to use in your application, verify it is appropriate for your scenario and whether the scheme is still considered secure.&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;h2&gt;
  
  
  Good Literature
&lt;/h2&gt;

&lt;p&gt;If you're interested in learning more about cryptography and want to learn more about the subject as a whole:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Foundations of Cryptography&lt;/em&gt;&lt;/strong&gt; by George Kudrayvtsev (&lt;a href="https://teapowered.dev/assets/crypto-notes.pdf" rel="noopener noreferrer"&gt;link &lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Introduction to Modern Cryptography&lt;/em&gt;&lt;/strong&gt; by M. Ballare, P. Rogaway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're interested in learning about the history behind cryptography and the historical figures behind our modern-day cryptographic landscape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Crypto&lt;/em&gt;&lt;/strong&gt; by Steven Levy&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>cloud</category>
      <category>rust</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Cryptography – A Gentle Overview (Part 1: Intro)</title>
      <dc:creator>Matt Irby</dc:creator>
      <pubDate>Wed, 30 Nov 2022 05:09:27 +0000</pubDate>
      <link>https://dev.to/irby/cryptography-a-gentle-overview-j8i</link>
      <guid>https://dev.to/irby/cryptography-a-gentle-overview-j8i</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I recently gave a lunch-and-learn discussing cryptography, and I figured I could convert the talk into a series of blog posts. While cryptography is a topic I enjoy learning, it is certainly not a field I am an expert in by any means. However, I feel that discussing it (verbally or written) helps me reinforce the knowledge.&lt;/p&gt;

&lt;p&gt;At depth, cryptography can be a complicated subject matter because it can get into the weeds of mathematics and understanding abstract concepts. So, these posts will be a gentle introduction to the topic that will discuss some concepts in cryptography at a high-level. &lt;/p&gt;

&lt;p&gt;This post will start off with a definition of cryptography, introduce some vocabulary, and wrap up with a little note about encryption. The next post will take what has been discussed here and flesh it out more.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Cryptography, Anyway?
&lt;/h2&gt;

&lt;p&gt;Cryptography is the process of protecting information and communication by obscuring its contents so it can only be read by an intended party. If the contents are to be read, there should be a guarantee about who originated the information. The mechanisms by which the information is obscured should use strong, mathematically intensive functions.&lt;/p&gt;

&lt;p&gt;In the open internet, we can't blindly trust that our communication is safe. There is always the chance that our communication could be intercepted or forged by a malicious actor. When information is stored, it should be protected by an unwanted person from reading its contents. Cryptography can help ensure information is protected when sent between parties (in-transit) or stored (at rest).&lt;/p&gt;

&lt;p&gt;Information security aims to address three pillars: &lt;strong&gt;confidentiality&lt;/strong&gt;, &lt;strong&gt;integrity&lt;/strong&gt;, and &lt;strong&gt;availability&lt;/strong&gt;. These make up the &lt;em&gt;CIA triad&lt;/em&gt; of security. In cryptography, while confidentiality and integrity are relevant, availability is not a concern. However, we do care about verifying where information came from. &lt;/p&gt;

&lt;p&gt;Therefore, cryptography should address the following CIA triad:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Confidentiality&lt;/strong&gt;: Information cannot be read by unauthorized parties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrity&lt;/strong&gt;: Data is not tampered with during transmission. It is complete.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authenticity&lt;/strong&gt;: Only the sender could have sent the message.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introducing Some Vocabulary
&lt;/h2&gt;

&lt;p&gt;Before diving in, let's introduce some vocabulary and provide some definitions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Encrypt&lt;/strong&gt;: Converting something readable into an unreadable form.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decrypt&lt;/strong&gt;: Converting something unreadable into a readable form&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plaintext&lt;/strong&gt;: Ordinary, readable text &lt;em&gt;before encryption&lt;/em&gt; and &lt;em&gt;after decryption&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ciphertext&lt;/strong&gt;: Unreadable text that is &lt;em&gt;output of encryption&lt;/em&gt; and &lt;em&gt;input to decryption&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hashing&lt;/strong&gt;: One-way conversion of a plaintext to a ciphertext. This &lt;strong&gt;should not&lt;/strong&gt; be able to convert back to plaintext.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cryptographic Cast of Characters
&lt;/h2&gt;

&lt;p&gt;If you come across literature concerning cryptography, sometimes example scenarios are provided to explain a concept. These examples probably involve characters named Alice, Bob, Eve, Mallory, etc. Alice and Bob are innocent actors while Eve and Mallory are typically malicious actors. For more information on these characters, feel free to check out &lt;a href="https://en.wikipedia.org/wiki/Alice_and_Bob" rel="noopener noreferrer"&gt;this Wikipedia article on Alice and Bob&lt;/a&gt;.&lt;/p&gt;

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




&lt;h2&gt;
  
  
  Encryption
&lt;/h2&gt;

&lt;p&gt;Encryption is the act of converting something readable into an unreadable form. Decryption is the act of converting something unreadable into a readable form. Information is encrypted using a key and decrypted using a key. The keys do not need to be the same.&lt;/p&gt;

&lt;p&gt;The main types of encryption include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Symmetric Encryption&lt;/strong&gt;: The same key is used to encrypt and decrypt a message (&lt;em&gt;secret key&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asymmetric Encryption&lt;/strong&gt;: A &lt;em&gt;public key&lt;/em&gt; is used to &lt;em&gt;encrypt&lt;/em&gt; a message and a &lt;em&gt;private key&lt;/em&gt; is used to &lt;em&gt;decrypt&lt;/em&gt; a message. Also known as &lt;em&gt;public key encryption&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid Encryption&lt;/strong&gt;: A blend of symmetric and asymmetric encryption.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Initialization Vectors
&lt;/h3&gt;

&lt;p&gt;So far, we've discussed a key and plaintext as input to encryption. If a plaintext is encrypted twice with the same key, is the resulting ciphertext the same? From what we have, the resulting ciphertext would be the same. This can be a bad thing. If an attacker knows the encryption of plaintext &lt;em&gt;A&lt;/em&gt; produces ciphertext &lt;em&gt;B&lt;/em&gt;, any time they see &lt;em&gt;B&lt;/em&gt; they can infer that &lt;em&gt;A&lt;/em&gt; was input. This would violate confidentiality.&lt;/p&gt;

&lt;p&gt;Another component is needed to maintain confidentiality of encryption – an &lt;strong&gt;initialization vector&lt;/strong&gt; (IV). The IV should be unpredictable / random and generated prior to any message encryption. Even if the plaintext and key are the same, a unique random IV will guarantee each resulting ciphertext will be different. The IV is usually appended at the start of the ciphertext and is used as input to decryption. It does not need to be secret.&lt;/p&gt;

&lt;p&gt;Randomness is one of the most crucial parts of cryptography, especially for IVs. It is also near impossible to produce a truly random value – how do you produce a truly random number? I won't go into detail for this post about randomness (&lt;a href="https://thecodeboss.dev/2017/05/why-random-numbers-are-impossible-in-software/" rel="noopener noreferrer"&gt;this post&lt;/a&gt; goes into good detail). IVs should be seeded using a &lt;em&gt;secure random number generator&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bits and Bytes
&lt;/h3&gt;

&lt;p&gt;Nearly everything in cryptography is expressed in bits and bytes. Some encryption schemes (ciphers) work from fixed-length groups of bits called &lt;strong&gt;blocks&lt;/strong&gt;. As you come across different algorithms, keys/blocks may require different bit sizes (256-bit / 512-bits).&lt;/p&gt;

&lt;p&gt;While key length does not imply security, some encryption algorithms have been proven to be weak when key size is small (see &lt;a href="https://electricenergyonline.com/energy/magazine/779/article/Security-Sessions-Exploring-Weak-Ciphers.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;). A larger key size can decrease performance. When choosing an encryption algorithm, always research its implementation, what key sizes are recommended, and whether it's still considered secure. As computers get faster, encryption with smaller key sizes can be "broken" more quickly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary &amp;amp; Up Next
&lt;/h2&gt;

&lt;p&gt;A lot of material has been covered so far!&lt;/p&gt;

&lt;p&gt;The next post in this series will take a look at symmetric and asymmetric encryption, understand what they are, how they could be applied, and what their limitations are. It will also dive into hashing and explain its usage. The post will conclude with how encryption and hashing could be used to fulfill the CIA triad of cryptography.&lt;/p&gt;

&lt;p&gt;Thank you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2
&lt;/h2&gt;

&lt;p&gt;Part 2 of this post is now available! Link to the next article: &lt;a href="https://dev.to/irby/cryptography-a-gentle-overview-part-2-encryption-67k"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>Making GDB Easier: The TUI Interface</title>
      <dc:creator>Matt Irby</dc:creator>
      <pubDate>Sun, 30 Jan 2022 18:36:10 +0000</pubDate>
      <link>https://dev.to/irby/making-gdb-easier-the-tui-interface-15l2</link>
      <guid>https://dev.to/irby/making-gdb-easier-the-tui-interface-15l2</guid>
      <description>&lt;h1&gt;
  
  
  Background
&lt;/h1&gt;

&lt;p&gt;I've recently started a new semester for my Master's program, and the first project for the semester involves using the &lt;a href="https://www.sourceware.org/gdb/" rel="noopener noreferrer"&gt;GDB tool (GNU Debugger)&lt;/a&gt; to analyze a stack on a simple C program that contains a buffer overflow vulnerability. A couple of semesters ago, I had been given a VM pre-loaded with a more featured debugger tool called &lt;a href="https://github.com/pwndbg/pwndbg" rel="noopener noreferrer"&gt;pwndbg&lt;/a&gt;. Pwndbg was excellent because it was easy to use and easily allowed accessed to information such as current assembly code being executed and a view of the program registers. So, going back to using GDB felt a little like stepping back into the stone age.&lt;/p&gt;

&lt;p&gt;For this project, one of the TAs recommended watching a video called &lt;a href="https://www.youtube.com/watch?app=desktop&amp;amp;v=PorfLSr3DDI" rel="noopener noreferrer"&gt;Give me 15 minutes &amp;amp; I'll change your view of GDB&lt;/a&gt;. In the video, the presenter, Greg Law, mentions that while GDB is easy to use, it is difficult to learn. He introduces a tool in GDB called TUI (Text User Interface). This tool allows the programmer to easily visualize the executing program, its assembly, and view the program registers (similar to what pwndbg offered). For reverse engineering and program forensics, these items are critical.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to Access TUI
&lt;/h1&gt;

&lt;p&gt;To access the TUI interface, first compile your C program with the gcc compiler and use the &lt;a href="https://dmalcolm.fedorapeople.org/gcc/2015-08-31/rst-experiment/options-for-debugging-your-program-or-gcc.html#cmdoption-g" rel="noopener noreferrer"&gt;&lt;code&gt;-g&lt;/code&gt; option&lt;/a&gt;. This option gives the GDB tool more information about your program. Then, run GDB on your compiled program and use &lt;code&gt;start&lt;/code&gt; to hit a breakpoint once the program enters the &lt;code&gt;main&lt;/code&gt; function.&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%2F2zww05poe7g0hpmiencw.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%2F2zww05poe7g0hpmiencw.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the program has started, to enable TUI mode you can either use &lt;code&gt;Ctrl+X+A&lt;/code&gt; or enter in &lt;code&gt;tui enable&lt;/code&gt; into GDB to enter TUI mode.&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%2Fvbyivaav8tiixodb4w4s.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%2Fvbyivaav8tiixodb4w4s.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once inside TUI mode, you can see the program's current point of execution marked in the line that's highlighted. In this case, my program is currently at line 7.  To see what assembly is currently being executed, type in &lt;code&gt;layout asm&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyivvhc6aomwc4640d1e6.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%2Fyivvhc6aomwc4640d1e6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To enable split screen, press &lt;code&gt;Ctrl+X&lt;/code&gt; then press 2.&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%2Fs37dd0z16fla69bfwy0u.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%2Fs37dd0z16fla69bfwy0u.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this split screen view enabled, I can use the &lt;code&gt;next&lt;/code&gt; command in GDB to step through the program's steps, see what assembly and line of the program is currently being executed.&lt;/p&gt;

&lt;p&gt;To see the program's registers, use the &lt;code&gt;layout reg&lt;/code&gt; command.&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%2F66mtjhrpaqgvsimzxjd6.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%2F66mtjhrpaqgvsimzxjd6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before TUI was enabled, pressing the up key would iterate through previous commands. However, with TUI enabled, pressing the up and down key scrolls through the assembly instructions. To iterate through previous instructions, use &lt;code&gt;Ctrl+P&lt;/code&gt;. If you would like to switch back to using the arrow keys for the command line, enter &lt;code&gt;focus cmd&lt;/code&gt; to switch focus to the command line. &lt;/p&gt;

&lt;p&gt;To exit TUI and go back to the GDB console interpreter, either use &lt;code&gt;Ctrl+X+A&lt;/code&gt; or type in &lt;code&gt;tui disable&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;As Greg Law mentions in &lt;a href="https://www.youtube.com/watch?app=desktop&amp;amp;v=PorfLSr3DDI" rel="noopener noreferrer"&gt;Give me 15 minutes &amp;amp; I'll change your view of GDB&lt;/a&gt;, while GDB is easy to use, it has a bit of a learning curve. Before I saw this video, I was not aware of the TUI interface and assumed that viewing register values would be much more cumbersome than it actually is. I recommend checking out &lt;a href="https://sourceware.org/gdb/onlinedocs/gdb/TUI-Commands.html" rel="noopener noreferrer"&gt;this list of TUI commands&lt;/a&gt; to get more familiar with the commands.&lt;/p&gt;

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

</description>
      <category>gdb</category>
      <category>assembly</category>
      <category>debugging</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Mocking Your Interfaces with Moq</title>
      <dc:creator>Matt Irby</dc:creator>
      <pubDate>Sat, 17 Jul 2021 05:45:49 +0000</pubDate>
      <link>https://dev.to/irby/mocking-your-interfaces-with-moq-339i</link>
      <guid>https://dev.to/irby/mocking-your-interfaces-with-moq-339i</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;An important aspect of unit testing is being able to test how your code handles responses from services. While dependency injection allows you to inject your services into your classes, you don't want your unit tests directly calling those  services, especially those making HTTP requests or database calls. &lt;/p&gt;

&lt;p&gt;To circumvent this, you want to be able to mock your services so you can simulate them returning responses without actually calling them. Fortunately, the Moq framework allows you to be able to do such a thing, and it's extremely easy to setup. In this lesson, we shall cover the Moq framework and how you can use it to simulate your services while unit testing.&lt;/p&gt;

&lt;h1&gt;
  
  
  Installation and Sample Code
&lt;/h1&gt;

&lt;p&gt;To install Moq, you can install it within your unit test project from the NuGet Package Manager or use the following command from the Package Manager Console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Install-Package Moq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, you are ready to start using Moq! Let's take an example of some code and how we can use Moq to our advantage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyProject&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// A class to denote students in a system&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Student&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&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;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;LastName&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;GradeAverage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// Enumeration to represent a grade a student may obtain&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Grade&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;F&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;/// A repository containing all the students in a system&lt;/span&gt;
    &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IStudentRepository&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;/// Returns a student by an ID value&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;param name="id"&amp;gt;Numeric ID value of student to pull&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;returns&amp;gt;If student with ID supplied exists in the repository, it return such a Student with Id. If no student in repository has such Id, it returns null.&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Student&lt;/span&gt; &lt;span class="nf"&gt;GetStudentById&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;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;/// Asynchronously returns all the students in the repository&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;returns&amp;gt;A list of students in the repository&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetStudentsAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StudentRepository&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IStudentRepository&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Student&lt;/span&gt; &lt;span class="nf"&gt;GetStudentById&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;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Make a DB call to get a student by ID&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NotImplementedException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetStudentsAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Make a DB call to get all student by ID&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NotImplementedException&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;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StudentService&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IStudentRepository&lt;/span&gt; &lt;span class="n"&gt;_repository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;StudentService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IStudentRepository&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_repository&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;/// Determines the grade value of a student based on their GradeAverage score.&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;param name="id"&amp;gt;An Id value of a student in the system&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;returns&amp;gt;Returns a Grade enumeration value of the student if student exists. If no student in the repository contains Id value provided, an Argument exception is thrown.&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Grade&lt;/span&gt; &lt;span class="nf"&gt;GetStudentGrade&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;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStudentById&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Could not find student with that ID."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;nameof&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GradeAverage&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;90&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;Grade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GradeAverage&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;80&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;Grade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GradeAverage&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;70&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;Grade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GradeAverage&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;60&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;Grade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Grade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;/// Asynchronously returns a list of students in order by their last name.&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;/// &amp;lt;returns&amp;gt;A list of students organized by their last name, ascending.&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetStudentsInAlphabeticalOrderAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;students&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;_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStudentsAsync&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;students&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastName&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&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;h1&gt;
  
  
  Testing the Synchronous Methods
&lt;/h1&gt;

&lt;p&gt;To verify the code of our StudentService class, we want to be able to write a unit test against it, but we don't want to depend on the StudentRepository class doing any work. Of course, in this example, none of the StudentRepository methods have been implemented, but assuming they have, we don't want our unit tests making any actual database calls. Therefore, we must mock responses for the IStudentRepository classes in our unit tests. But, with Moq, this isn't a problem.&lt;/p&gt;

&lt;p&gt;Consider the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyProject.Tests&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tests&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;StudentService&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SetUp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Setup&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="n"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ShouldCalculateStudentGradeCorrectly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Student&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="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;LastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;GradeAverage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;81.5&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockStudentService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IStudentRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class="n"&gt;mockStudentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStudentById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsAny&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;())).&lt;/span&gt;&lt;span class="nf"&gt;Returns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;_service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StudentService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockStudentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;grade&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStudentGrade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;123&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AreEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Grade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;grade&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;Within the &lt;code&gt;ShouldCalculateStudentGradeCorrectly&lt;/code&gt; method, we've created a &lt;code&gt;Student&lt;/code&gt; object to simulate our repository returning, and then in the next line we instantiate a Mock version of the &lt;code&gt;IStudentRepsitory&lt;/code&gt; interface called &lt;code&gt;mockStudentService&lt;/code&gt;, and then on &lt;code&gt;mockStudentService&lt;/code&gt; we setup the &lt;code&gt;GetStudentById&lt;/code&gt; method, with any integer provided, to return our &lt;code&gt;Student&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;It.IsAny&amp;lt;T&amp;gt;&lt;/code&gt; declared within the variable, the Moq framework tells our method that any value of type &lt;code&gt;T&lt;/code&gt; will return the &lt;code&gt;Student&lt;/code&gt; value. Therefore, we could provide the value 123 to the &lt;code&gt;GetStudentGrade&lt;/code&gt; method, and, no matter what, our &lt;code&gt;IStudentRepository&lt;/code&gt; interface would return the &lt;code&gt;Student&lt;/code&gt; value, whose Id is 1.&lt;/p&gt;

&lt;p&gt;With this configuration, we know the code will always return &lt;code&gt;Student&lt;/code&gt; with Id = 1 and GradeAverage = 81.5. Because 81.5 is less than 90.0, but greater than or equal to 80.0, we should expect our code to return a Grade enum of B. And, based on our unit test passing, this seems to be the case. &lt;/p&gt;

&lt;p&gt;We can be more specific with our inputs that using the generic &lt;code&gt;It.IsAny&amp;lt;int&amp;gt;&lt;/code&gt; with Moq. If we want to specify that, for only the integer 1, we want student with Id of 1 to come back from the service (as it would in an actual instance), we can do so. This will also allow our unit test to explore instances in which an Id that doesn't exist in our repository to be called, and we can therefore test edge cases. &lt;/p&gt;

&lt;p&gt;Let's consider the following piece of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyProject.Tests&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tests&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;StudentService&lt;/span&gt; &lt;span class="n"&gt;_service&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ShouldThrowExceptionIfStudentIdNotExist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;student&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Student&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="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;LastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;GradeAverage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;81.5&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockStudentService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IStudentRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class="n"&gt;mockStudentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStudentById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;Returns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;_service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StudentService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockStudentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Confirm that if we pass 1, we get our expected value&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;grade&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStudentGrade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AreEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Grade&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;grade&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// If we pass in a value not defined to Moq, its result will be treated as null.&lt;/span&gt;
            &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Throws&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ArgumentException&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStudentGrade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;123&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;In this scenario, we specify that if our &lt;code&gt;GetStudentById&lt;/code&gt; method on the &lt;code&gt;mockkStudentService&lt;/code&gt; service receives a parameter value of &lt;code&gt;1&lt;/code&gt;, it will return the &lt;code&gt;Student&lt;/code&gt; object whose Id = 1. And, we confirm that when we do pass the value of 1 to that method that we still get our &lt;code&gt;Grade.B&lt;/code&gt; result as expected. &lt;/p&gt;

&lt;p&gt;So, what happens if we try to pass in the &lt;code&gt;123&lt;/code&gt; value now as our parameter? Well, to our Moq framework, this value isn't yet defined. Therefore, when the &lt;code&gt;GetStudentById&lt;/code&gt; method is called with this input, a value of &lt;code&gt;null&lt;/code&gt; is returned. Thus, our unit test is able to explore the edge case scenario and hit the null-checking portion of the &lt;code&gt;GetStudentGrade&lt;/code&gt; method in the StudentService class, and we can verify that an ArgumentException is thrown when no student with such Id exists.&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing the Asynchronous Functions
&lt;/h1&gt;

&lt;p&gt;So far, we've looked at how we can test the synchronous functions within the Moq testing framework, but what about testing the asynchronous functions? Fortunately, we are still able to do so.&lt;/p&gt;

&lt;p&gt;Let's consider the following code in a unit test project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyProject.Tests&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tests&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;StudentService&lt;/span&gt; &lt;span class="n"&gt;_service&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ShouldSortStudentsInAlphabeticalOrder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;students&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Student&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="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Jacob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;LastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Jingleheimerschmidt"&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Student&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="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;LastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Appleseed"&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Student&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="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Zig"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;LastName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Zag"&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockStudentService&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IStudentRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class="n"&gt;mockStudentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStudentsAsync&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;Returns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

            &lt;span class="n"&gt;_service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StudentService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockStudentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStudentsInAlphabeticalOrderAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="c1"&gt;// Verify all 3 Student values are turned from the function&lt;/span&gt;
            &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AreEqual&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;Count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Verify the order of the last names is as expected (item 0 = Appleseed (Id = 2), item 1 = Jingleheimerschmidt (Id = 1), item 2 = Zag (Id = 3))&lt;/span&gt;
            &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AreEqual&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="m"&gt;0&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="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AreEqual&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="m"&gt;1&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="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AreEqual&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="m"&gt;2&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="m"&gt;3&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;If our asynchronous method &lt;code&gt;GetStudentsAsync&lt;/code&gt; required any parameters, we could still use the &lt;code&gt;It.IsAny&amp;lt;T&amp;gt;&lt;/code&gt; code and still supply it as generic parameters, but in this case no parameters are needed. Truly, the only important item to note is the &lt;code&gt;Task.FromResult()&lt;/code&gt; within the &lt;code&gt;Returns&lt;/code&gt; method of the &lt;code&gt;GetStudentsAsync&lt;/code&gt; method. For asynchronous functions, you can declare that your mocked values are the &lt;strong&gt;result of a task&lt;/strong&gt; and achieve the same result you would for mocking synchronous methods. &lt;/p&gt;

&lt;p&gt;If we run our unit test code, we see that the &lt;code&gt;GetStudentsInAlphabeticalOrderAsync&lt;/code&gt; does fetch all 3 &lt;code&gt;Student&lt;/code&gt; values available in the repository and does order the results according by the &lt;code&gt;Student&lt;/code&gt; last name, as we can tell by the ordering of the &lt;code&gt;Id&lt;/code&gt; values.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In this lesson, we can see how easy it is to setup a mock interface for a unit test to work with using the Moq framework, and we have explored how to mock up responses for both synchronous and asynchronous functions. With Moq, we can easily be able to simulate how our code can handle responses from dependencies without actually needing to call upon their concrete implementations.&lt;/p&gt;

&lt;p&gt;This lesson only provides a simple overview of Moq, but there's a lot more to Moq than just what we've covered. For example, it's good to take a look at &lt;a href="http://www.blackwasp.co.uk/MoqCallbacks.aspx" rel="noopener noreferrer"&gt;the callback functionality of Moq&lt;/a&gt; or just the &lt;a href="https://github.com/Moq/moq4/wiki/Quickstart" rel="noopener noreferrer"&gt;documentation from Moq's project page&lt;/a&gt;.&lt;/p&gt;

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

</description>
      <category>csharp</category>
      <category>testing</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Developing a Firebase Function Pt 2 - Environment Variables and HTTP Methods</title>
      <dc:creator>Matt Irby</dc:creator>
      <pubDate>Mon, 12 Jul 2021 00:46:25 +0000</pubDate>
      <link>https://dev.to/irby/developing-a-firebase-function-pt-2-environment-variables-and-http-methods-1pbf</link>
      <guid>https://dev.to/irby/developing-a-firebase-function-pt-2-environment-variables-and-http-methods-1pbf</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/irby/developing-a-firebase-function-1dgd"&gt;last article&lt;/a&gt;, I demonstrated how you can initialize a Firebase Functions project and how to deploy. In this lesson, I will explain how you can configure environment variables for your API and how to perform other HTTP methods such as PUT and POST.&lt;/p&gt;

&lt;h1&gt;
  
  
  Environment Variables
&lt;/h1&gt;

&lt;p&gt;It is generally good practice to make use of environment variables when developing an API, especially when you want to source control your API code but not expose sensitive information such as database credentials. Fortunately, Firebase Functions allow for an easy way to get and set environment variables for your function.&lt;/p&gt;

&lt;p&gt;To set an &lt;a href="https://firebase.google.com/docs/functions/config-env" rel="noopener noreferrer"&gt;environment variable&lt;/a&gt;, run the following code from your command line:&lt;/p&gt;

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

$ firebase functions:config:set [scope].[value]="something"


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

&lt;/div&gt;

&lt;p&gt;For example, if you wanted to assign a value of &lt;code&gt;hello&lt;/code&gt; to a variable called &lt;code&gt;myvariable&lt;/code&gt; in the scope of &lt;code&gt;test&lt;/code&gt;, run the following code:&lt;/p&gt;

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

$ firebase functions:config:set test.myvariable="hello"


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

&lt;/div&gt;

&lt;p&gt;To fetch the environment variables, run the following code&lt;/p&gt;

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

$ firebase functions:config:get


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

&lt;/div&gt;

&lt;p&gt;This will return a JSON object containing the environment variables for the project&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;"test"&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;"myvariable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hello"&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;One thing to note is that setting the environment variable from the command line can introduce some quirks. For instance, if we try to set the variable to "hello, world!" we get a weird error:&lt;/p&gt;

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

$ firebase functions:config:set test.myvariable="hello, world!"
bash: !": event not found


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

&lt;/div&gt;

&lt;p&gt;The reason for this error is that an exclamation mark character is &lt;a href="https://serverfault.com/questions/208265/what-is-bash-event-not-found" rel="noopener noreferrer"&gt;a special character to bash&lt;/a&gt;, so to get around this error we can substitute double quotes for single quotes&lt;/p&gt;

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

$ firebase functions:config:set test.myvariable='hello, world!'


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

&lt;/div&gt;

&lt;p&gt;Now let's use our environment variables within our code. Let's review our code we wrote in the previous lesson.&lt;/p&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="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create and Deploy Your First Cloud Functions&lt;/span&gt;
&lt;span class="c1"&gt;// https://firebase.google.com/docs/functions/write-firebase-functions&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;helloWorld&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onRequest&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello logs!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;structuredData&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello from Firebase!&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Within our response, let's return the &lt;code&gt;myvariable&lt;/code&gt; environment variable we've setup. To retrieve all the environment variables in our project, we can write &lt;code&gt;functions.config()&lt;/code&gt; within our code, and then we can access the environment variable by specifying the path to the variable. Since &lt;code&gt;myvariable&lt;/code&gt; is part of the &lt;code&gt;test&lt;/code&gt; scope, our code should look like this&lt;/p&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="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create and Deploy Your First Cloud Functions&lt;/span&gt;
&lt;span class="c1"&gt;// https://firebase.google.com/docs/functions/write-firebase-functions&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;helloWorld&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onRequest&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello logs!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;structuredData&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myvariable&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;Let's run the emulator and see if we can get this value when we view our function from the browser.&lt;/p&gt;

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

$ firebase emulators:start


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

&lt;/div&gt;

&lt;p&gt;However, when visiting the API endpoint for helloworld, the following error appears:&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%2Fjj46e511ptgn3zhyr1ws.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%2Fjj46e511ptgn3zhyr1ws.png" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reason for this error is that, although the environment variables are defined, the emulator is unable to retrieve the environment variables. In order for the emulator to retrieve the environment variables, a file containing a copy of the environment variables will need to be created. To do so, run the following script:&lt;/p&gt;

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

$ firebase functions:config:get &amp;gt; .runtimeconfig.json


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

&lt;/div&gt;

&lt;p&gt;This script will write the environment variables to a file called &lt;code&gt;.runtimeconfig.json&lt;/code&gt;. This is a file that the emulator is able to read from. Let's restart the emulator and see if we can read our environment variable now:&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%2F98uw1nj38yoaz7uxkwb0.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%2F98uw1nj38yoaz7uxkwb0.png" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that each time you add/update your environment variables, you will need to run the &lt;code&gt;firebase functions:config:get &amp;gt; .runtimeconfig.json&lt;/code&gt; script. In addition, once the emulator is started it caches the values within the runtimeconfig file, so you'll need to restart the emulator to have the new environment variables picked up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE: Because the .runtimeconfig.json file contains environment variables (and potentially sensitive information), we will want to make sure we ignore this file from version control, i.e. adding it to .gitignore&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This should cover the basics on getting environment variables configured and retrieved by the API. For some more information about environment variables, please consult &lt;a href="https://firebase.google.com/docs/functions/config-env" rel="noopener noreferrer"&gt;Firebase's documentation&lt;/a&gt;. For now, let's move onto how the API can support more HTTP methods besides just GET.&lt;/p&gt;

&lt;h1&gt;
  
  
  More HTTP Methods
&lt;/h1&gt;

&lt;p&gt;Currently, our application only supports a GET operation. How about support for more HTTP methods such as POST or PUT? Fortunately, Firebase Functions does allow support for this. To do so, you can use Express routers to specify the operations and have the &lt;code&gt;functions.https.onRequest()&lt;/code&gt; method accept the Express router configuration.&lt;/p&gt;

&lt;p&gt;Here is some sample code to illustrate this, borrowed from  &lt;a href="https://stackoverflow.com/questions/42995433/how-firebase-cloud-functions-handle-http-post-method" rel="noopener noreferrer"&gt;this StackOverflow post&lt;/a&gt;  &lt;/p&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="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Automatically allow cross-origin requests&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Defines my GET method at the helloWorld endpoint&lt;/span&gt;
&lt;span class="nx"&gt;app&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="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Here is my GET request!&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="c1"&gt;// Defines my POST method at the helloWorld endpoint and prints out an environment variable&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Here is my POST request! &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myvariable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Defines my PUT method at the helloWorld endpoint&lt;/span&gt;
&lt;span class="nx"&gt;app&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Here is my PUT request!&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="c1"&gt;// Expose Express API as a single Cloud Function&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;helloWorld&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&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 emulators running, when we visit the API endpoint for helloWorld in the brower, we see the 'Here is my GET request!' message.&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%2Fazyd1janbxnjgws2deun.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%2Fazyd1janbxnjgws2deun.png" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To test the POST endpoint, open up a command line tool and use CURL:&lt;/p&gt;

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

$ curl -X POST http://localhost:5001/irbytestproject/us-central1/helloWorld
Here is my POST request! hello, world!


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

&lt;/div&gt;

&lt;p&gt;Similarly, to test the PUT endpoint:&lt;/p&gt;

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

$ curl -X PUT http://localhost:5001/irbytestproject/us-central1/helloWorld
Here is my PUT request!


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

&lt;/div&gt;
&lt;h1&gt;
  
  
  Deploying our API
&lt;/h1&gt;

&lt;p&gt;Now that we have our environment variables configured and multiple HTTP methods supported, we are ready to deploy our function to Firebase. As a reminder from the first part of this lesson, the command to deploy our Firebase function:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ firebase deploy


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

&lt;/div&gt;

&lt;p&gt;Once the deployment has completed, we can use CURL to test our POST endpoint to ensure it gets the environment variable correctly:&lt;/p&gt;

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

$ curl -X POST https://us-central1-irbytestproject.cloudfunctions.net/helloWorld 
Here is my POST request! hello, world!


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

&lt;/div&gt;

&lt;p&gt;Excellent! Our API seems to be working as expected. &lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;For now, this should wrap up the basics on developing a Firebase function. If you are unfamiliar with Node.js or Express, I recommend &lt;a href="https://www.udemy.com/course/angular-2-and-nodejs-the-practical-guide/" rel="noopener noreferrer"&gt;checking out this course by Maximilian Schwarzmüller&lt;/a&gt; which goes over connecting a Node application to a MongoDB database, setting up API controllers, and more.&lt;/p&gt;

&lt;p&gt;Hope you've enjoyed the article!&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>googlecloud</category>
      <category>node</category>
    </item>
    <item>
      <title>Developing a Firebase Function Pt 1 - Initialize and Deploy</title>
      <dc:creator>Matt Irby</dc:creator>
      <pubDate>Sat, 10 Jul 2021 20:25:25 +0000</pubDate>
      <link>https://dev.to/irby/developing-a-firebase-function-1dgd</link>
      <guid>https://dev.to/irby/developing-a-firebase-function-1dgd</guid>
      <description>&lt;p&gt;Recently, I've been dabbling in Google Firebase due to its minimal overhead in getting started and relatively simple deployment pipeline. In particular, its support for NodeJS code and HTTPS makes it an ideal candidate for folks who are new to API development and looking for &lt;a href="https://firebase.google.com/pricing" rel="noopener noreferrer"&gt;a low-cost option&lt;/a&gt;. In this post, I wish to demonstrate from start to finish how to start a NodeJS API, be able to test it, and deploy it to production.&lt;/p&gt;

&lt;h1&gt;
  
  
  Installation and Initialization
&lt;/h1&gt;

&lt;p&gt;To get started, check to ensure you have the Firebase CLI installed on your computer. To install the Firebase CLI, please follow &lt;a href="https://firebase.google.com/docs/cli" rel="noopener noreferrer"&gt;these instructions&lt;/a&gt;. Once you are done, ensure you have installed Firebase version 8.6.0&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ firebase --version 
8.6.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you do not have version 8.6.0 installed, you can install this version globally using the following command with NPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install -g firebase@8.6.0
$ npm install -g firebase-tools@8.6.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NOTE: If you receive an EACCESS: permission denied error running the npm install commands, use &lt;code&gt;sudo npm install...&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;Now, head over to &lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt; and sign in. If you've never used Firebase before, all you need is to log into a Google account.&lt;/p&gt;

&lt;p&gt;Using the Firebase CLI, log into your Firebase account using a command line application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ firebase login

? Allow Firebase to collect CLI usage and error reporting information (Y/n): N
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will open a page in your browser to login to Firebase and grant permissions for the CLI to access your account. Once you've signed in, the CLI will have the credentials stored and you're ready to initialize your project.&lt;/p&gt;

&lt;p&gt;Create a new folder and visit this folder using your command line app. Then, use the script below to start the initialization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ firebase init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this command is entered, it will prompt you for which kind of project you want to create. For this tutorial, we will only be making a Functions project. Using the arrow keys, go down to Functions, hit space, and then hit enter. Next, you will be asked if you want to create a new project or use an existing project. Choose 'Create a new project', supply a unique project name (the initialization will fail if the name is already taken), and then choose a name to call your project (if left blank, it will default to the project name).&lt;/p&gt;

&lt;p&gt;Then, You will then be asked if you want to use JavaScript or TypeScript. We will use JavaScript for this project. Then, when asked if you want to use ESLint to catch probable bugs or enforce style, choose No. When asked if you want to install dependencies with npm, choose Yes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ firebase init

You're about to initialize a Firebase project in this directory:

  /Users/matt/Documents/test

? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices. Functions
: Configure and deploy Cloud Functions

=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add, 
but for now we'll just set up a default project.

? Please select an option: Create a new project
i  If you want to create a project in a Google Cloud organization or folder, please use "firebase projects:create" instead, and return to this command when you've created the project.
? Please specify a unique project id (warning: cannot be modified afterwa
rd) [6-30 characters]:
 irbytestproject
? What would you like to call your project? (defaults to your project ID)

✔ Creating Google Cloud Platform project
✔ Adding Firebase resources to Google Cloud Platform project

🎉🎉🎉 Your Firebase project is ready! 🎉🎉🎉

Project information:
   - Project ID: irbytestproject
   - Project Name: irbytestproject

Firebase console is available at
https://console.firebase.google.com/project/irbytestproject/overview
i  Using project irbytestproject (irbytestproject)

=== Functions Setup

A functions directory will be created in your project with a Node.js
package pre-configured. Functions can be deployed with firebase deploy.

? What language would you like to use to write Cloud Functions? JavaScript
? Do you want to use ESLint to catch probable bugs and enforce style? No
✔  Wrote functions/package.json
✔  Wrote functions/index.js
✔  Wrote functions/.gitignore
? Do you want to install dependencies with npm now? Yes

added 255 packages, and audited 256 packages in 5s

i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...
i  Writing gitignore file to .gitignore...

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

&lt;/div&gt;



&lt;p&gt;Inside of your project folder, you will now see a folder called &lt;code&gt;functions&lt;/code&gt;. If you check the package.json file within this folder, you should see something very similar to this:&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"functions"&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="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cloud Functions for Firebase"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&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;"serve"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"firebase emulators:start --only functions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"shell"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"firebase functions:shell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm run shell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"firebase deploy --only functions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"logs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"firebase functions:log"&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;"engines"&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;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10"&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;"dependencies"&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;"firebase-admin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.10.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;"firebase-functions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^3.6.1"&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;"devDependencies"&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;"firebase-functions-test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^0.2.0"&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;"private"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a couple of items to note. First, you will see commands such as &lt;code&gt;firebase emulators:start&lt;/code&gt; and &lt;code&gt;firebase deploy&lt;/code&gt;. Respectively, these commands will allow you to run your functions locally and deploy the functions. The &lt;code&gt;--only functions&lt;/code&gt; flag at the end of these commands specifies that you only want the functions folder to be deployed to Firebase.&lt;/p&gt;

&lt;h1&gt;
  
  
  Running your API locally
&lt;/h1&gt;

&lt;p&gt;Let's run our API and see it do some work. Run the following command to start your emulator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ firebase emulators:start

i  emulators: Starting emulators: functions
⚠  functions: The following emulators are not running, calls to these services from the Functions emulator will affect production: firestore, database, hosting, pubsub
⚠  Your requested "node" version "10" doesn't match your global version "12"
i  ui: Emulator UI logging to ui-debug.log
i  functions: Watching "/Users/matt/Documents/test/functions" for Cloud Functions...

┌───────────────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! View status and logs at http://localhost:4000 │
└───────────────────────────────────────────────────────────────────────┘

┌───────────┬────────────────┬─────────────────────────────────┐
│ Emulator  │ Host:Port      │ View in Emulator UI             │
├───────────┼────────────────┼─────────────────────────────────┤
│ Functions │ localhost:5001 │ http://localhost:4000/functions │
└───────────┴────────────────┴─────────────────────────────────┘
  Other reserved ports: 4400, 4500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, depending on how your emulator is configured, you may see a different value in your Host:Port box. In my instance, I have localhost:5001 set up as my function's host and port. When I visit &lt;a href="http://localhost:5001" rel="noopener noreferrer"&gt;http://localhost:5001&lt;/a&gt; in my browser, however, I get the following message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cannot GET /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this tells me is that my API is active, but the endpoint I'm trying to reach isn't available for GET. Let's look back at the project and see why this is the case.&lt;/p&gt;

&lt;p&gt;Within the functions folder, in addition to the package.json file there's another file called &lt;code&gt;index.js&lt;/code&gt;. The index.js file serves as the entry point of our API. When I open the index.js file, I see the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// // Create and Deploy Your First Cloud Functions&lt;/span&gt;
&lt;span class="c1"&gt;// // https://firebase.google.com/docs/functions/write-firebase-functions&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// exports.helloWorld = functions.https.onRequest((request, response) =&amp;gt; {&lt;/span&gt;
&lt;span class="c1"&gt;//   functions.logger.info("Hello logs!", {structuredData: true});&lt;/span&gt;
&lt;span class="c1"&gt;//   response.send("Hello from Firebase!");&lt;/span&gt;
&lt;span class="c1"&gt;// });&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;There are two things I notice. The first is, at the top, there's an import a firebase-functions package. The second thing I notice is that the code below it is commented out. &lt;/p&gt;

&lt;p&gt;The firebase-functions package is an SDK that provides you with access to Cloud Functions for Firebase. It allows you to access things such as environment variables (which we will look further into in the next post) and defining HTTP routes. &lt;/p&gt;

&lt;p&gt;In the commented out code, there's an command to export an endpoint called &lt;code&gt;helloWorld&lt;/code&gt;, and it's pointing to a functions command to route an HTTP request to a function which will log &lt;code&gt;Hello logs!&lt;/code&gt; and then send a response back saying &lt;code&gt;Hello from Firebase!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's un-comment this code and see what happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firebase-functions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create and Deploy Your First Cloud Functions&lt;/span&gt;
&lt;span class="c1"&gt;// https://firebase.google.com/docs/functions/write-firebase-functions&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;helloWorld&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onRequest&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello logs!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;structuredData&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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello from Firebase!&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the emulator is running, it will detect any saved changes made and will automatically reload the project. Checking my command line, I see the following message appear&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;functions[helloWorld]: http function initialized (http://localhost:5001/irbytestproject/us-central1/helloWorld).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I visit the URL in my browser, I get a plain HTML page that says 'Hello from Firebase!'. Neat! My API is working!&lt;/p&gt;

&lt;p&gt;Now let's check the Terminal to see if the log command is captured:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i  functions: Beginning execution of "helloWorld"
&amp;gt;  {"structuredData":true,"severity":"INFO","message":"Hello logs!"}
i  functions: Finished "helloWorld" in ~1s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we can see our API is working and logs are being captured, let's move onto deploying our API.&lt;/p&gt;

&lt;h1&gt;
  
  
  Deploying the API
&lt;/h1&gt;

&lt;p&gt;While it's not much (for now), we should be proud of the progress we've made. I think the world is ready to see our creation.&lt;/p&gt;

&lt;p&gt;Let's stop our emulator (either by using Ctrl+C or Cmd+C) and use the &lt;code&gt;firebase deploy&lt;/code&gt; command. Since we only have functions in our project, we don't need to worry about specifying the &lt;code&gt;--only functions&lt;/code&gt; flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ firebase deploy


=== Deploying to 'irbytestproject'...

i  deploying functions
i  functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i  functions: ensuring required API cloudbuild.googleapis.com is enabled...
✔  functions: required API cloudfunctions.googleapis.com is enabled
⚠  functions: missing required API cloudbuild.googleapis.com. Enabling now...

Error: HTTP Error: 400, Billing account for project [removed] is not found. Billing must be enabled for activation of service(s) 'cloudbuild.googleapis.com,containerregistry.googleapis.com' to proceed.
Help Token: ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks like we've run into an issue due to our project not being setup for billing yet. Not a problem. To fix this, let's go to our console by visiting &lt;a href="https://console.firebase.google.com/" rel="noopener noreferrer"&gt;https://console.firebase.google.com/&lt;/a&gt;, go into your project and click on Functions, and click on &lt;code&gt;Upgrade project&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Select the &lt;code&gt;Blaze - Pay as You Go&lt;/code&gt; option, enter in your billing information, and purchase.&lt;/p&gt;

&lt;p&gt;Once this is done, we are ready to run our deploy code again. Note that it may take a couple of minutes for your project upgrade to take effect, and then deploying may take several minutes especially if it's the first time deploying.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ firebase deploy

=== Deploying to 'irbytestproject'...

i  deploying functions
i  functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i  functions: ensuring required API cloudbuild.googleapis.com is enabled...
⚠  functions: missing required API cloudbuild.googleapis.com. Enabling now...
✔  functions: required API cloudfunctions.googleapis.com is enabled
✔  functions: required API cloudbuild.googleapis.com is enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (54.5 KB) for uploading
✔  functions: functions folder uploaded successfully
i  functions: creating Node.js 10 function helloWorld(us-central1)...
✔  functions[helloWorld(us-central1)]: Successful create operation. 
Function URL (helloWorld): https://us-central1-irbytestproject.cloudfunctions.net/helloWorld

✔  Deploy complete!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we check out our Firebase Functions page again, we can now see a Functions entry for helloWorld:&lt;/p&gt;

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

&lt;p&gt;Let's go test out our API! Copy the URL for your function and put it into your browser. You should see a plain HTML page that says &lt;code&gt;Hello from Firebase!&lt;/code&gt;&lt;/p&gt;

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

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We have walked through initializing our Firebase Functions project, running it locally, and deploying it to Firebase. In &lt;a href="https://dev.to/irby/developing-a-firebase-function-pt-2-environment-variables-and-http-methods-1pbf"&gt;my next article&lt;/a&gt;, I will walk through some more concepts such as creating environment variables and handling different types of HTTP methods such as POST, PUT, etc.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>googlecloud</category>
      <category>node</category>
    </item>
    <item>
      <title>Unit Testing with xUnit</title>
      <dc:creator>Matt Irby</dc:creator>
      <pubDate>Tue, 22 Dec 2020 18:08:37 +0000</pubDate>
      <link>https://dev.to/irby/unit-testing-with-xunit-e81</link>
      <guid>https://dev.to/irby/unit-testing-with-xunit-e81</guid>
      <description>&lt;p&gt;Before even writing a line of code, I always try to think of how I can unit test the classes and methods I'll write. Test-driven development at times may be tedious, but it is tremendously helpful in verifying your code works without running your program.&lt;/p&gt;

&lt;p&gt;In Visual Studio, there are several testing frameworks that are offered out of the box, including MSTest, NUnit and xUnit. Of the three frameworks, my personal preference is xUnit. There are several reasons why I prefer this framework:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test isolation is built into the design&lt;/li&gt;
&lt;li&gt;It offers parallelization by default&lt;/li&gt;
&lt;li&gt;Reduction of attributes cluttering your code&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Test Isolation
&lt;/h1&gt;

&lt;p&gt;When running tests, it's important that the context of each test be separate from each other. You wouldn't want to have the failure of one test to cause other tests to fail or to have the order in which tests are run play a role in a test's outcome. &lt;/p&gt;

&lt;p&gt;With the xUnit framework, tests are designed to be isolated much like the JUnit framework for Java. Each test is run on its own instance. Of course, if there is a need to have an object that's only created once, such as a database connection, fixtures can be used to share contexts in xUnit. But, as mentioned by &lt;a href="https://martinfowler.com/bliki/JunitNewInstance.html" rel="noopener noreferrer"&gt;this post&lt;/a&gt; cited by the creators of xUnit, the idea is to make it difficult to design tests in a way that may be problematic.&lt;/p&gt;

&lt;h1&gt;
  
  
  Parallelization
&lt;/h1&gt;

&lt;p&gt;One of the newer features xUnit has to offer is that it offers parallelization of unit tests by default. If xUnit detects multiple collections (classes) of unit tests within the same assembly, it will parallelize them to make best use of your computing capacity. For example, one project I've worked on can run around 100 unit tests in just 2.5 seconds. &lt;/p&gt;

&lt;p&gt;While MSTest and NUnit do offer parallelization, it's not a default behavior like it is in xUnit. For MSTest and NUnit, attributes are required to specify that parallelization to take place. If you believe you do not require parallelization for your project, xUnit does allow you to &lt;a href="https://xunit.net/docs/running-tests-in-parallel#parallelism-in-test-frameworks" rel="noopener noreferrer"&gt;disable this feature&lt;/a&gt; (see section &lt;code&gt;Changing Default Behavior&lt;/code&gt;) through the use of attributes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Reduction of Attributes
&lt;/h1&gt;

&lt;p&gt;One of the more subtle differences between xUnit and the MSTest and NUnit frameworks is the fewer number of attributes required to establish a test class. Under the xUnit framework, really the only attribute needed to setup a unit test is &lt;code&gt;[Fact]&lt;/code&gt; above the test method, and you're good to go. You can setup your tests from a constructor, there's no need for the &lt;code&gt;[TestInitialize]&lt;/code&gt; or &lt;code&gt;[SetUp]&lt;/code&gt; attributes to initialize a test as you would need in MSTest or NUnit. In addition, there's no need for an attribute to declare your test class is indeed a test class, xUnit infers test classes by the unit tests within.&lt;/p&gt;

&lt;p&gt;I enjoy the clean nature of xUnit. When I'm trying to write multiple test classes with multiple unit tests per class, having less code to write is a big win. I don't have to worry about trying to add in attributes to ensure my test runner can identify the test classes and its corresponding tests.&lt;/p&gt;

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

&lt;p&gt;While MSTest and NUnit are still great testing frameworks to work with, xUnit is my personal favorite among the bunch. It's incredibly performant, and the test isolation and clean nature of the framework gives me assurance that my unit tests are working as expected and easier to write and read.&lt;/p&gt;

&lt;h1&gt;
  
  
  Related Reading
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://dev.to/hatsrumandcode/net-core-2-why-xunit-and-not-nunit-or-mstest--aei"&gt;NET Core 2: Why xUnit and not NUnit or MSTest&lt;/a&gt; by Chris Mathurin&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;Banner - Peter Masełkowski - Unsplash.com&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>testing</category>
      <category>dotnet</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
