<?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: Harry</title>
    <description>The latest articles on DEV Community by Harry (@bendix).</description>
    <link>https://dev.to/bendix</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%2F177664%2F0c7dbbc2-f6d2-4be1-9b2d-df7445cbdb0c.png</url>
      <title>DEV Community: Harry</title>
      <link>https://dev.to/bendix</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bendix"/>
    <language>en</language>
    <item>
      <title>Best Practices for Fostering Collaboration with the Open-Source Community in 2024</title>
      <dc:creator>Harry</dc:creator>
      <pubDate>Fri, 31 May 2024 08:00:00 +0000</pubDate>
      <link>https://dev.to/bendix/best-practices-for-fostering-collaboration-with-the-open-source-community-in-2024-2pbh</link>
      <guid>https://dev.to/bendix/best-practices-for-fostering-collaboration-with-the-open-source-community-in-2024-2pbh</guid>
      <description>&lt;p&gt;&lt;a href="https://forward.digital/blog/best-practices-for-fostering-collaboration-with-the-open-source-community"&gt;&lt;em&gt;This post originally appeared on my blog&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open-source software (OSS) has become an integral part of modern software development, with many organisations relying on open-source components to build their products.&lt;/p&gt;

&lt;p&gt;However, using open-source software comes with its own set of challenges, such as security risks, licensing issues, and the need to contribute back to the community.&lt;/p&gt;

&lt;p&gt;In this post, we delve into effective practices for engaging with and contributing to the open-source community, enhancing both your projects and the broader ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Source Program Office
&lt;/h2&gt;

&lt;p&gt;An Open Source Program Office (OSPO) is a corporate entity that is responsible for managing an organisation’s open-source efforts. The OSPO is a “central nervous system” for open source within an organisation and provides governance, oversight, and support for all things related to open source (&lt;a href="https://www.linuxfoundation.org/research/a-deep-dive-into-open-source-program-offices"&gt;Haddad, 2022&lt;/a&gt;). It trains staff, promotes efficient software development with open-source parts, guides open-sourcing projects, ensures legal compliance, and builds community engagement.&lt;/p&gt;

&lt;p&gt;An OSPO helps bridge the gap between an organisation’s internal development and the external open-source community, helping to ensure that the organisation is a good steward of open-source software and can reap the benefits of open-source adoption, all the while minimising risks (&lt;a href="https://ospoglossary.todogroup.org/ospo-definition/"&gt;TODO Group, 2023&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Six common characteristics of successful open source programs (&lt;a href="https://opensource.com/business/16/5/whats-open-source-program-office"&gt;Walker, 2016&lt;/a&gt;) are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Value marketing and branding highly.&lt;/li&gt;
&lt;li&gt;Choose open-source communities that match your tech goals.&lt;/li&gt;
&lt;li&gt;Get good legal advice to balance risk and innovation.&lt;/li&gt;
&lt;li&gt;Your open-source efforts should support your product goals.&lt;/li&gt;
&lt;li&gt;Explain your support plans clearly to everyone involved.&lt;/li&gt;
&lt;li&gt;Hire someone passionate about open source to lead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Uber, for example, was motivated to create its own OSPO because of the need to streamline support for various open-source initiatives. For instance, there was a significant demand for advice on incorporating open-source technology into external products from engineers. Key concerns included navigating compliance, licensing, and related legal matters. Additionally, there was a crucial need to offer engineers direction on how to release Uber’s own software as open source, whether by initiating new projects or contributing to existing ones (&lt;a href="https://todogroup.org/resources/case-studies/uber/"&gt;Uber Case Study n.d.&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;“It was natural and organic for Uber to create an open source program office since it allowed us to build our platform and scale the technology at unprecedented speed […] in essence, Uber loves open source because it’s essential to our success.” (&lt;a href="https://todogroup.org/resources/case-studies/uber/"&gt;Hsieh, n.d.&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Since the OSPO is a relatively new concept, with Google opening one of the first OSPOs in 2004 (&lt;a href="https://opensource.google/about"&gt;Google, 2022&lt;/a&gt;), the literature references mostly large corporate entities with the resources to create an OSPO. The Linux Foundation recommends a minimum of five employees to start a successful OSPO (&lt;a href="https://www.linuxfoundation.org/research/a-deep-dive-into-open-source-program-offices"&gt;Haddad, 2022&lt;/a&gt;). Therefore, an OSPO is not best suited for smaller organisations that cannot afford to dedicate the resources to an OSPO.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Sourcing Previously Proprietary Software
&lt;/h2&gt;

&lt;p&gt;Open-sourcing previously proprietary software is the process of releasing software to the open-source community for free use and modification. This process can be beneficial for organisations; it allows for increased innovation, collaboration, and community engagement and can lead to the development of features that are beneficial to the organisation, as well as the resolution of issues that impact the organisation’s operations.&lt;/p&gt;

&lt;p&gt;There are a series of examples of organisations open-sourcing previously proprietary software. Some of the most notable examples include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Microsoft Open-sourcing .NET&lt;/strong&gt; By open-sourcing .NET, Microsoft allowed for a single, collaborative codebase across platforms rather than separate implementations. Ultimately, open development allows more community engagement to provide feedback and contributions, making the stack better for all (&lt;a href="https://devblogs.microsoft.com/dotnet/net-core-is-open-source/"&gt;Landwerth, 2014&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Microsoft Open-sourcing Powershell&lt;/strong&gt; Microsoft open-sourced PowerShell to make it more widely available and helpful for system administrators and developers who work with multiple operating systems. By making it open source and available cross-platform, more people can use PowerShell to automate tasks and manage their diverse computing environments that include different OSes (&lt;a href="https://www.zdnet.com/article/microsoft-open-sources-powershell-brings-it-to-linux-and-mac-os-x/"&gt;Foley, 2016&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NVIDIA Open-sourcing PhysX&lt;/strong&gt; NVIDIA open-sourced PhysX because physics simulation has “dovetails” with AI, robotics, and computer vision. NVIDIA considered physics simulation “foundational for so many things” and open-sourcing it would allow it to be developed and applied more widely than NVIDIA could do alone (&lt;a href="https://blogs.nvidia.com/blog/physx-high-fidelity-open-source/"&gt;Lebaredian, 2018&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Microsoft Open-sourcing Live Writer&lt;/strong&gt; Microsoft open-sourced Live Writer to allow the community to continue to develop and improve it, as Microsoft no longer had the resources to maintain it (&lt;a href="https://arstechnica.com/information-technology/2015/12/microsoft-open-sources-live-writer-beloved-but-abandoned-blogging-tool/"&gt;ARS STAFF, 2015&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The primary motivation for open-sourcing previously proprietary software is to allow for increased community engagement, feedback, and contributions, making the software better for all.&lt;/p&gt;

&lt;p&gt;However, open-sourcing previously proprietary software does have some technical considerations. For example, the software must be properly documented, the code must be clean and well-structured, and the software must be properly licensed. We saw from the interviews that these technical considerations are usually a deal-breaker and the reason why organisations do not open-source their software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hiring
&lt;/h2&gt;

&lt;p&gt;To reduce the risk of using OSS, organisations should hire internal staff to manage OSS. Develop in-house proficiency and aim to reduce reliance on external service providers by cultivating organisational expertise to oversee projects. This approach will enable quicker deployment of upgrades and enhancements (&lt;a href="https://materialplus.srijan.net/resources/blog/migrating-open-source-survival-guide-smes"&gt;Team Srijan, 2010&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Smaller organisations might not necessarily hire new personnel but rather delegate the responsibility to an existing staff member who is recognised as a subject-matter expert within the specific area (Interviewee 8, 2024). This approach is viable because, as noted, “In general, open source developers are experienced users of the software they write. They are intimately familiar with the features they need, and what the correct and desirable behavior is” (&lt;a href="https://dl.acm.org/doi/10.1145/337180.337209"&gt;Mockus et al., 2000&lt;/a&gt;). This innate understanding significantly mitigates one of the primary challenges in large software projects: the lack of domain knowledge. Consequently, smaller organisations can effectively rely on their in-house experts, capitalising on their comprehensive knowledge and experience.&lt;/p&gt;

&lt;p&gt;Hiring is a significant investment, and it is not always feasible for smaller organisations to hire new personnel to manage OSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Culture
&lt;/h2&gt;

&lt;p&gt;Open source has always been deeply rooted in culture, originating as a grassroots movement advocating for software freedom. Culture encompasses a broad spectrum, and individuals and organisations get involved in open source for various reasons.&lt;/p&gt;

&lt;p&gt;When inquiring about the cultural drivers behind companies’ engagement in open source, innovation emerged as the leading motivation, with 84% of respondents to Fintech Open Source Foundation State of Open Source Survey affirming it as a critical factor (&lt;a href="https://www.finos.org/reports/2021-state-of-open-source-in-financial-services"&gt;Ellison et al., 2021&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Uber instituted internal standards for governing and incentivising contributing upstream and back to the community to encourage ongoing, regular involvement in open-source projects. Contributing back to the open-source community is one of the best ways to help ensure open-source project sustainability (&lt;a href="https://todogroup.org/resources/case-studies/uber/"&gt;Uber Case Study n.d.&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;A big part of culture is fostering an environment where developers feel comfortable taking an unconventional route to solve a problem (&lt;a href="https://todogroup.org/resources/case-studies/autodesk/"&gt;Autodesk Case Study n.d.&lt;/a&gt;), and where they are encouraged to share code and collaborate with others (&lt;a href="https://todogroup.org/resources/case-studies/meta/"&gt;Abernathy, n.d.&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;An organisation’s culture is a significant factor in the adoption of open-source software, one that is quite hard to quantify and measure. There was very little mention of culture in the best practices we reviewed, and from our interviews, we found that there isn’t an “open-source” culture but rather a more collaborative and innovative culture that is conducive to using open-source software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contributions
&lt;/h2&gt;

&lt;p&gt;Active engagement in the open-source community offers substantial rewards. When you contribute to the projects your organisation utilises, you’re boosting its reputation and playing a significant role in steering the software’s development path. Such proactive participation can lead to the development of features that are beneficial to your organisation, as well as the resolution of issues that impact your operations.&lt;/p&gt;

&lt;p&gt;Contributing to the open-source ecosystem extends beyond just coding. Offering documentation, identifying bugs, and aiding in translations represent other crucial ways to contribute. Through these contributions, you help cultivate a mutually beneficial relationship with the community (&lt;a href="https://vaultinum.com/blog/managing-open-source-software-integration-in-software-development#best-practices-for-managing-open-source-software-integration"&gt;Yborra, 2024&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Contributing also helps keep the open-source component active and maintained. In recent years, a notable challenge has been the shortage of contributions or ongoing maintenance for projects, affecting even highly utilised packages like gorilla/mux, which have struggled to secure maintainers and consequently, had to archive their projects (&lt;a href="https://www.scaleway.com/en/blog/foss-giving-back/"&gt;Norblin, 2023&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Another way to contribute is through financial support. A recent survey by DigitalOcean found that only 20% of respondents had been paid for their contributions to open source, while 53% agreed or strongly agreed that individuals should be compensated for their work (&lt;a href="https://anchor.digitalocean.com/rs/113-DTN-266/images/DigitalOcean-Currents_June-2022.pdf"&gt;DigitalOcean, 2022&lt;/a&gt;). This suggests that there is room for improvement in financial support for open-source contributors (&lt;a href="https://tandochain.medium.com/the-importance-of-financial-support-for-open-source-software-bb486f32b145"&gt;Tandochain, 2023&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;More work is being done to support financial contributions to open source; notable examples include GitHub Sponsors and Open Source Collective, both offering platforms for financial support of open-source projects (&lt;a href="https://www.oscollective.org/"&gt;Open Source Collective 2024&lt;/a&gt;; &lt;a href="https://github.com/sponsors/explore"&gt;Explore GitHub Sponsors 2024&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Contributing to the open-source community is a best practice for managing the security risks associated with OSS. Most of the literature we reviewed mentioned contributing to the open-source community as a best practice. However, from our interviews, very few organisations contribute to the open-source community, and those that do do so in a limited capacity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting Events
&lt;/h2&gt;

&lt;p&gt;Hosting events is a great way to engage with the open-source community. Events can be an excellent way to engage with the open-source community, and they can take many forms, from hackathons to conferences to meet-ups.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=6UMCe5o0KBw"&gt;Schumacher, 2022&lt;/a&gt;, went as far as to say that corporate organisations looking to lead in open source should host events, as they are a great way to engage with the community and build relationships.&lt;/p&gt;

&lt;p&gt;However, our interviews found that hosting events is not widely used in practice and that the best practices landscape does not reflect the real-world use of hosting events. Companies do send their employees to events, but larger organisations typically host events, as smaller organisations do not have the resources to host events.&lt;/p&gt;

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

&lt;p&gt;In conclusion, fostering collaboration with the open-source community is essential for organisations that rely on open-source software. By engaging with the community, contributing back to the community, and hosting events, organisations can enhance their projects and the broader ecosystem.&lt;/p&gt;

&lt;p&gt;However, there are challenges to fostering collaboration with the open-source community, such as the need to hire internal staff to manage OSS, the technical considerations of open-sourcing previously proprietary software, and the cultural challenges of adopting open-source software.&lt;/p&gt;

&lt;p&gt;Despite these challenges, the benefits of fostering collaboration with the open-source community are significant. By following best practices for engaging with and contributing to the open-source community, organisations can enhance their projects and the broader ecosystem, ultimately leading to better software for all.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>Best Practices for Managing the Security Risks Associated with Open-Source Software in 2024</title>
      <dc:creator>Harry</dc:creator>
      <pubDate>Fri, 24 May 2024 08:00:00 +0000</pubDate>
      <link>https://dev.to/bendix/best-practices-for-managing-the-security-risks-associated-with-open-source-software-in-2024-4ji3</link>
      <guid>https://dev.to/bendix/best-practices-for-managing-the-security-risks-associated-with-open-source-software-in-2024-4ji3</guid>
      <description>&lt;p&gt;&lt;a href="https://forward.digital/blog/best-practices-for-managing-the-security-risks-associated-with-open-source-software"&gt;&lt;em&gt;This post originally appeared on my blog&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Welcome to this four-part mini-series on open-source best practices. In this series, we will discuss the best practices for adopting open-source software (OSS) into your organisation, managing OSS dependencies daily, fostering collaboration with the OSS community, and finally, my opinion on which best practices are best adopted for organisations of all sizes and industries.&lt;/p&gt;

&lt;p&gt;This article will discuss the best practices for managing open-source software, including the internal considerations organisations must make, the metrics to judge the quality of OSS components, the approval process, and the licensing of OSS components.&lt;/p&gt;

&lt;p&gt;Open source software (OSS) is a critical component of modern software development. It allows developers to leverage existing code, reduce development time, and focus on building new features.&lt;/p&gt;

&lt;p&gt;However, OSS also introduces security risks. Vulnerabilities in OSS components can expose organisations to cyber threats, data breaches, and financial losses. To mitigate these risks, organisations must adopt best practices for managing the security risks associated with OSS.&lt;/p&gt;

&lt;p&gt;In this blog post, we explore best practices for managing the security risks associated with OSS.&lt;/p&gt;

&lt;p&gt;We review the literature, conduct interviews with industry experts, and analyse case studies to identify key strategies for securing OSS components. Our research highlights the importance of regular vulnerability assessments, tooling, continuous monitoring, binary repositories, risk management and mitigation, static application security testing, and forking as essential practices for managing the security risks associated with OSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regular vulnerability assessments
&lt;/h2&gt;

&lt;p&gt;Regular vulnerability assessments identify, prioritise, and apply patches to systems and software to address vulnerabilities. As the OSS landscape constantly evolves, organisations encounter thousands of new vulnerabilities. Yet, many businesses do not have a robust patch management strategy in place and fail to implement critical patches promptly, leaving them vulnerable to security breaches (&lt;a href="https://www.hackerone.com/knowledge-center/what-vulnerability-assessment-benefits-tools-and-process"&gt;Hackerone, 2024&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;With an estimated 84% of open source components having at least one vulnerability (&lt;a href="https://venturebeat.com/2021/04/13/synopsys-84-of-codebases-contain-an-open-source-vulnerability/"&gt;Sawers, 2021&lt;/a&gt;), regular vulnerability assessments are essential for managing the security risks associated with OSS.&lt;/p&gt;

&lt;p&gt;A rough overview of the process is as follows (&lt;a href="https://www.hackerone.com/knowledge-center/what-vulnerability-assessment-benefits-tools-and-process"&gt;Hackerone, 2024&lt;/a&gt;):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initial Preparation&lt;/strong&gt; – Defining the scope and goals of the vulnerability testing to ensure a targeted and practical assessment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vulnerability Testing&lt;/strong&gt; – Running automated tests to identify vulnerabilities within the systems included in the predefined scope.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prioritise Vulnerabilities&lt;/strong&gt; – Assessing which vulnerabilities are most critical, requiring immediate attention, and evaluating their potential business impact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create Vulnerability Assessment Report&lt;/strong&gt; – Produce a detailed report outlining medium and high-priority vulnerabilities found and recommended remediation strategies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous Vulnerability Assessment&lt;/strong&gt; – Conducting scans for vulnerabilities on a continuous basis to verify if previous vulnerabilities have been effectively remediated and to discover new ones.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Regular vulnerability assessments are frequently mentioned in the best practices for managing the security risks associated with OSS. Without automated vulnerability assessments, it is difficult to keep up with the large number of OSS components used in modern software systems and the many vulnerabilities discovered each year. Therefore, with automation, regular vulnerability assessments are a best practice for managing the security risks associated with OSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tooling
&lt;/h2&gt;

&lt;p&gt;Tooling is the functionality that allows for automating the management of OSS components. It can be very useful as a way to manage the large number of OSS components used in modern software systems without introducing unnecessary manual work. Any software project that actively works to reduce security vulnerabilities is less risky. Therefore, tools that aid in identifying security vulnerabilities within software projects are critical (&lt;a href="https://dodcio.defense.gov/Portals/0/Documents/Library/SoftwareDev-OpenSource.pdf"&gt;Department of Defense, 2022&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;There are three tools found from our literature review that are considered “leaders”; Snyk, Sonatype, and Synopsys (Black Duck) (&lt;a href="https://www.forrester.com/report/the-forrester-wave-tm-software-composition-analysis-q2-2023/RES178483"&gt;Worthington et al., 2023&lt;/a&gt;). These tools are designed to help organisations manage the security risks associated with OSS. They can be used to automate vulnerability assessments, manage licensing, enforce an OSS policy, and generate SBOMs. With this in mind, due to the diversity of OSS components, there is no one-size-fits-all solution (&lt;a href="https://ieeexplore.ieee.org/document/9073010"&gt;Wen et al., 2019&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We consider tooling to be a best practice for managing the security risks associated with OSS. It enables organisations of all sizes to manage many OSS components used in modern software systems without introducing unnecessary manual work. There is a lot of research into tooling, and a wide range of tools are available. We found that many tool-promoting papers and articles are written by the companies that produce the tools, so it is down to the organisation to evaluate the tools and decide which one is best for them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous monitoring
&lt;/h2&gt;

&lt;p&gt;Modern software applications are built using a complex web of dependencies, including open-source libraries and frameworks. This process is typically recursive, with each dependency having its dependencies, and so on (&lt;a href="https://arxiv.org/pdf/2306.05534.pdf"&gt;Dietrich et al., 2023&lt;/a&gt;). Infamously, this web of dependencies can lead to security vulnerabilities, as seen in the equifax data breach (&lt;a href="https://www.csoonline.com/article/567833/equifax-data-breach-faq-what-happened-who-was-affected-what-was-the-impact.html"&gt;Fruhlinger, 2020&lt;/a&gt;) and the log4j vulnerability (&lt;a href="https://builtin.com/cybersecurity/log4j-vulerability-explained"&gt;Gallo, 2022&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Continuous monitoring is the process of monitoring OSS components for vulnerabilities and other security risks on an ongoing basis. These can be manual but are often automated and part of an organisation’s CI/CD pipeline. It is crucial for application developers to detect dependencies on vulnerable libraries as soon as possible, to assess their impact precisely, and to mitigate any potential risk (&lt;a href="https://dl.acm.org/doi/10.1007/s10664-020-09830-x"&gt;Ponta et al., 2020&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Now more than ever, developers are using automation to secure their dependencies; in 2023, developers merged 60% more pull requests from GitHub’s Dependabot, a tool that automates dependency updates, than in 2022 (&lt;a href="https://github.blog/2023-11-08-the-state-of-open-source-and-ai/"&gt;Daigle, 2023&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Software composition analysis (SCA) can be used to conduct regular vulnerability assessments, can be implemented as part of the continuous integration/continuous deployment (CI/CD) pipeline, and can be used to enforce an OSS policy (&lt;a href="https://www.crowdstrike.com/cybersecurity-101/secops/software-bill-of-materials-sbom/"&gt;Alvarenga, 2023a&lt;/a&gt;). SCAs will provide an inventory of all open-source components used in a project, including their versions and licenses, and will also identify any known vulnerabilities in these components; effectively, producing an SBOM (&lt;a href="https://www.crowdstrike.com/cybersecurity-101/secops/software-bill-of-materials-sbom/"&gt;Alvarenga, 2023a&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Due to the dynamic nature of the open-source ecosystem, continuous monitoring is essential for managing the security risks associated with OSS. An SCA is a great way to monitor OSS components continuously and can be implemented as part of the CI/CD pipeline and can be used to enforce an OSS policy. It is a best practice for managing the security risks associated with OSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Binary repositories
&lt;/h2&gt;

&lt;p&gt;A binary repository manager is a tool designed to store and manage binary files (the compiled version of your source code) and their metadata. Some popular binary repository managers include JFrog Artifactory, Sonatype Nexus Repository, and GitHub Packages.&lt;/p&gt;

&lt;p&gt;A binary repository manager is indispensable for managing open-source components effectively. It facilitates the caching of local copies of these elements, ensuring that frequently used packages remain accessible even during downtimes of external repositories. This capability is essential for maintaining continuous project development and operations without interruptions.&lt;/p&gt;

&lt;p&gt;Moreover, such a tool distinguishes between approved third-party artefacts and those pending approval, significantly improving the management and visibility of open-source components within projects. It also allows access to specific libraries to be excluded and limited, thereby safeguarding projects from incorporating non-compliant artefacts (&lt;a href="https://www.altexsoft.com/blog/5-best-practices-for-managing-open-source-components/"&gt;Wainstein, 2018&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;By caching versions of all open-source software components, you also safeguard against incidents like the left-pad debacle, where the withdrawal of a minor package from the npm package manager (a package manager for the JavaScript programming language) resulted in widespread failure in numerous projects (&lt;a href="https://www.theregister.com/2016/03/23/npm_left_pad_chaos/"&gt;Williams, 2016&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;There is a licensing concern, specifically with GPL-licensed open-source software. The GPL license requires that any software distributed that includes or is derived from GPL-licensed code must itself be available under the GPL. If a binary repository contains GPL software and is shared externally, the entire repository may need to be open-sourced. For example, Microsoft released Hyper-V drivers with GPL-licensed binaries, leading to Microsoft having to open-source the drivers in question (&lt;a href="https://linux-network-plumber.blogspot.com/2009/07/congratulations-microsoft.html"&gt;Linux Network Plumber, 2009&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Binary repositories appear to be a polarising issue in the literature. The &lt;a href="https://dodcio.defense.gov/Portals/0/Documents/Library/SoftwareDev-OpenSource.pdf"&gt;Department of Defense, 2022&lt;/a&gt; recommended binary repositories as a best practice for managing the security risks associated with OSS, whereas &lt;a href="https://security.salesforce.com/blog/seven-best-practices-to-secure-your-open-source-components"&gt;Anand, 2023&lt;/a&gt; (Salesforce) mentioned securing a repository as a best practice, but didn’t mention binary repositories specifically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Risk management and mitigation
&lt;/h2&gt;

&lt;p&gt;Risk management and mitigation is the process of identifying, assessing, and prioritising risks, and then taking steps to reduce or eliminate them.&lt;/p&gt;

&lt;p&gt;According to the Open Worldwide Application Security Project (OWASP), the most significant risk associated with open source software is “Vulnerable and Outdated Components” and has moved from 9th to the 6th most critical risk to web applications (&lt;a href="https://owasp.org/www-project-top-ten/"&gt;OWASP, 2020&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;OSS vulnerabilities grew by 50% year-on-year — from just over 4,000 in 2018 to over 6,000 in 2019 (&lt;a href="https://www.helpnetsecurity.com/2020/03/13/open-source-vulnerabilities-2019/"&gt;Zorz, 2020&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;One reason for the increase in vulnerabilities is the growing number of open source components being used in software projects from developers utilising the speed and convenience of open source, especially under time pressure, without considering the security implications. This highlights the need for formal processes to manage the risks. Typically, these correlated to implementing some continuous monitoring and regular vulnerability assessments, as outlined in Section 4.2.1 and 4.2.3 (&lt;a href="https://security.salesforce.com/blog/seven-best-practices-to-secure-your-open-source-components"&gt;Anand, 2023&lt;/a&gt;, &lt;a href="https://www.mayerbrown.com/en/insights/publications/2022/10/the-importance-of-tracking-and-managing-the-use-of-open-source-software}"&gt;Chandler et al., 2022&lt;/a&gt;, &lt;a href="https://cobalt.io/blog/risks-of-open-source-software"&gt;Mathpati, 2023&lt;/a&gt;). Such efforts should avoid being overly laborious and manual to ensure they do not frustrate developers and slow down the development process (&lt;a href="https://www.contrastsecurity.com/hubfs/Understanding-the-Risks_WhitePaper_042020_Final.pdf?hsLang=en"&gt;Contrast Security, 2020&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Like those outlined in this report, the most effective way to mitigate OSS risks is to follow best practices (&lt;a href="https://www.mayerbrown.com/en/insights/publications/2022/10/the-importance-of-tracking-and-managing-the-use-of-open-source-software}"&gt;Chandler et al., 2022&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Interestingly, our interviews and case studies found that the approach to risk and risk mitigation varied from organisation to organisation. Larger organisations seemed more proactive in mitigating risk, with dedicated teams and processes in place. Whereas smaller organisations were more reactive, only taking action when a risk materialised and looking to improve their processes after the event. This suggests there is a gap in the best practices landscape, as it doesn’t consider the different approaches to risk management and mitigation based on the size of the organisation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static application security testing
&lt;/h2&gt;

&lt;p&gt;Static application security testing (SAST) is a method of testing the security of an application by examining its source code, byte code, or binary code for security vulnerabilities.&lt;/p&gt;

&lt;p&gt;Frequent scanning and security assessment of your repository aids in detecting security concerns at early stages, minimising the chance of significant security problems developing later on. Static code analysis tools can pinpoint typical security weaknesses, and dependency vulnerability scanners can highlight any recognised problems in your project’s dependencies (&lt;a href="https://security.salesforce.com/blog/seven-best-practices-to-secure-your-open-source-components"&gt;Anand, 2023&lt;/a&gt;). SAST goes hand in hand with the continuous monitoring of OSS components, as it allows for detecting vulnerabilities in OSS components as soon as possible, allowing for their impact to be assessed and mitigated, see Section 4.2.3.&lt;/p&gt;

&lt;p&gt;From our research, SAST is only suggested by Salesforce as a best practice. However, current tooling is comprehensive and can be used to automate the continuous monitoring of OSS components, as outlined in Section 4.2.2. Therefore, SAST can be considered a technical implementation of continuous monitoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Forking
&lt;/h2&gt;

&lt;p&gt;Forking is the process of creating a new project based on an existing project. It allows you to monitor alterations in open-source components, as there will always be a connection to the original repository. One of the key advantages mentioned in the definition of open-source is the explicit permission granted to duplicate and independently alter the source code of an open-source project as desired (&lt;a href="https://opensource.org/osd"&gt;The Open Source Definition 2024&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;However, it’s important to be mindful that opting to create a private fork entails the responsibility of integrating any updates from the upstream version of the component. This responsibility grows as the differences between the forked components and the original increase. An ideal situation for forking is when you take an open-source component from a project that is unlikely to receive many updates in the future (&lt;a href="https://www.altexsoft.com/blog/5-best-practices-for-managing-open-source-components/"&gt;Wainstein, 2018&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The process often includes creating a distinct OSS developer community (OSS-DC) for the forked version, allowing the organisation to focus on modifying or enhancing specific components of the software—usually those deemed critical for their purposes (&lt;a href="https://www.scitepress.org/Papers/2021/104970/104970.pdf"&gt;Méndez-Tapia et al., 2021&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Forking does get mentioned in varying mediums as a best practice. However, the added responsibility of integrating updates from the upstream version of the component is often overlooked, and from our interviews, we found that forking is not widely used in practice.&lt;/p&gt;

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

&lt;p&gt;In this blog post, we explored best practices for managing the security risks associated with open-source software. We reviewed the literature, conducted interviews with industry experts, and analysed case studies to identify key strategies for securing OSS components.&lt;/p&gt;

&lt;p&gt;Our research highlights the importance of regular vulnerability assessments, tooling, continuous monitoring, binary repositories, risk management and mitigation, static application security testing, and forking as essential practices for managing the security risks associated with OSS.&lt;/p&gt;

&lt;p&gt;By adopting these best practices, organisations can reduce the likelihood of security breaches, data loss, and financial losses associated with OSS vulnerabilities. We recommend that organisations implement these practices to enhance the security of their software systems and protect their data and assets.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>Best Practices for Adopting Open-Source Software in 2024</title>
      <dc:creator>Harry</dc:creator>
      <pubDate>Fri, 17 May 2024 08:00:00 +0000</pubDate>
      <link>https://dev.to/bendix/best-practices-for-adopting-open-source-software-in-2024-3mkn</link>
      <guid>https://dev.to/bendix/best-practices-for-adopting-open-source-software-in-2024-3mkn</guid>
      <description>&lt;p&gt;&lt;a href="https://forward.digital/blog/best-practices-for-adopting-open-source-software"&gt;&lt;em&gt;This post originally appeared on my blog&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Welcome to this four-part mini-series on open-source best practices. In this series, we will discuss the best practices for adopting open-source software (OSS) into your organisation, managing OSS dependencies daily, fostering collaboration with the OSS community, and finally, my opinion on which best practices are best adopted for organisations of all sizes and industries.&lt;/p&gt;

&lt;p&gt;The second and third parts are already readily available on my website &lt;a href="https://forward.digital/blog"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article will discuss the best practices for adopting open-source software, including the internal considerations organisations must make, the metrics to judge the quality of OSS components, the approval process, and the licensing of OSS components.&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Open-source adoption includes the strategic and tactical considerations of introducing open-source software to your organisation. A robust adoption process is critical to ensuring new open-source components are correctly evaluated before being integrated into the organisation’s systems.&lt;/p&gt;

&lt;p&gt;This article lists all the general best practices for adopting OSS. It is by no means an opinion piece. &lt;/p&gt;

&lt;h1&gt;
  
  
  OSS Policy
&lt;/h1&gt;

&lt;p&gt;An OSS policy is a formal document that outlines the rules and guidelines for using open-source software within an organisation.&lt;/p&gt;

&lt;p&gt;Our literature review found an OSS policy to be a recurring theme in the best practices for adopting open-source software. Best practices recommend that organisations have a formal OSS policy in place.&lt;/p&gt;

&lt;p&gt;An OSS policy should (&lt;a href="https://www.eclipse.org/org/foundation/membersminutes/20090326StrategySummit/OSS-WYPAUT3_JeffreyH.pdf"&gt;Hammond, 2009&lt;/a&gt;);&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be concise&lt;/li&gt;
&lt;li&gt;Developer consumable&lt;/li&gt;
&lt;li&gt;Involve general counsel early and often&lt;/li&gt;
&lt;li&gt;Classify OSS license types&lt;/li&gt;
&lt;li&gt;Take control of the process&lt;/li&gt;
&lt;li&gt;Measure internalisation&lt;/li&gt;
&lt;li&gt;Be revisited and revised on a regular basis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should include the goals for OSS adoption, the acquisition process, the rules for the business case, and guidelines for the appropriate use of OSS (&lt;a href="https://www.eclipse.org/org/foundation/membersminutes/20090326StrategySummit/OSS-WYPAUT3_JeffreyH.pdf"&gt;Hammond, 2009&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Lacking a formal policy for OSS usage and adoption, which typically includes licencing guidelines, can lead to legal and security risks (&lt;a href="https://www.theguardian.com/technology/blog/2008/dec/12/cisco-fsf-opensource"&gt;Schofield, 2008&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;However, a policy alone is not enough. It is essential to ensure that all employees understand and follow the policy. Most importantly, the policy steps should apply to the organisational context (&lt;a href="https://www.linuxfoundation.org/the-european-public-sector-open-source-opportunity"&gt;Osborne et al., 2023&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Open-source policies are a formal way for an organisation to set guidance and rules for using open-source software. As we will see later, most developers use their own discretion rather than a formal organisational process, which can lead to inconsistencies and licensing risks.&lt;/p&gt;

&lt;p&gt;A policy is an excellent way for an organisation to ensure that all developers are following the same process, the correct stakeholders are included in the adoption process, and that the process is tailored to the organisation’s needs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Maturity Models
&lt;/h1&gt;

&lt;p&gt;Maturity models are a way to evaluate the quality of open-source software components. They can play a key role in the adoption process, as they allow for evaluating OSS components before they are integrated into the organisation’s systems. We found that there are several maturity models for evaluating OSS components; however, there wasn’t a consensus on which model was the best.&lt;/p&gt;

&lt;p&gt;Fundamentally, the adoption of OSS components differs from the adoption of proprietary software due to the fact OSS is stored in public repositories, accessible by anyone, and is often developed by a community of developers (&lt;a href="https://www.researchgate.net/publication/318339374_Comparison_of_Open_Source_Maturity_Models"&gt;Umm-e-Laila et al., 2016&lt;/a&gt;). Due to this, the quality of open-source software can be very different from one product to another; therefore, evaluation methods have been developed to evaluate OSS components properly.&lt;/p&gt;

&lt;p&gt;The most popular OSS evaluation methods are the Capgemini-Open Source Maturity Model (C-OSSM), Navicasoft-Open Source Maturity Model (N-OSSM), Qualification and Selection of Open Source (QSOS), Open Business Readiness Rating (Open BRR) and Easiest Open Source (E-OSS) (&lt;a href="https://www.researchgate.net/publication/318339374_Comparison_of_Open_Source_Maturity_Models"&gt;Umm-e-Laila et al., 2016&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;None of those interviewed were familiar with these models, let alone using them in their organisation. This suggests that these models are not widely used in practice. We also found, from our literature review, that there is no consensus on which model is the best, with &lt;a href="https://www.researchgate.net/publication/318339374_Comparison_of_Open_Source_Maturity_Models"&gt;Umm-e-Laila et al., 2016&lt;/a&gt; going as far as to say that “in order to take advantage of OSS properly, it is recommended to propose a new framework/model that will eliminate the weakness of all models.”.&lt;/p&gt;

&lt;p&gt;We can conclude that while maturity models are an excellent way to evaluate OSS components, there is no consensus on which model is the best, and they are not widely used in practice. From our interviews, we found that most developers judge the maturity of OSS components based on their own discretion, usually stemming from their own experiences and the experiences of their colleagues.&lt;/p&gt;

&lt;h1&gt;
  
  
  Trust in Open-Source Software
&lt;/h1&gt;

&lt;p&gt;Trust in OSS is a critical concept when adopting OSS components. How does one come to trust an OSS component? More often than not, “there is no sound basis for trust in the Software Ecosystems (SECO) hubs”, with trust being considered “founded or unfounded” (&lt;a href="https://www.researchgate.net/publication/365699098_A_systematic_literature_review_on_trust_in_the_software_ecosystem"&gt;Hou et al., 2022&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Trust is subjective and based on the end-developer’s perception and intrinsic and extrinsic motivations. When adopting a new OSS component, the developer will consider intrinsic factors such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source code&lt;/li&gt;
&lt;li&gt;Reliability&lt;/li&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Extrinsic factors such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;li&gt;Structural assistance&lt;/li&gt;
&lt;li&gt;Cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quality is the most discussed factor in trustworthiness, with most developers considering the quality of the OSS component as the most critical factor in trustworthiness (&lt;a href="https://www.researchgate.net/publication/365699098_A_systematic_literature_review_on_trust_in_the_software_ecosystem"&gt;Hou et al., 2022&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;From our literature review and the interviews, we found that each developer uses their own trust model and that there is no documented process for evaluating the trustworthiness of OSS components within an organisation.&lt;/p&gt;

&lt;p&gt;Outside of academic papers, trustworthiness wasn’t mentioned in any of the best practices we reviewed.&lt;/p&gt;

&lt;p&gt;This is a significant gap in the best practices landscape, as trust plays a vital role in adopting OSS components.&lt;/p&gt;

&lt;h1&gt;
  
  
  Approval process
&lt;/h1&gt;

&lt;p&gt;The approval process is a formal process for evaluating and approving OSS components before they are integrated into the organisation’s systems. It’s an opportunity for the organisation to evaluate the OSS component and ensure that it meets the organisation’s needs and standards, and engage relevant stakeholders in the approval process.&lt;/p&gt;

&lt;p&gt;When adopting OSS, there are several “deal-breakers” that can prevent the adoption of an OSS component. Outlined by &lt;a href="https://ieeexplore.ieee.org/document/8909944/authors"&gt;Spinellis, 2019&lt;/a&gt;, these include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Lacking functionality&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Incompatible license&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nonfunctional properties&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Businesses should approve OSS based on technical needs, licensing, longevity, and business factors like cost and benefits. Yet, businesses must balance risk with commercial advantages and be willing to adapt their methods quickly. The approval process should be formal, with a clear set of guidelines and rules, and should be managed by a central team and engage relevant stakeholders (&lt;a href="https://www.sciencedirect.com/science/article/pii/S0164121221002442#b37"&gt;Butler et al., 2022&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;When selecting an OSS component, ensure it demonstrates the following security and maintenance best practices (&lt;a href="https://dodcio.defense.gov/Portals/0/Documents/Library/SoftwareDev-OpenSource.pdf"&gt;Department of Defense, 2022&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Detection Tool Usage:&lt;/strong&gt; Actively employs detection tools within its integration pipeline and externally.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vulnerability Reporting Transparency:&lt;/strong&gt; Has a clear process for the open reporting and documentation of security vulnerabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security Review History:&lt;/strong&gt; Possesses a record of security reviews.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cybersecurity Testing:&lt;/strong&gt; Undergoes regular cybersecurity assessments, notably third-party audits, to verify security measures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Issue Resolution:&lt;/strong&gt; Demonstrates a commitment to promptly addressing and resolving reported issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Timely Vulnerability Remediation:&lt;/strong&gt; Shows a track record of quickly remedying vulnerabilities.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We found that an approval process was a recurring theme in the best practices for adopting open-source software. Every interviewee demonstrated some approval process for the adoption of OSS components. Smaller companies tended to build a minimal viable product (MVP) with the OSS in question; larger teams had a multistep process that involved multiple stakeholders.&lt;/p&gt;

&lt;p&gt;The US &lt;a href="https://dodcio.defense.gov/Portals/0/Documents/Library/SoftwareDev-OpenSource.pdf"&gt;Department of Defense, 2022&lt;/a&gt; recommendations primarily emphasise the quantifiable attributes of OSS dependencies, including security features and measurable performance metrics. In contrast, &lt;a href="https://www.sciencedirect.com/science/article/pii/S0164121221002442#b37"&gt;Butler et al., 2022&lt;/a&gt; analysis portrays the approval process as somewhat ambiguous, describing it as more reliant on assessment and discretion than on strict, predefined criteria.&lt;/p&gt;

&lt;p&gt;To conclude, the approval process for adopting open-source software is dynamic and customised to each organisation’s specific requirements, yet it remains a universally acknowledged standard that all entities conform to.&lt;/p&gt;

&lt;h1&gt;
  
  
  Software Bill of Materials
&lt;/h1&gt;

&lt;p&gt;Software Bill of Materials (SBOM) is a formal list of components used in a software system. It allows for tracking OSS components and their dependencies, which is essential for managing the security and compliance risks associated with OSS.&lt;/p&gt;

&lt;p&gt;Since 2018, SBOMs have surged in popularity, driven in part by a collaborative effort headed up by the American National Telecommunications and Information Administration’s (NTIA) multi-stakeholder process (&lt;a href="http://ntia.gov/SBOM"&gt;National Telecommunications and Information Administration, n.d.&lt;/a&gt;). This work culminated in the US government’s issuance of an executive order mandating the use of SBOMs in all federal software (&lt;a href="https://www.whitehouse.gov/briefing-room/presidential-actions/2021/05/12/executive-order-on-improving-the-nations-cybersecurity/"&gt;The White House, n.d.&lt;/a&gt;) in direct response to the SolarWinds supply chain attack (&lt;a href="https://www.cybersecuritydive.com/news/solarwinds-1-year-later-cyber-attack-orion/610990/"&gt;Schwartz, 2021&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The two primary standards for SBOM are SPDX and CycloneDX.&lt;/p&gt;

&lt;p&gt;SPDX17 is an open standard developed by the Linux Foundation to communicate details of a SBOM, including components, licenses, copyrights, and security references, recognised internationally as ISO/IEC 5962:202118 (&lt;a href="https://spdx.dev"&gt;System Package Data Exchange (SPDX®) 2024&lt;/a&gt;). CycloneDX19, originating from the Open Web Application Security Project (OWASP) community, is an SBOM standard crafted for application security and supply chain component analysis, now extended to encompass a broader array of applications such as software-as-a-service BOM (SaaSBOM) (&lt;a href="https://cyclonedx.org/"&gt;CycloneDX 2024&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Both formats are popular, yet organisations are advised to select the format that most aptly meets their specific requirements (&lt;a href="https://www.crowdstrike.com/cybersecurity-101/secops/software-bill-of-materials-sbom/"&gt;Alvarenga, 2023a&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;At a minimum, an SBOM must contain three categories (&lt;a href="https://www.ntia.gov/blog/ntia-releases-minimum-elements-software-bill-materials"&gt;United States Department of Commerce, 2021&lt;/a&gt;);&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data fields&lt;/strong&gt; Data fields must be standardised and contain essential information on each component for effective tracking and management. The aim is to ensure these components can be easily identified throughout the software supply chain, linking them to other valuable data sources (&lt;a href="https://www.ntia.gov/blog/ntia-releases-minimum-elements-software-bill-materials"&gt;United States Department of Commerce, 2021&lt;/a&gt;). Naming conventions should try and follow the guidance outlined by &lt;a href="https://www.ntia.gov/files/ntia/publications/ntia_sbom_framing_2nd_edition_20211021.pdf"&gt;NTIA Multistakeholder Process on Software Component Transparency Framing Working Group, 2021&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automation Support&lt;/strong&gt; Automation support is essential for the effective use of SBOMs, as it allows for the automatic generation and updating of SBOMs, which is essential for managing the large number of OSS components used in modern software systems.&lt;/p&gt;

&lt;p&gt;The data formats that are being used to generate and consume SBOMs are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Software Package Data eXchange (SPDX)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CycloneDX13&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Software Identification (SWID) tags&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Practices and Processes&lt;/strong&gt; Practices and processes are essential for the effective use of SBOMs, as they allow for the effective management of OSS components and their dependencies, necessary for managing the security and compliance risks associated with OSS.&lt;/p&gt;

&lt;p&gt;There are two elements that should be explicitly stated in the SBOM:&lt;/p&gt;

&lt;p&gt;Frequency – When a software component is updated or new information about its components is discovered, the supplier must issue an updated SBOM to reflect these changes (&lt;a href="https://www.ntia.gov/blog/ntia-releases-minimum-elements-software-bill-materials"&gt;United States Department of Commerce, 2021&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Depth – An SBOM must include all primary components and their transitive dependencies, ensuring top-level dependencies are detailed enough to identify all subsequent dependencies recursively (&lt;a href="https://www.ntia.gov/blog/ntia-releases-minimum-elements-software-bill-materials"&gt;United States Department of Commerce, 2021&lt;/a&gt;).&lt;/p&gt;

&lt;h1&gt;
  
  
  Licencing
&lt;/h1&gt;

&lt;p&gt;The licensing of OSS components is a crucial consideration when adopting OSS as it can significantly impact the organisation’s ability to use the OSS component and considerably affect the organisation’s ability to distribute the software that uses the OSS component.&lt;/p&gt;

&lt;p&gt;As of 2022, 78% of open source components are under permissive licenses, which allow users wide freedom to use, modify, and distribute the software, with minimal requirements on how it can be redistributed. Meanwhile, copyleft licenses, which require that any modified versions of the software also be distributed under the same license terms, make up the remaining 22% of open source components (&lt;a href="https://www.mend.io/blog/open-source-licenses-in-2022-trends-and-predictions/"&gt;Murray, 2022&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The Apache License is the most popular OSS license, with 30% of all OSS projects using it (&lt;a href="https://www.mend.io/blog/open-source-licenses-in-2022-trends-and-predictions/"&gt;Murray, 2022&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Larger organisations (&amp;gt;5000 employees) are more likely to have an internal legal team familiar with OSS licensing when compared to small organisations (100 employees) 31.46% vs 22.30%, respectively (&lt;a href="https://www.openlogic.com/resources/2023-state-open-source-report"&gt;OpenLogic, 2023&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;To help reduce the risk of legal problems arising with the use of open-source software (&lt;a href="https://cobalt.io/blog/risks-of-open-source-software"&gt;Mathpati, 2023&lt;/a&gt;), organisations should watch over all open-source code being brought into the organisation, ensuring that licence requirements are met. To achieve this, there are several tools available, such as (&lt;a href="https://www.linuxfoundation.org/tools-for-managing-open-source-programs/"&gt;The Linux Foundation, 2024&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Black Duck Protex&lt;/strong&gt; – A fee-based tool for license compliance and open source management.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Copyright review tools&lt;/strong&gt; – Command line utilities for copyright file management.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;FOSSA&lt;/strong&gt; – Automates code dependency tracking and license compliance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;FOSSology&lt;/strong&gt; – An open-source toolkit from the Linux Foundation for license compliance featuring a web UI for compliance workflows.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Managing the licensing of OSS components is a key consideration when adopting OSS. Large organisations often have the advantage of an internal legal team to navigate open-source software (OSS) licensing, a resource that smaller organisations lack. Therefore, relying on internal legal teams for OSS license management cannot be deemed a universally applicable best practice, as it disadvantages smaller entities. The easiest way to manage your OSS licensing is to use a tool that can automatically track and manage the licensing of OSS components, as outlined by &lt;a href="https://www.linuxfoundation.org/tools-for-managing-open-source-programs/"&gt;The Linux Foundation, 2024&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;In this article, we have discussed the best practices for adopting open-source software, including the internal considerations organisations must make, the metrics by which to judge the quality of OSS components, the approval process, and the licensing of OSS components.&lt;/p&gt;

&lt;p&gt;The adoption of open-source software is a complex process that requires careful consideration of the organisation’s needs and the OSS components being adopted. Having a robust adoption process is critical to ensuring that new open-source components are correctly evaluated before being integrated into the organisation’s systems.&lt;/p&gt;

&lt;p&gt;We can see that the current literature is broad and extensive, with many different opinions on the best practices for adopting open-source software. However, there are some recurring themes, such as the need for an OSS policy, the importance of an approval process, and the need to manage the licensing of OSS components.&lt;/p&gt;

&lt;p&gt;We hope that this article has provided you with some valuable insights into the best practices for adopting open-source software and that you can use this information to improve your organisation’s OSS adoption process.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Implementing Sign in with Apple with Expo</title>
      <dc:creator>Harry</dc:creator>
      <pubDate>Fri, 18 Jun 2021 14:17:40 +0000</pubDate>
      <link>https://dev.to/bendix/implementing-sign-in-with-apple-with-a-managed-expo-workflow-and-a-nest-js-backend-8ja</link>
      <guid>https://dev.to/bendix/implementing-sign-in-with-apple-with-a-managed-expo-workflow-and-a-nest-js-backend-8ja</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://forwardigital.co.uk/blog/implementing-Sign-in-with-Apple-with-a-managed-Expo-workflow" rel="noopener noreferrer"&gt;This post originally appeared on Forward Digital's blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Making your whole authentication process as seamless a possible is vital to ensuring that any potential users don't get put off by filling out a long-winded create account form.&lt;/p&gt;

&lt;p&gt;Back in WWDC 2019 Apple introduced Sign in with Apple, this allows users to authenticate with their Apple Id with forced 2FA. A seamless solution to getting users into your app.&lt;/p&gt;

&lt;p&gt;Today I will be running through the steps to integrate this into your managed Expo project using a Nest.js backend to authenticate that user and handle the user accounts.   &lt;/p&gt;

&lt;p&gt;Before we begin I will make the assumption the reader is familiar with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expo&lt;/li&gt;
&lt;li&gt;Nest.js&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although the backend code will be using Nest, a lot of the code will be transferrable to any other Node backend framework you may be using. &lt;/p&gt;

&lt;h2&gt;
  
  
  What do we need?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Expo
&lt;/h3&gt;

&lt;p&gt;For our managed Expo project, we will need to add: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;"expo-apple-authentication"&lt;/code&gt; by running: &lt;code&gt;expo install expo-apple-authentication&lt;/code&gt; which will install the version compatible with your SDK version. This tutorial is written for &lt;strong&gt;SDK41&lt;/strong&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;There are extra configuration steps you need to follow that can be found here: &lt;a href="https://docs.expo.io/versions/latest/sdk/apple-authentication/#configuration" rel="noopener noreferrer"&gt;https://docs.expo.io/versions/latest/sdk/apple-authentication/#configuration&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;

&lt;p&gt;For our Nest.js backend we need to add:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/auth0/node-jsonwebtoken" rel="noopener noreferrer"&gt;https://github.com/auth0/node-jsonwebtoken&lt;/a&gt; (&lt;code&gt;npm install jsonwebtoken&lt;/code&gt;)

&lt;ul&gt;
&lt;li&gt;We use this to verify the JWT token was signed by Apple's public key&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/auth0/node-jwks-rsa" rel="noopener noreferrer"&gt;https://github.com/auth0/node-jwks-rsa&lt;/a&gt; (&lt;code&gt;npm install jwks-rsa&lt;/code&gt;)

&lt;ul&gt;
&lt;li&gt;We use this to retrieve the signing keys from Apple's keys API endpoint and to retrieve Apple's public key&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/auth0/jwt-decode" rel="noopener noreferrer"&gt;https://github.com/auth0/jwt-decode&lt;/a&gt; (&lt;code&gt;npm install jwt-decode&lt;/code&gt;)

&lt;ul&gt;
&lt;li&gt;We use this to decode the JWT generated by the Sign in with Apple button&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A brief overview of the auth flow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A user presses the Sign in with Apple button and logins in through the native Apple modal&lt;/li&gt;
&lt;li&gt;Once authorised through 2FA on the device, will return to us a JWT token with a nullable name value. (plus other values, we don't need to worry about these)&lt;/li&gt;
&lt;li&gt;Determine if the user is attempting to log in or create an account&lt;/li&gt;
&lt;li&gt;We send the JWT token off to our backend with the user's name (if they are creating an account)&lt;/li&gt;
&lt;li&gt;We then decode the JWT token, get Apple's public key and verify the JWT token was signed by Apple &lt;/li&gt;
&lt;li&gt;Validate the token against our bundle id&lt;/li&gt;
&lt;li&gt;At this point, we can safely assume they are authenticated with Apple and we can either login them in through our backend auth or create an account on our database using the values we have from step 2. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  An overview of the Expo package
&lt;/h2&gt;

&lt;p&gt;Expo's &lt;code&gt;expo-apple-authenticator&lt;/code&gt; is in effect a one-stop-shop with everything you need for your app. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Sign-in with Apple button will only appear on iOS devices, so make sure to consider this when building the UI.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The package contains the functions for displaying the modal and even comes bundled with the button itself, although this isn't required if you want to use a custom button.&lt;/p&gt;

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

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AppleAuthenticationButton&lt;/span&gt;
    &lt;span class="na"&gt;buttonType&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthenticationButtonType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CONTINUE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;buttonStyle&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthenticationButtonStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BLACK&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;BUTTON_BORDER_RADIUS&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BUTTON_WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BUTTON_HEIGHT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;onPress&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;There's also plenty of style options so the button fits in line with other buttons on the app. &lt;code&gt;BUTTON_BORDER_RADIUS&lt;/code&gt;, &lt;code&gt;BUTTON_WIDTH&lt;/code&gt; and  &lt;code&gt;BUTTON_HEIGHT&lt;/code&gt; are custom values I declared for all buttons on the app. &lt;/p&gt;

&lt;p&gt;When a user presses the Sign in with Apple button they will be presented with a native modal that sits on top of your app, with module fields dependent on the scope you requested.&lt;/p&gt;

&lt;p&gt;You have access to two scopes: &lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;credential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signInAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;requestedScopes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthenticationScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FULL_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthenticationScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EMAIL&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;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd33wubrfki0l68.cloudfront.net%2F59ac2da39902a203391f624c4fa1d93cea0c187f%2F0676c%2Fimages%2Fsiwa-scopes.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%2Fd33wubrfki0l68.cloudfront.net%2F59ac2da39902a203391f624c4fa1d93cea0c187f%2F0676c%2Fimages%2Fsiwa-scopes.png" alt="https://d33wubrfki0l68.cloudfront.net/59ac2da39902a203391f624c4fa1d93cea0c187f/0676c/images/siwa-scopes.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the user doesn't cancel the modal, the response will look something like:&lt;/p&gt;

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

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AppleAuthenticationCredential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppleAuthenticationFullName&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;realUserStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppleAuthenticationUserDetectionStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;identityToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;authorizationCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We only really care about 4 fields that get returned: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;user&lt;/code&gt; - this is a stable unique identifier that will persist between app versions/device changes for the app.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fullName&lt;/code&gt; - The user's name object, includes family name, given name, nickname etc.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;email&lt;/code&gt; - The user's email, used for the backend to create a user account&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;identityToken&lt;/code&gt; - A JWT token that stores information about the audience, issuer and user.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Email and name access
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Be warned!&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;fullName&lt;/code&gt; will only be populated &lt;strong&gt;ONCE.&lt;/strong&gt; The first time they press the button, this applies even if they change their device or update the app. A user's email is still available in the JWT token, but once &lt;code&gt;fullName&lt;/code&gt; gets pulled down the first time, &lt;strong&gt;you can never request it again and subsequent requests will return null.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the user creating an account or logging in?
&lt;/h3&gt;

&lt;p&gt;As this button will act as both a create account button and a login button, how do we determine which the user is trying to do?&lt;/p&gt;

&lt;p&gt;As mentioned above we know the first time they press the button, email and name values will be populated. If the name and email values are undefined, it is a fair assumption this is the users first time on the app and they are trying to create an account.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is the problem with this? If the user signs in through the button, pulls down the name and email values but, say, the device crashes/the subsequent API call fails or they kill the app; they can't create an account through the Sign up with Apple button.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One mitigation of this is to cache the name value to the phone's storage if it is populated and so if any edge-case happens that causes the device to lose the name then we can fall back to the cache. &lt;/p&gt;

&lt;p&gt;Save the name value to the cache with the key value of the &lt;code&gt;credential.user&lt;/code&gt; as we know this is a stable unique identifier.&lt;/p&gt;

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

&lt;span class="c1"&gt;// Expo Apple button&lt;/span&gt;
&lt;span class="nx"&gt;onPress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppleAuthenticationCredential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signInAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;requestedScopes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthenticationScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FULL_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthenticationScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EMAIL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;cachedName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAppleLoginName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;detailsArePopulated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;givenName&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;detailsArePopulated&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cachedName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identityToken&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;detailsArePopulated&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;cachedName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cachedName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identityToken&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;await&lt;/span&gt; &lt;span class="nf"&gt;createAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;givenName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identityToken&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ERR_CANCELED&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="nf"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Continue was cancelled.&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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;You can see in the above code snippet we are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Requesting the user's email and name&lt;/li&gt;
&lt;li&gt;Retrieving the name value stored in the cache (if any)&lt;/li&gt;
&lt;li&gt;If both the cache and credential values are undefined, we are assuming they have already used the button successfully to create an account, so start the login flow&lt;/li&gt;
&lt;li&gt;If the cached name is declared but the credential details are not, we are assuming something happened between requesting the values from Apple and the server creating them an account, so create an account using the cached name&lt;/li&gt;
&lt;li&gt;Otherwise, create an account with the requested values that are populated.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;This is not bulletproof! If the user requests the details but the cache gets cleared/they change devices before creating an account, they will not be able to create an account using this flow. We hedged a bet that this was edge case enough to warrant the risk.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Decoding and validating the JWT token
&lt;/h2&gt;

&lt;p&gt;If the user is creating an account or logging in, we need to handle decoding and validating the JWT token sent in the payload to our Nest.js API. &lt;/p&gt;

&lt;p&gt;Using Nest.js we need to create two new endpoints to handle creating an account and logging in. Both these endpoints I will add a respective guard to. It's in this guard that we call the Apple auth strategy code. &lt;/p&gt;

&lt;p&gt;From experience, I couldn't use the existing login and create account endpoints as these require the information we receive &lt;em&gt;after&lt;/em&gt; decoding and validating the token, not once the request is made on the device. &lt;/p&gt;

&lt;p&gt;Login guard:&lt;/p&gt;

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

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExecutionContext&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;switchToHttp&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getRequest&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;switchToHttp&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;request.body.identityToken;
    const jwt: JwtTokenSchema = await this.apple.ValidateTokenAndDecode(token);

    try &lt;span class="si"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;IUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AttemptLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;user&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&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;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Auth-Token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sessionId&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;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Expose-Headers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Auth-Token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="si"&gt;}&lt;/span&gt; catch (error) &lt;span class="si"&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="nc"&gt;HttpException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Validation failed for login. &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HttpStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UNAUTHORIZED&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="si"&gt;}&lt;/span&gt;

    return false;
} 


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

&lt;/div&gt;

&lt;p&gt;The most important line is: &lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JwtTokenSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apple&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ValidateTokenAndDecode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;As we are injecting calling the Apple strategy to do most of the logic. The logic is as follows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Apple's public key
&lt;/h3&gt;

&lt;p&gt;Before we use the JWT token, we need to make sure that it was signed by Apple's private key. To do that, we need Apple's public key to verify the signature.&lt;/p&gt;

&lt;p&gt;Firstly we need to decode the JWT token sent by the client and extract the &lt;code&gt;kid&lt;/code&gt; value found in the token's header.&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;jwtDecode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JwtHeader&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jwt-decode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// rest of file &lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenDecodedHeader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JwtHeader&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;kid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwtDecode&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;JwtHeader&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;kid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;header&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="p"&gt;});&lt;/span&gt;


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

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;The "kid" (key ID) Header Parameter is a hint indicating which key was used to secure the JWS. This parameter allows originators to explicitly signal a change of key to recipients. The structure of the "kid" value is unspecified. Its value MUST be a case-sensitive string. Use of this Header Parameter is OPTIONAL.&lt;br&gt;
When used with a JWK, the "kid" value is used to match a JWK "kid" parameter value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then we need to perform an HTTP request to Apple's &lt;code&gt;auth/keys&lt;/code&gt; public endpoint to return an object which contains an array of keys. Read more about this &lt;a href="https://www.notion.so/Implementing-Sign-in-with-Apple-with-a-managed-Expo-workflow-ec737b58a2064049b4f8860cfc189117" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;applePublicKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;string&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="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&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;https://appleid.apple.com/auth/keys&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;(&lt;code&gt;this.api.Get&lt;/code&gt; is a HTTP client we built for Nest, find out more here)&lt;/p&gt;

&lt;p&gt;This endpoint will return a JSON Web Key Set which will look like:&lt;/p&gt;

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

&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keys&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;kty&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RSA&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;kid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AIDOPK1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sig&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RS256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lxrwmuYSAsTfn....&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;e&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AQAB&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;//&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;As the keys array typically has more than one element, we need to filter the &lt;code&gt;keys&lt;/code&gt; array to the one that has a matching &lt;code&gt;kid&lt;/code&gt; value from the decoded header of the JWT token. &lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tokenDecodedHeader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kid&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;sharedKid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;applePublicKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;kid&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now we need to get Apple's public key using the &lt;code&gt;kid&lt;/code&gt; value. To do this we use the package mentioned above: &lt;code&gt;jwks-rsa&lt;/code&gt;.&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jwksClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JwksClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;jwksClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;jwksUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://appleid.apple.com/auth/keys&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jwksClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CertSigningKey&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;jwksClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RsaSigningKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSigningKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sharedKid&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;signingKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPublicKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;If all is dandy, we should now have Apple's public key that we can use to verify our JWT token was signed with the same key. Thanks to &lt;code&gt;jsonwebtoken&lt;/code&gt;:&lt;/p&gt;

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

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JwtTokenSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;JwtTokenSchema&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;jwt.verify(token, signingKey);
} catch (error) &lt;span class="si"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// token is invalid&lt;/span&gt;
&lt;span class="si"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;I wrote my own &lt;code&gt;JwtTokenSchema&lt;/code&gt; for type safety:&lt;/p&gt;

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

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;JwtTokenSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;iss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;aud&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;iat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;c_hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;email_verified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;is_private_email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;auth_time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now we have the decoded JWT token we just need to perform some basic validation before we proceed with the rest of the auth process. &lt;/p&gt;

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

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;ValidateToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JwtTokenSchema&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iss&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://appleid.apple.com&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="k"&gt;throw&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Issuers do not match!&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aud&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audience&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Audiences do not match!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;this.audience&lt;/code&gt; is your app's bundle ID. This will change depending on if you are on Expo or in production. I do a ternary in the class' constructor to set this:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;audience&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isInProd&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;co.repetitio.repetitio&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;host.exp.Exponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// this will be your bundle id, found in app.json&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now we should have the decoded token that we have validated against Apple's public key and can safely assume that the user is whom they say they are and are trying to login into the correct app. The full class is linked at the bottom.&lt;/p&gt;

&lt;p&gt;From here you are free to proceed to the log in process or create them an account. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Forward-Digital/Sign-up-with-Apple-Nestjs" rel="noopener noreferrer"&gt;I have uploaded the code to a public repo so you can take a deeper look here.&lt;/a&gt;&lt;/p&gt;

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

</description>
      <category>reactnative</category>
      <category>expo</category>
      <category>apple</category>
      <category>nestjs</category>
    </item>
    <item>
      <title>When to use TailwindCSS over CSS</title>
      <dc:creator>Harry</dc:creator>
      <pubDate>Tue, 15 Jun 2021 15:04:00 +0000</pubDate>
      <link>https://dev.to/bendix/when-to-use-tailwindcss-over-css-4iaa</link>
      <guid>https://dev.to/bendix/when-to-use-tailwindcss-over-css-4iaa</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://forwardigital.co.uk/blog/when-to-use-tailwindcss-over-css"&gt;This post originally was shared @ Forward Digital&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I find the premise of &lt;a href="https://tailwindcss.com/"&gt;TailwindCSS&lt;/a&gt; exciting, an un-opinionated CSS framework that has an extensive list of utility classes by which to build UIs. &lt;/p&gt;

&lt;p&gt;Coming from a background of using Bootstrap 3 quite heavily before we collectively decided as an industry that Bootstrap is past it (we did do that right? I can't keep up), there was plenty to complain about; their use of &lt;code&gt;!important&lt;/code&gt; would keep me up at night, &lt;a href="https://jquery.com/"&gt;jQuery&lt;/a&gt; was great - in 2008, among others. &lt;/p&gt;

&lt;p&gt;In their defence, they also did a lot right. The Bootstrap grid system is still fantastic, the modal is equally great and ultimately they made building consistent and functional UIs a breeze. For that alone, I'll always be grateful.   &lt;/p&gt;

&lt;p&gt;There has been an appetite for something &lt;em&gt;more&lt;/em&gt; in recent memory. Something a bit, simpler? I think Tailwind (or rather the creators) realised people were looking for something just like Tailwind, so they made it.&lt;/p&gt;

&lt;p&gt;There are whole swathes of developers out there who believe CSS is black magic and anyone that is remotely fluent in it is this all-powerful style-sheet, colour, whitespace, Shoreditch coffee drinking genius. When someone comes to me with a CSS issue they have spent "the last few days trying to solve" and I did it in one line (&lt;code&gt;position: relative&lt;/code&gt; folks) from then on I was considered a sorcerer of black magic. &lt;/p&gt;

&lt;p&gt;These whole swathes of developers are pre-dominantly backend developers and trust me guys CSS is a bizarre bit of kit, the main difference is exposure (as with most things), so I'm not gunning at ya. I sympathies with never really knowing how CSS works, I still don't think I do.  &lt;/p&gt;

&lt;p&gt;What I'm ultimately trying to say is, Tailwind came along and said: "don't worry about that nonsense, do it all in HTML and never write another line of CSS again". Immediately interest was piqued and Tailwind became very popular.&lt;/p&gt;

&lt;p&gt;I finally found a use-case to try out Tailwind (this website uses it, as well) and thought I write my thoughts about it and how I think it compares to using good ol' CSS (or SCSS/LESS whatever takes your fancy).&lt;/p&gt;

&lt;h2&gt;
  
  
  So, how is Tailwind?
&lt;/h2&gt;

&lt;p&gt;Tailwind has shined when I've been using it to get something up and running quickly, be it a prototype or a proof-of-concept. You can just focus on building your component (if we were using React, for example), there's no worry with importing stylesheets and ensuring they get parsed correctly.&lt;/p&gt;

&lt;p&gt;Tailwind is extendable to be able to interject your styles and colour schemes, add your classes and modify existing ones. Tailwind also allows you to target pseudo-classes right in the class name, which is probably my favourite feature.&lt;/p&gt;

&lt;p&gt;I think Tailwind's use of utility classes bodes well for component-based frameworks as it allows you to encapsulate styles to minimise class name bleed. As one component can encapsulate the template and the corresponding style, rather than having them in two separate places. This applies to small components (which they all should be, of course 😝) to not have complicated components made more complicated by hundreds of class names.&lt;/p&gt;

&lt;p&gt;Tailwind also comes with the ability to "apply" Tailwind classes in your style sheets. So your &lt;code&gt;button&lt;/code&gt; goes from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-blue bg-blue-500 hover:bg-blue-800 hover: text-white"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn-blue"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.btn-blue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;text-blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;bg-blue-500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="k"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;bg-blue-800&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;@apply&lt;/span&gt; &lt;span class="nt"&gt;text-white&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;Which helps in minimising the class name spam. However, this begs my most important question...&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it scale?
&lt;/h2&gt;

&lt;p&gt;Increasingly, I am re-writing my applications that are using TailwindCSS and moving all the HTML classes to the SCSS style-sheets. Why?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex md:w-2/3 w-full p-2 md:p-8"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex flex-col items-start justify-center text-center md:text-left"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"font-black header-text-xl md:text-6xl"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-2xl md:text-3xl mt-2 opacity-75"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"flex w-full mt-6 justify-center md:justify-start"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;findOutMoreLink&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded text-2xl ml-auto"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
               &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;findOutMoreLinkText&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is not readable (and that is a very tame example). At the very least, you need to &lt;em&gt;study&lt;/em&gt; that HTML block to start to figure out how it is styled or what it is trying to convey.&lt;/p&gt;

&lt;p&gt;With a bit of clever SCSS you can transform the block above to something more akin to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"wrapper two-thirds"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"center"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;findOutMoreLink&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; 
               &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; 
               &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-red"&lt;/span&gt;
            &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
               &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;findOutMoreLinkText&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sure, you still need to go to the SCSS file and read that understand how it styled, but that is the purpose of SCSS. Are we not crossing streams, muddying the waters, by merging the styling and markup into the same file?&lt;/p&gt;

&lt;p&gt;When I view HTML I want to see the semantics of the file. When I view the stylesheet I want to see how the content is styled.&lt;/p&gt;

&lt;p&gt;If I've decided to move all my Tailwind classes to custom SCSS style-sheets, then why wouldn't I just use SCSS? Spoiler: this is exactly what I've done. &lt;/p&gt;

&lt;p&gt;Now I get complete control over my styling, I can use variables and all the other lovely functionality bundled with SCSS and can apply proven architectural structures to my styling that makes it easier to read and understand.&lt;/p&gt;

&lt;p&gt;It is far easier to organise your code when you can have a distinction between your stylesheets and your templates. It also allows you to structure your styles and take full advantage of all the utility that comes with SCSS.&lt;/p&gt;

&lt;p&gt;Ultimately I had projects where I was struggling to understand how to tweak the UI as I found following all the class names so difficult. &lt;/p&gt;

&lt;p&gt;If I, the author of the code, was struggling to follow it - how would anyone else?&lt;/p&gt;

&lt;h2&gt;
  
  
  Tailwind fills a niche
&lt;/h2&gt;

&lt;p&gt;It is a great tool, but I can only see myself using it if I need to prototype something fast, or a backend heavy side-project with a minimal front-end. That is where Tailwind shines. &lt;/p&gt;

&lt;p&gt;If your project has scalability concerns or it is a style heavy project then I recommend to run your own SCSS architecture and follow something like the &lt;a href="https://www.learnhowtoprogram.com/user-interfaces/building-layouts-preprocessors/7-1-sass-architecture"&gt;7-1 pattern&lt;/a&gt; (which is by far my favourite way of organising my SCSS). This allows you to reap all the benefits of using SCSS and keeps a clear concern between your style-sheets (here be styles) and your HTML (here be HTML).&lt;/p&gt;

</description>
      <category>css</category>
      <category>tailwindcss</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Creating a framework-agnostic API module in TypeScript</title>
      <dc:creator>Harry</dc:creator>
      <pubDate>Thu, 30 Jul 2020 18:29:45 +0000</pubDate>
      <link>https://dev.to/bendix/creating-a-framework-agnostic-api-module-in-typescript-13kd</link>
      <guid>https://dev.to/bendix/creating-a-framework-agnostic-api-module-in-typescript-13kd</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://forwardigital.co.uk/blog/creating-a-framework-agnostic-api-module-in-typescript"&gt;This post originally appeared on my personal blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hello, today I'm going to be writing about how to write a framework-agnostic API module in TypeScript.&lt;/p&gt;

&lt;p&gt;Due to the day job demands, I've recently transitioned from writing Angular UIs to writing primarily React UIs. I'm not going to get into the finer points of Angular vs React, framework vs library, as that horse is long dead! &lt;/p&gt;

&lt;p&gt;However, one thing I do miss from the Angular days is the &lt;code&gt;HttpClient&lt;/code&gt; provided by Angular. It &lt;a href="https://angular.io/guide/http"&gt;'provides simplified client HTTP API for Angular applications'&lt;/a&gt;. That it does. &lt;/p&gt;

&lt;p&gt;Today I'm going to show how I write something similar using TypeScript, which is more explicit and more functional than our Angular counterpart. &lt;/p&gt;

&lt;p&gt;Please note as this is written entirely in TypeScript I will make no assumptions about what framework you are using. I will also tailor this tutorial to be generic that either &lt;code&gt;fetch&lt;/code&gt; or &lt;code&gt;Axios&lt;/code&gt; can be used. However, I will touch on some Axios specific features further down the post.&lt;/p&gt;

&lt;p&gt;Another assumption; if you are reading this, you are familiar with TypeScript. So let's jump straight into it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/hbendix/API-Module"&gt;If you just wanna see the code, no danger! I uploaded it here. Enjoy.&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Why?
&lt;/h1&gt;

&lt;p&gt;Good question. By writing an API module is allows us to encapsulate all our API calls into a single module/folder within our codebase. By splitting up each facet of an API call (creating the URL, passing the data, handling the correct Http verb) we can easily test, maintain and understand our codebase or someone else's. Code readability to me is of the utmost importance and should be valued above much else. &lt;/p&gt;

&lt;p&gt;The API module will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Handle the sending and receiving of all server calls&lt;/li&gt;
&lt;li&gt;Create our server compliant URLs, handle all parsing of parameters required and set global headers for all requests&lt;/li&gt;
&lt;li&gt;Encapsulate a generic Client Factory layer that will handle our &lt;code&gt;POST&lt;/code&gt;,&lt;code&gt;PUT&lt;/code&gt;,&lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt; request, whilst also giving us type safety and IntelliSense&lt;/li&gt;
&lt;li&gt;Serve as a logical layer to declare and reference any data transfer objects (DTO) your API sends or receives&lt;/li&gt;
&lt;li&gt;Allow the developer to be as verbose as required for each server call, as to minimise confusion and emphasis readability of the codebase &lt;/li&gt;
&lt;li&gt;Be easy to test as each step on the process is small, simple and functional&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To give you a brief example, we can see the differences:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// oh look at me I'm not using an API module &lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateUserDetails&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PUT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/x-www-form-urlencoded; charset=UTF-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ohohhh yeah look at that API module&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateUserDetails&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;API&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UserDTO&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUserDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// handle the error&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;DRY!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Write an API module once and never worry about URLs, headers, return types ever again. Cover your API module in tests (easy using a functional approach) and never fret about your server calls again!&lt;/p&gt;

&lt;h1&gt;
  
  
  Let us begin
&lt;/h1&gt;

&lt;p&gt;Right, if you've come this far your either sold or intrigued. &lt;/p&gt;

&lt;p&gt;I will be using the &lt;code&gt;getUserDetails&lt;/code&gt; and other user-centric calls in these examples. &lt;br&gt;
Folder structure is simple:&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="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;
    &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;API&lt;/span&gt;
        &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;Client&lt;/span&gt;
            &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
            &lt;span class="nx"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
            &lt;span class="nx"&gt;HttpInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt; &lt;span class="c1"&gt;// axios only&lt;/span&gt;
            &lt;span class="nx"&gt;ResponseCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
            &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
        &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;
            &lt;span class="nx"&gt;CreateQueryString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
            &lt;span class="nx"&gt;CreateUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
            &lt;span class="nx"&gt;JoinPaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
            &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
        &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;
            &lt;span class="nx"&gt;GetUserDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
            &lt;span class="nx"&gt;DeleteUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
            &lt;span class="c1"&gt;// etc&lt;/span&gt;
        &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
    &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="c1"&gt;//rest of app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Client&lt;/code&gt; folder is where the actual server calls happen through the use of factories that handle each respective Http verb. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;URL&lt;/code&gt; folder will parse our base url, any params and remove all unwanted characters.&lt;/p&gt;

&lt;p&gt;Here, the &lt;code&gt;User&lt;/code&gt; is an example but you can start to see how I am very explicit and verbose. Each file within &lt;code&gt;/User&lt;/code&gt; performs one simple action, which is immediately identifiable at a glance. &lt;/p&gt;

&lt;p&gt;How many times have you been burned by having say: &lt;code&gt;user.service.ts&lt;/code&gt; which contains all server calls for your user domain, soon it is 600 LOC and completely unreadable. We mitigate that entirely by spitting each action our user can perform into its own file. This results in more files, however, this is an improvement over a monolithic service (IMO). &lt;/p&gt;

&lt;h1&gt;
  
  
  URL
&lt;/h1&gt;

&lt;p&gt;Our URL layer needs to ultimately create the correct URL for the API. We need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sort any parameters into a key-value pair query string&lt;/li&gt;
&lt;li&gt;Join our base URL with the params &lt;/li&gt;
&lt;li&gt;Make our URL error-proof
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CreateUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I may call &lt;code&gt;createUrl&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;createUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://exmaple.com/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/user/&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;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;abc5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which produces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://exmaple.com/api/user?userId=123&amp;amp;token=abc5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating the API URL
&lt;/h2&gt;

&lt;p&gt;Our &lt;code&gt;createUrl&lt;/code&gt; needs to first and foremost join the &lt;code&gt;baseUrl&lt;/code&gt; and the &lt;code&gt;template&lt;/code&gt; together. This is where &lt;code&gt;JoinPaths.ts&lt;/code&gt; comes into the ring, as seen in the folder structure overview above.&lt;/p&gt;

&lt;p&gt;We need to ensure we don't simply join two strings together, as shown in the code above, this could result in a bad API URL, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://exmaple.com//api/user/?userId=123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to take both strings in as an array to be able to trim the trailing and leading slashes and handle the slashes from with the &lt;code&gt;JoinPaths&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trimLeadingSlash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// if first character is slash, return string minus first char&lt;/span&gt;
    &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&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;trimTrailingSlash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// if last character is slash, return string minus last char&lt;/span&gt;
    &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;joinPaths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;currentSegment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;trimTrailingSlash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;trimLeadingSlash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentSegment&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows anyone working on this codebase to not have to worry about trivial problems like leading and trailing slashes. We move the responsibility into our API module and if you write some unit tests you can sleep safely knowing &lt;code&gt;JoinPaths&lt;/code&gt; will look after your URLs. &lt;/p&gt;

&lt;h2&gt;
  
  
  Sort the parameters
&lt;/h2&gt;

&lt;p&gt;So now we have a URL that has been parsed and formatted, we can append our API parameters to it. Ultimately, we need to iterate through the object we passed into &lt;code&gt;createUrl()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Typically there are two ways to pass parameters to a server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com/api/:token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example.com/api?token=token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's not discriminate and create a parameter pattern that will allow us to decide on the fly which way we please.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;joinPaths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;template&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;queryParams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;paramPlaceHolder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paramPlaceHolder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paramPlaceHolder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we're iterating and filtering over each key in the parameter object, then we either do one of two things:&lt;/p&gt;

&lt;p&gt;If the parameters being passed in match the template then we assume the token is being passed out of parameters like &lt;code&gt;:token&lt;/code&gt; and we replace the template match with the parameter value.&lt;/p&gt;

&lt;p&gt;Otherwise, we add the key-value pair to our new &lt;code&gt;queryParams&lt;/code&gt; object defined above.&lt;/p&gt;

&lt;p&gt;Now that all remains is to put it all together and sort the query parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createKeyValuePair&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createKeyValuePair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;amp;&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="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createQueryString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createKeyValuePair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;amp;&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;The above code will iterate over all the parameters in the object we created in the previous step, each parameter we call a recursive function that first checks to if the passed in value is an array and if so then work through each element in the array and create the parameters. &lt;/p&gt;

&lt;p&gt;Otherwise, return the value in the format the server is expecting. By joining each element with an ampersand we will create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;?key=value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, array or object both use cases get covered. &lt;/p&gt;

&lt;p&gt;Now all is todo is add the &lt;code&gt;createQueryString&lt;/code&gt; reference and return the URI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;{.*}/&lt;/span&gt;&lt;span class="p"&gt;,&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;queryString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createQueryString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;encodeURI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)}${&lt;/span&gt;&lt;span class="nx"&gt;queryString&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;`?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;queryString&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code appears below the object parameter code we wrote above. &lt;/p&gt;

&lt;p&gt;Now the URL is sorted we can turn our attention to the generic factories.&lt;/p&gt;

&lt;h1&gt;
  
  
  Factories
&lt;/h1&gt;

&lt;p&gt;What are the factories? They will be the layer that is responsible for actually making the request to the server. This layer acts as a wrapper around either the &lt;code&gt;Axios&lt;/code&gt; client or the native &lt;code&gt;fetch&lt;/code&gt; client. We also need to handle each HTTP verb and leverage TypeScript to allow IntelliSense. This is the &lt;code&gt;/Client&lt;/code&gt; folder from the folder structure overview above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AxiosRequestConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AxiosResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AxiosError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./HttpInstance&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;sendRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AxiosRequestConfig&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AxiosResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AxiosError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sendRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;K&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;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sendRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;body&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;putFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;K&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;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sendRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PUT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;body&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deleteFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sendRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The above code is for the Axios client, however, for &lt;code&gt;fetch&lt;/code&gt; it's almost identical but you will need to handle the stringification yourself and make sure to reject the request promise if &lt;code&gt;res.ok&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Response/ok"&gt;as with &lt;code&gt;fetch&lt;/code&gt; a failed request does not get caught in the &lt;code&gt;catch&lt;/code&gt; block of a promise.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We declare each verb as it's own factory function, and through the use of generics and declare the response and request types we will declare when calling these functions. &lt;/p&gt;

&lt;h1&gt;
  
  
  Actions
&lt;/h1&gt;

&lt;p&gt;Now we've sorted the request URL, parameters and created a layer to communicate with the API, now we need to introduce our actions layer. This is where I like to declare DTOs and will act as a buffer between the application and our API module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ../API/User/createAccount.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createUrl&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../URL/CreateUrl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;environmentVariables&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../../environment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;postFactory&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../Client&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;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CreateDTO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;confirmPassword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createAccount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateDTO&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;postFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;createUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;environmentVariables&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;payload&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;From the example above you can see all the pieces coming together and can see the TypeScript generics in play. It's clear from a glance exactly what this code is doing, what the data looks like and how the data will look on a successful request.&lt;/p&gt;

&lt;p&gt;Please note the &lt;code&gt;environmentVariables()&lt;/code&gt; function just returns the base URL of the server.&lt;/p&gt;

&lt;p&gt;Now all you need to do is call and await &lt;code&gt;createAccount&lt;/code&gt; and make sure to wrap it in a try/catch block. That's it! You now have an API module that handles all the things you need to make a request to your server without you ever having to repeat yourself or worry about incorrect syntax/data structures.&lt;/p&gt;

&lt;h1&gt;
  
  
  Axios specifics
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Headers
&lt;/h2&gt;

&lt;p&gt;I like to create an Axios instance on application load that will take a headers object as an argument, this ensures that you don't have to keep creating/passing in a headers object. Fire and forget!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;defaultHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;include&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AxiosInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;defaultHeaders&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;h2&gt;
  
  
  Interceptors
&lt;/h2&gt;

&lt;p&gt;I also like to register interceptors for the client (&lt;code&gt;axios&lt;/code&gt;) we initialise above (so all requests and responses get accounted for)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RegisterInterceptor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&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;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AxiosError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;error&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="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// no response from the server (is the user offline?)&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;clearCache&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StateActions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LOGGED_OUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&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;You can see my interceptor is used to handle unauthorised messages and log out the user. You can also use this layer to handle any response type or no response at all for your client.&lt;/p&gt;

&lt;p&gt;Lastly, register this interceptor on application load, something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/API&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// app component code:&lt;/span&gt;
&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;API&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RegisterInterceptor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setState&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;That is it all! I hope you learnt something today. &lt;a href="https://github.com/hbendix/API-Module"&gt;All the code I've uploaded to a GitHub repository here. Enjoy.&lt;/a&gt; :)&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>fetch</category>
      <category>axios</category>
      <category>http</category>
    </item>
    <item>
      <title>Applying Domain-Driven Design principles to a Nest.js project</title>
      <dc:creator>Harry</dc:creator>
      <pubDate>Sat, 25 Jul 2020 08:48:52 +0000</pubDate>
      <link>https://dev.to/bendix/applying-domain-driven-design-principles-to-a-nest-js-project-5f7b</link>
      <guid>https://dev.to/bendix/applying-domain-driven-design-principles-to-a-nest-js-project-5f7b</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://forwardigital.co.uk/blog/applying-domain-driven-design-principles-to-a-nestjs-project"&gt;This post originally appeared on my personal blog.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hey, today I'm going to be writing about how you can apply domain-driven design (DDD) principles to a Nest.js project.&lt;/p&gt;

&lt;p&gt;I've created a quick repository showing the architecture explained in this blog. &lt;a href="https://github.com/hbendix/domain-driven-nest"&gt;Find it here.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I am by no means an expert in DDD, we merely decided to adopt it for &lt;a href="https://www.repetitio.co"&gt;Repetitio&lt;/a&gt; when we re-wrote the server.&lt;/li&gt;
&lt;li&gt;I will not cover what DDD is in this blog, please refer to this &lt;a href="https://dev.to/microtica/the-concept-of-domain-driven-design-explained-1ccn"&gt;dev.to blog post&lt;/a&gt; or the &lt;a href="https://www.amazon.co.uk/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215"&gt;DDD bible&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nestjs.com/"&gt;Nest.js&lt;/a&gt; - A progressive Node.js framework for building efficient, reliable and scalable server-side applications. It mirrors Angular's architecture style and is built with TypeScript from the ground up.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Nest?
&lt;/h2&gt;

&lt;p&gt;Nest is opinionated on how to structure your code, this works well in a DDD case as you need to be able to put strict boundaries around your code as to keep your code maintainable and readable. If you are looking for a powerful and scalable framework for your Node.js application, I highly recommend Nest.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  So why would we do this?
&lt;/h2&gt;

&lt;p&gt;Having used Nest.js in production for about 4 months we ended up, due to the project being unrestricted without clear boundaries, with a mess of spaghetti code for our server and API. We're talking about &lt;code&gt;services&lt;/code&gt; that are 600+ LOC long.&lt;/p&gt;

&lt;p&gt;This is by no means a reflection of Nest.js, but rather a reflection of what happens to codebases without strict rules and boundaries implemented.&lt;/p&gt;

&lt;p&gt;We decided to jump on the bandwagon and start to look into DDD as a way forward after we had decided to rewrite the server.&lt;/p&gt;

&lt;p&gt;So ultimately what we wanted to get out of this exercise is a codebase that by nature of design stays tameable.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you do this?
&lt;/h2&gt;

&lt;p&gt;We found that DDD outlines a clear structure to your code that not only makes sense but can minimise the amount of code/methods/classes that resides in aspects of your domain.&lt;/p&gt;

&lt;p&gt;To use our old server as an example; we had a service called &lt;code&gt;user.service.ts&lt;/code&gt; that contained ALL logic for the user. Now, as with most applications, the user tends to take a center stage and encapsulates a lot of domain logic. Therefore, our service became huge, covering the entire user logic. It became hard to read and understand what each method was trying to achieve and what actions it was performing.&lt;/p&gt;

&lt;p&gt;So let us use this example and apply some DDD logic to it, firstly we decided to be very strict with our domain layer, therefore in the user domain we only care about our user domain model, all other relationships are abstracted out into a new domain layer or a subdomain.&lt;/p&gt;

&lt;p&gt;We kept the usage simple and made a class per action, rather than lumping them all into the same omnipotent, omniscient service. By the fact of simplifying, our domain layer becomes very functional with each class performing typically one action, with the methods within further reflecting this.&lt;/p&gt;

&lt;h1&gt;
  
  
  Our architecture
&lt;/h1&gt;

&lt;p&gt;This is our architecture: (using a very generic user as an example for the different files and services)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
    /API
        /User
            UserController.ts
            CreateUserDTO.ts
        APIModule.ts
    /Auth
        AuthModule.ts
    /Database
        DatabaseModule.ts
    /Domain
        /User
            CreateUser.ts
            IUserRepository.ts
            User.ts
            UserModule.ts
    /Persistence
        /User
            UserRepository.ts
            UserRepositoryModule.ts
            UserEntity.ts
    /Utils
        /Mappers
            /User
                CreateUserDTOToUser.ts
        /Services
            /Email
                EmailSenderService.ts
    AppModule.ts
    Environment.ts
    main.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Module&lt;/code&gt; in this case is a Nest Module. We decided that each Domain would have its module, as would each persistence entity. However, we decided to lump all API endpoints into one module, as the only thing importing the &lt;code&gt;APIModule&lt;/code&gt; was the &lt;code&gt;AppModule&lt;/code&gt; on application bootstrap.&lt;/p&gt;

&lt;h2&gt;
  
  
  API
&lt;/h2&gt;

&lt;p&gt;This layer contains all our endpoints and controllers. We tried to make a Controller class mirror a domain entity. So, if we had a user domain, we'd have a user controller. This pattern extends to the persistence layer too.&lt;/p&gt;

&lt;p&gt;This is also an obvious space to declare any DTOs - sending or receiving.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth
&lt;/h2&gt;

&lt;p&gt;This is where all our Guards, Strategies and general Auth configuration lies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database
&lt;/h2&gt;

&lt;p&gt;You guessed it, this layer is responsible for connecting to any kind of data store, or multiple data stores for that matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain
&lt;/h2&gt;

&lt;p&gt;The most important part of our codebase. The domain is a reflection of the problem we are trying to solve. This is broken up into our domain models (each warranting their folder). Our domain model, in our case, is a TypeScript types file.&lt;/p&gt;

&lt;p&gt;We want to keep our domain layer pure from third party artefacts, so within our domain we should only reference our code. We don't want to see MongoDB schemas, third-party packages, reference to any database-specific logic or anything related to our API layer.&lt;/p&gt;

&lt;p&gt;We define an interface that mocks our repository layer. This is defined in our domain layer as it is directly related to our domain. We are outlining how we want to be able to mutate our domain models, we are not bothered with the implementation (that is the persistence layer's job).&lt;/p&gt;

&lt;p&gt;A few rules we adhere to with our domain layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The domain actions should only accept the domain model as a parameter or an Id in string form. DTOs should be mapped &lt;em&gt;before&lt;/em&gt; calling our domain layer.&lt;/li&gt;
&lt;li&gt;Leave all third-party libraries, packages etc outside the domain layer. It should be third-party dependency-free.&lt;/li&gt;
&lt;li&gt;It should only reference code that exists in the domain layer&lt;/li&gt;
&lt;li&gt;In theory, you should be able to cut and paste your domain layer it into any project (language-dependent) and it should work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dependency-free domain
&lt;/h3&gt;

&lt;p&gt;One of the biggest mental challenges is organising your code in such a way that your domain layer is only dependent on other classes and files within your domain layer.&lt;/p&gt;

&lt;p&gt;For example, to communicate with the persistence layer we can introduce the &lt;code&gt;UserRepositoryModule&lt;/code&gt; as a dependency to our &lt;code&gt;UserModule&lt;/code&gt; but would go against a key component of DDD - a dependency free domain. It's also why we have a &lt;code&gt;User.ts&lt;/code&gt; (domain) and &lt;code&gt;UserEntity.ts&lt;/code&gt; (persistence). One is our domain model, in its purest form. The other, our domain model but with the added attributes/functionality for whatever data store.&lt;/p&gt;

&lt;p&gt;One way (and thanks to &lt;a href="https://github.com/SeWaS"&gt;SeWaS&lt;/a&gt; for showing me how) we can use interface injection, rather than typical module injection to communicate with the persistence layer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DomainAction.ts&lt;/code&gt; is just a generic name which represents the many actions our domain will perform.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Domain/User/DomainAction.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Inject&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserRepository&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../Persistence/User/Repository&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IUserRepository&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./IUserRepository&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;UserRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UserRepo&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="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DomainAction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;UserRepo&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="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IUserRepository&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Persistence/User/UserPersistenceProvider.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserRepository&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Repository&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserRepoProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UserRepo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserRepository&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Persistence/User/UserRepositoryModule.ts &lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserRepoProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./UserPersistenceProvider&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="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UserRepoProvider&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UserRepoProvider&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserRepositoryModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Domain structure
&lt;/h3&gt;

&lt;p&gt;Each domain action that gets performed on our domain model should constitute its own file and class. The name of this class should be explicit and leave no-one guessing as to its purpose.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/Domain
    /User
        Create.ts
        Update.ts
        Delete.ts
        GetEmail.ts
        RemoveToken.ts
        IUserRepository.ts
        UserEntity.ts
        UserModule.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can even drop the User from the name of the class as it is implied due to it residing within the user domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Persistence
&lt;/h2&gt;

&lt;p&gt;Our persistence layer is where all our database queries are performed. This will contain the entity's Module and its Repository. The repository in this sense is a class that contains all database operations. Again, this should mirror our domain entities 1:1 and should typically only contain around 4/5 methods - predominately CRUD operations. Unlike our domain layer, we couple multiple actions within the same class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utils
&lt;/h2&gt;

&lt;p&gt;These typically share functionality required across our domain. &lt;/p&gt;

&lt;p&gt;This is where we store all our mappers that map data-transfer-objects to domain models and vice versa.&lt;/p&gt;

&lt;p&gt;It is a good place to store singleton services, like the example, an email sender service.&lt;/p&gt;

&lt;h1&gt;
  
  
  Typical flow through our server
&lt;/h1&gt;

&lt;p&gt;As I feel the need to show &lt;em&gt;some&lt;/em&gt; code, I'll show some snippets of how this all looks if we were to create a very basic user in a purely fictional server. Obviously, I'm excluding import statements here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// the user DTO we receive from the client&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateUserDTO&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;IsString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;IsNotEmpty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;IsString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;IsNotEmpty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Class validator is great for validation, couple that with an &lt;code&gt;AuthGuard&lt;/code&gt; (in the &lt;code&gt;Auth&lt;/code&gt; layer) and you can handle all exceptions for your code in one place and handle the response object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// UserController.ts&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Post&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="nc"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CreateUserDTO&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HttpStatus&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// all our mappings get done in static classes&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;domainModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mapCreateDTOToUserModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domainModel&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;HttpStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As our domain is only concerned with &lt;strong&gt;our domain&lt;/strong&gt; we need to make sure that all API layer related objects get mapped to the domain appropriate model, hence our mapping happening in the API layer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// /Domain/User/Create.ts&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UserRepo&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;EmailService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EmailService&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="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Create&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;UserRepo&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="nx"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IUserRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;EmailService&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="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IEmailSenderService&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;async&lt;/span&gt; &lt;span class="nc"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;registeredUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registeredUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;EmailOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AccountCreationEmailOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;registeredUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;EmailSenderService&lt;/code&gt; is an example of shared logic across our domain that would exist in the &lt;code&gt;Utils&lt;/code&gt; layer mentioned above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// /Persistence/User/UserRepository.ts&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;IUserRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;InjectModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Model&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nc"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserEntity&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;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;createdUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserEntity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createdUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GenericError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;addedEntity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserEntity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addedEntity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also see the need to have two types of &lt;code&gt;User&lt;/code&gt;, one for our domain which is the purest form of our domain model and one that exists in our persistence layer that would be very similar to our domain model but would contain third-party (in this case, database-related) attributes or logic specific to our persistence layer. &lt;/p&gt;

&lt;p&gt;This further re-enforces the need for our domain layer to be pure of all third-party artefacts.&lt;/p&gt;

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

&lt;p&gt;This is a brief overview of the architecture we've employed at Repetitio. By holding ourselves to such rigid rules we've found our codebase has been pleasantly manageable, nothing like it was before! With clear logical layers to our server, it is easy to navigate and understand, allowing us to easily dive in and iterate with an ever-evolving set of requirements.&lt;/p&gt;

&lt;p&gt;I've created a quick repository showing the architecture explained in this blog. &lt;a href="https://github.com/hbendix/domain-driven-nest"&gt;Find it here.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nestjs</category>
      <category>typescript</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
