<?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: Johannes Mogashoa</title>
    <description>The latest articles on DEV Community by Johannes Mogashoa (@johannesmogashoa).</description>
    <link>https://dev.to/johannesmogashoa</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%2F465624%2F78a9d872-75f1-4faf-8780-06cd53bc8239.jpg</url>
      <title>DEV Community: Johannes Mogashoa</title>
      <link>https://dev.to/johannesmogashoa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/johannesmogashoa"/>
    <language>en</language>
    <item>
      <title>Mistakes Were Made</title>
      <dc:creator>Johannes Mogashoa</dc:creator>
      <pubDate>Sat, 18 Oct 2025 21:00:56 +0000</pubDate>
      <link>https://dev.to/johannesmogashoa/mistakes-were-made-2p8n</link>
      <guid>https://dev.to/johannesmogashoa/mistakes-were-made-2p8n</guid>
      <description>&lt;h2&gt;
  
  
  Legacy Legacy Legacy
&lt;/h2&gt;

&lt;p&gt;For many years, .NET Framework has been at the core of many enterprise systems, where some of the very crucial systems we use to this day still run on this technology. Like many other things that come and go, that are discontinued, deprecated, or no longer actively supported, the same can be said for .NET Framework. Though the &lt;a href="https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-framework" rel="noopener noreferrer"&gt;support policy&lt;/a&gt; for the framework is still active and will still be distributed with Windows, many folks have stopped ensuring backwards compatibility for the framework in new tools.&lt;/p&gt;

&lt;p&gt;Since the decision to unify the .NET Framework &amp;amp; .NET Core with the release of .NET 5 in 2020, a new .NET version has been released every year, with every second release being an LTS version. So the time has come for some companies to make the difficult &amp;amp; costly decision of how to move into the future with their legacy systems. What is the game plan? How far behind are they? Now, in my opinion, I believe that there are all but two clear paths that can be taken.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strangler Fig Pattern
&lt;/h3&gt;

&lt;p&gt;Simply put, rebuild the system piece by piece until you have a shiny "new" system. Now, a lot needs to be taken into consideration when going down this path, and best to have a guideline and well-planned execution. One could liken this approach to requiring "surgical" precision, knowing which components to migrate and when, having clear boundaries and understanding each dependency, but of course, do you simply have the know-how to put this strategy into place?&lt;br&gt;
For more context: &lt;a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/strangler-fig" rel="noopener noreferrer"&gt;MS Learn&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Full Rewrite
&lt;/h3&gt;

&lt;p&gt;As one would think, this is probably the better road to take, blank canvas and all. Wrong, this path, just like the first, leaves so much room for error, if not more. One could say, if you are the gambling type, this approach is probably for you. There is a higher risk, higher cost, higher requirements and possibly a higher reward as well if executed skillfully. &lt;/p&gt;

&lt;p&gt;I guess from the title, you can bet which approach we took.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready...Set...Go!
&lt;/h2&gt;

&lt;p&gt;Let the rewriting begin. So a team was assembled that would be responsible for spearheading the redesign, redevelopment, re-everything of the system, and everyone else would follow our lead. The responsibilities included, but were not limited to, choosing of tech stack, choosing of architecture, choosing of infrastructure, and choosing of tools that would be used.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake One: Tech Stack
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Language &amp;amp; Framework (BE)
&lt;/h4&gt;

&lt;p&gt;Having been a company that relied heavily on the Microsoft ecosystem and the legacy system being built with C# and .NET, the choice language-wise was basically already made, no room for discussion there. So much of the core data models and structures could be reused with a few minor tweaks here and there, leveraging the new features that came with C# v12 &amp;amp; .NET 8. This seemed really possible and straightforward, language and framework, check. Onto the next thing on the list.&lt;/p&gt;

&lt;h4&gt;
  
  
  Database + ORM
&lt;/h4&gt;

&lt;p&gt;Already having decided that our BE is C# and .NET, there aren't really a lot of ORM options one can go for, so why not the tried and tested Entity Framework, why not the constantly improving ORM that makes life so much easier for you? Nope. Fair, the original system was built using &lt;a href="https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/" rel="noopener noreferrer"&gt;ADO.NET&lt;/a&gt;. Perhaps the aim is to use something similar and perhaps re-use some of the SQL queries with improvements from &lt;a href="https://github.com/DapperLib/Dapper" rel="noopener noreferrer"&gt;Dapper&lt;/a&gt;, wrong. We not only opted not to use Entity Framework, but we also opted for a NoSQL database as well, Azure Cosmos DB.&lt;/p&gt;

&lt;h4&gt;
  
  
  Language &amp;amp; Framework (FE)
&lt;/h4&gt;

&lt;p&gt;With re-writing came the great opportunity to relook at the user interface and experience. We could explore and experiment as much as we want. The JS ecosystem has been booming with different libraries, frameworks and meta-frameworks which could really bring new life into how the system looks. Err, wrong! Most of the team members are C# developers and only ever use JS with the likes of JQuery; therefore, having to learn either React, Angular, or Vue is going to be costly and time-consuming.&lt;/p&gt;

&lt;p&gt;Enter the "saviour", Microsoft's newest frontend framework, &lt;a href="https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor" rel="noopener noreferrer"&gt;Blazor&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Blazor is a modern front-end web framework based on HTML, CSS, and C# that helps you build web apps faster."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sure, why not use Blazor? It makes life easier for the developers who are primarily backend, to work on the frontend as well. Seems like the better choice. So what's next? The UI library. No shade to the long-time standing Bootstrap, but it's 2023 and there are so many other libraries one could use outside of Bootstrap; &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt;, &lt;a href="https://bulma.io/" rel="noopener noreferrer"&gt;Bulma&lt;/a&gt;, &lt;a href="https://materializecss.com/" rel="noopener noreferrer"&gt;Materialize CSS&lt;/a&gt;, just to name a few. Forget that for a minute, maybe we can use a Blazor component library to speed up development; there are a few in the market: &lt;a href="https://mudblazor.com/" rel="noopener noreferrer"&gt;MudBlazor&lt;/a&gt;, &lt;a href="https://www.telerik.com/" rel="noopener noreferrer"&gt;Telerik&lt;/a&gt;, &lt;a href="https://www.syncfusion.com/blazor-components" rel="noopener noreferrer"&gt;Syncfusion&lt;/a&gt;, &lt;a href="https://www.radzen.com/" rel="noopener noreferrer"&gt;Radzen&lt;/a&gt;. Ultimately, we go with what we already have a license for, Telerik.&lt;/p&gt;

&lt;p&gt;So there you have it, the main components of our tech stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blazor + Telerik&lt;/li&gt;
&lt;li&gt;C# + .NET&lt;/li&gt;
&lt;li&gt;Azure Cosmos DB + Repository&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mistake Two: Architecture
&lt;/h3&gt;

&lt;p&gt;Having a blank canvas can just as easily break a system as it can make it. You start to think to yourself, if we had a monolithic system that ended up in the position it is now, where only a few can contribute to it because of its fragility and code spaghetti-ness, then we sure best not repeat the same mistake, so let's go for a microservice architecture. Let us have individual services that will be responsible for separate yet not-so-isolated processes that can somewhat run independently of one another. &lt;/p&gt;

&lt;h4&gt;
  
  
  Microservice Architecture
&lt;/h4&gt;

&lt;p&gt;Easy technical design to go with if all the considerations and requirements are taken into account, and everything matches up. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do we have a bounded context map that clearly outlines what the different services will be and what their responsibilities will be? &lt;/li&gt;
&lt;li&gt;What sort of data management will we have? Will each service have its own database, or will there be a logical separation of a shared database?&lt;/li&gt;
&lt;li&gt;How will the services communicate with each other? How will the data flow between them?&lt;/li&gt;
&lt;li&gt;How will this be deployed and maintained?&lt;/li&gt;
&lt;li&gt;What sort of security will we have?&lt;/li&gt;
&lt;li&gt;How will the frontends communicate with the backend services?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sure enough, every question was answered, or so we thought. So where did it really start to go wrong?&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake Three: MVP aka POC
&lt;/h3&gt;

&lt;p&gt;With "everything" taken into consideration, we got to writing the code. We had to prove that this technology can work together and that the architecture was sound. Why not start with a proof of concept that evolves into the minimal viable product? The requirements were set out, and so it began, day in, day out. Pull request after pull request. Demo after demo. One year later, we finally delivered a working MVP that was presented from videos recorded while the system was running on localhost with multiple Visual Studio debugging instances. &lt;/p&gt;

&lt;p&gt;Happiness all round, we proved the concept works and the system "runs" on this new technology. Onto the next phase, delivering an actual deployable, "production-ready" version of the system. &lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake Four: "Fail Fast, Fail Forward"
&lt;/h3&gt;

&lt;p&gt;This is a term thrown around a lot in different environments and ecosystems, and in the development world, it purely means identifying problems quickly(iterate quickly) and learn from them to make the next iteration a lot better. Place your team in a position that allows them to iterate quickly and test out functionality, and see if it works. One word comes to mind: "Agile". Agile + Scrum, why not? 2-week sprints with daily standups and sprint planning. &lt;/p&gt;

&lt;p&gt;One of the most important items when wanting to fail fast but fail forward is to ensure everything is tested out in the very beginning, scaffold your solution, and an API or two, deploy to an environment and see with everything hooked up, does it work? You will quickly realise things you may have overlooked, things that may influence how your team will work, how they will deliver on the sprint items...developer experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mistake Five: Developer Experience
&lt;/h3&gt;

&lt;p&gt;With all the above mistakes being made, it led to the biggest mistake of all, crucial yet overlooked by plenty. Developer tools can only do so much to improve the overall experience of the developer when writing code; IntelliSense, debugging, code completion, etc. Yes, they are important, but restrictions placed on developers due to mistakes are just as important. "My laptop is too slow to run the solution", "My laptop is out of memory, I need more RAM", "The build pipelines take close to 8 minutes to build one service", "I'd rather work on my personal machine since it has more power". &lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learnt
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The definition of insanity is doing the same thing over and over again and expecting different results&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A lot has been learned during the course of this rewrite, and we would surely be insane to do the same in future and expect success. It is crucial to understand the requirements of the path you are undertaking and not rush an outcome due to consequences that ought to have been considered upon planning. Lessons to take into the next journey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Fail to plan, plan to fail" - without clear goals, architecture, and processes, you’ll waste time, mismanage resources, and deliver unstable systems.&lt;/li&gt;
&lt;li&gt;Understand your team's capabilities (strengths &amp;amp; weaknesses) - knowing and understanding your team's dynamics allows you to allocate work accordingly.&lt;/li&gt;
&lt;li&gt;Understand the tech you're backing - the newest shiniest tool isn't always the sharpest tool in the shed or the best tool for the job. Take time to understand the applicable scenarios that work best for the tool, not try to bend it to work best for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One major lesson I learned is, awareness without action is complicity — seeing the car headed for disaster and saying nothing until it crashes doesn’t absolve you.&lt;/p&gt;

&lt;p&gt;You plan intelligently, expect failure, detect it fast, and evolve forward.&lt;/p&gt;

&lt;p&gt;Cheers ✌🏽&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>csharp</category>
      <category>dotnet</category>
      <category>programming</category>
    </item>
    <item>
      <title>I built a PWA - The Blazor WASM way</title>
      <dc:creator>Johannes Mogashoa</dc:creator>
      <pubDate>Thu, 04 Jan 2024 11:55:29 +0000</pubDate>
      <link>https://dev.to/johannesmogashoa/i-built-a-pwa-the-blazor-wasm-way-bfg</link>
      <guid>https://dev.to/johannesmogashoa/i-built-a-pwa-the-blazor-wasm-way-bfg</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;As a software developer, one is bound to come across the weird requirement from a client, "I want a mobile app". Yeah, sure no problem, let me get my dev environment setup correctly. You are bound to reach for something like Flutter or React Native or Ionic for a single codebase cross-platform approach because why not right? Then your client says, "But I am not willing to deal with the stores, can't we get around that?" Of course, we can, why not build a PWA. Users can save it onto their phone from the web and we can have extra native features like push notifications etc. "Great! Let's go for it"!&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting into it
&lt;/h2&gt;

&lt;p&gt;Well building a PWA is not too far off from building any other web app like a SPA am I right? Pick and choose from React, Angular, Vue and the like... &lt;br&gt;
&lt;em&gt;Well issue one is that I am a .NET developer.&lt;/em&gt; Oh boy! &lt;br&gt;
&lt;strong&gt;Easy solution&lt;/strong&gt;: .NET's crown jewel framework, &lt;strong&gt;BLAZOR&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Time to build
&lt;/h2&gt;

&lt;p&gt;With building the app there were a few things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Will the app need a backend? (yes)&lt;/li&gt;
&lt;li&gt;Is authentication required? (yes, I want to use Microsoft)&lt;/li&gt;
&lt;li&gt;What are the core functionalities of the app? (more web-like features)&lt;/li&gt;
&lt;li&gt;Feasibility of building a PWA over Native App? (cheaper to deploy)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With all those considered the building began. Well with the app requiring a backend and authentication, I reached for the Blazor WebAssembly template with the Co-Hosted &amp;amp; PWA options enabled. Authentication from there was an easy choice, "Individual Accounts" or "Microsoft Identity Platform". Well with an existing Microsoft Active Directory it makes perfect sense to go for Microsoft Identity Platform. So right at the end this what the options looked like...&lt;/p&gt;

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

&lt;p&gt;Easy enough going from there was simply configuring all the relevant Microsoft Entra ID applications on Azure for the Client app and the Server app and letting Visual Studio do all the heavy lifting of configuring everything for me. The end result looks very similar to how any Blazor WASM app with ASP.NET Core Hosted solution looks like. Only a few minor differences due to the "PWA" option that was selected which means the client project had a few more files specifically in the &lt;code&gt;wwwroot&lt;/code&gt; folder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;service-worker.js&lt;/li&gt;
&lt;li&gt;service-worker.published.js&lt;/li&gt;
&lt;li&gt;manifest.json&lt;/li&gt;
&lt;li&gt;icon-512.png&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What next?
&lt;/h2&gt;

&lt;p&gt;I finally have a running project which I can actually install on my device, I mean Edge tells me I can.&lt;/p&gt;

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

&lt;p&gt;That's the easy part done. Fast forward all the design implementations and coding out all the features, comes the time to finally deploy the app to a test environment and test it on an actual mobile device. Easy enough I deploy the server project to an IIS server like I would a normal AspNet Core app and it runs smoothly. I then update the URLs in Azure Entra ID for the authentication to work and Bob was my uncle, or so I thought. Enter classic tale of a developer; &lt;strong&gt;"It worked on my local"&lt;/strong&gt;, I now ran into a few issues that I had to resolve, and I learned something while doing so.&lt;/p&gt;
&lt;h2&gt;
  
  
  PWA Learnings
&lt;/h2&gt;

&lt;p&gt;The tale of building a PWA is that it's meant to be cross platform and not have any issues but oh it did.&lt;/p&gt;
&lt;h3&gt;
  
  
  DateTime compatibility
&lt;/h3&gt;

&lt;p&gt;Turned out Android &amp;amp; iOS do not format the date and time the same way and the iOS format was not compatible with C#'s DateTime type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: build a helper method that will parse the datetime input correctly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="nf"&gt;GetCorrectDateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;inputDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;_newDate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"dd/MM/yyyy HH:mm:ss"&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="c1"&gt;// Try to parse using the default format and culture&lt;/span&gt;
        &lt;span class="n"&gt;_newDate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputDate&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="n"&gt;FormatException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="c1"&gt;// If the default format fails, try to parse using the specified format and culture&lt;/span&gt;
       &lt;span class="n"&gt;_newDate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ParseExact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CultureInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvariantCulture&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_newDate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install prompt
&lt;/h3&gt;

&lt;p&gt;When a web app is a PWA, the browser picks up on that and is able to prompt the user to install the app onto their device, turns out not all browsers support that. Ooops!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: there is none, 👀 just ensure on iOS the user is using Safari and on Android they use Chrome. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Guides/Making_PWAs_installable" rel="noopener noreferrer"&gt;Read more here...&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication state
&lt;/h3&gt;

&lt;p&gt;When the user hadn't been using the app for some time and the Azure token expires and they open up a page that makes an API call, it would fail. This is because the internal API calls have a &lt;code&gt;HttpMessageHandler&lt;/code&gt; which is &lt;code&gt;BaseAddressAuthorizationMessageHandler&lt;/code&gt; which extends the &lt;code&gt;AuthorizationMessageHandler&lt;/code&gt; class which tries to add the authentication token to the request header and when that fails an exception is thrown. If not handled the app breaks. 🤯💥&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: use the &lt;code&gt;TryGetToken&lt;/code&gt; method on the &lt;code&gt;AccessTokenResult&lt;/code&gt; to get the user's authentication token and if that fails redirect to login before making any calls using the HTTP Client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;@code&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;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Prisma&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Prisma"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;Loading&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;OnInitializedAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;accessTokenResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;AccessTokenProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequestAccessToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;accessTokenResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;accessTokenResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InteractionOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryAddAdditionalParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"prompt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"login"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;NavigationManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NavigateToLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accessTokenResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InteractiveRequestUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="n"&gt;accessTokenResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InteractionOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;Loading&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&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;Hopefully in future releases there will be a much more graceful way of handling this issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying new updates
&lt;/h3&gt;

&lt;p&gt;Well since this is a PWA I should just be able to deploy the changes and not have to worry about the user having to update the app manually like they would via the store. Yes &amp;amp; No. Huh? Yes you can deploy the changes but they will not be able to see the changes until they close ALL active instances of the app on their device. This means the actual installed version and any open tabs in their browser need to be closed before updates can happen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Why not just force the app to use the updated version...enter this line of code in the &lt;code&gt;service-worker.published.js&lt;/code&gt;. Blazor actually copies all the contents in the &lt;code&gt;service-worker.published.js&lt;/code&gt; into &lt;code&gt;service-worker.js&lt;/code&gt; when building for production hence we make the change in there.&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="c1"&gt;// Activate the new service worker as soon as the old one is retired.&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;skipWaiting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The line above is added like so:&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onInstall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Service worker: Install&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Activate the new service worker as soon as the old one is retired.&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;skipWaiting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Fetch and cache all matching items from the assets manifest&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assetsRequests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assetsManifest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assets&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;asset&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;offlineAssetsInclude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asset&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="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;asset&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;offlineAssetsExclude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asset&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="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;asset&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asset&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;integrity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheName&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;cache&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;addAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assetsRequests&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;
  
  
  Outro
&lt;/h2&gt;

&lt;p&gt;The question that is always asked around Blazor is, "Will it ever replace Angular or React or Vue?" Honest truth? Nope it will not but I will say that it is a really great alternative to using those frameworks especially if you are a dotnet developer and want to continue using C# even on the frontend. I would definitely use Blazor again. 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Web Dev: &lt;a href="https://web.dev/learn/pwa/" rel="noopener noreferrer"&gt;https://web.dev/learn/pwa/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;MDN: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PWA Install Criteria: &lt;a href="https://web.dev/articles/install-criteria-" rel="noopener noreferrer"&gt;https://web.dev/articles/install-criteria-&lt;/a&gt; Lighthouse Report: &lt;a href="https://developer.chrome.com/docs/lighthouse/pwa/load-fast-enough-for-pwa" rel="noopener noreferrer"&gt;https://developer.chrome.com/docs/lighthouse/pwa/load-fast-enough-for-pwa&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Microsoft Learn: &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/blazor/progressive-web-app?view=aspnetcore-7.0&amp;amp;tabs=visual-studio" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/aspnet/core/blazor/progressive-web-app?view=aspnetcore-7.0&amp;amp;tabs=visual-studio&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Auth with Entra ID: &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/hosted-with-microsoft-entra-id?view=aspnetcore-7.0" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/hosted-with-microsoft-entra-id?view=aspnetcore-7.0&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Pushing updates: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>blazor</category>
      <category>csharp</category>
      <category>pwa</category>
    </item>
    <item>
      <title>Setup project with Next.js, Prisma, tRPC, &amp; NextAuth</title>
      <dc:creator>Johannes Mogashoa</dc:creator>
      <pubDate>Fri, 15 Apr 2022 17:04:20 +0000</pubDate>
      <link>https://dev.to/johannesmogashoa/setup-project-with-nextjs-prisma-trpc-nextauth-4df1</link>
      <guid>https://dev.to/johannesmogashoa/setup-project-with-nextjs-prisma-trpc-nextauth-4df1</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;Recently I was working on a small project where I could explore using technologies I haven't really used that much and put it all to practice. The aim was to build a clone of &lt;a href="https://gdpd.xyz/" rel="noopener noreferrer"&gt;Kubool&lt;/a&gt; which is a platform that allows you to send anonymous messages. And so I got started.&lt;/p&gt;

&lt;p&gt;My initial stack choice was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NextJS&lt;/li&gt;
&lt;li&gt;Prisma&lt;/li&gt;
&lt;li&gt;Postgres from Railway&lt;/li&gt;
&lt;li&gt;Typescript&lt;/li&gt;
&lt;li&gt;NextAuth&lt;/li&gt;
&lt;li&gt;Formik + Yup&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;Vercel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I went ahead built the first basic version of the clone and deployed it on Vercel. You can check it out here: &lt;a href="https://anony-sender.vercel.app" rel="noopener noreferrer"&gt;https://anony-sender.vercel.app&lt;/a&gt;. Later on I decided that "Nope let me rebuild the API endpoint to include tRPC which is a tool that provides you with end-to-end typesafe APIs. Adding tRPC to the project was a mission but I prevailed and thought why not share the steps of creating a project from scratch with tRPC. Links to the respective sites will be provided at the bottom.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps for setting up
&lt;/h2&gt;

&lt;p&gt;The project setup will make use of the technologies I mentioned above. &lt;strong&gt;Prerequisites:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.JS &lt;/li&gt;
&lt;li&gt;Text/code editor (I prefer VS Code)&lt;/li&gt;
&lt;li&gt;Preferred command line tool (Windows Terminal)&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Create &amp;amp; clone repo from starter template
&lt;/h3&gt;

&lt;p&gt;As I have come to focus my interest in building projects with the above mentioned technologies, I went ahead and created a starter template for myself whenever beginning a new project. So let's build on top of that starter template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8gosd941p2jj9jk87dm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8gosd941p2jj9jk87dm.png" alt="Screenshot of the nextjs-prisma template" width="800" height="164"&gt;&lt;/a&gt;Link to starter template: &lt;a href="https://github.com/JohannesMogashoa/nextjs-prisma" rel="noopener noreferrer"&gt;https://github.com/JohannesMogashoa/nextjs-prisma&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating and cloning your repo to your local machine. You may open up that project in your command line tool. Go ahead and install the dependencies by running &lt;code&gt;npm install&lt;/code&gt; or &lt;code&gt;yarn install&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Adding tRPC to the project
&lt;/h3&gt;

&lt;p&gt;You can head over to the official tRPC site: &lt;a href="https://trpc.io/" rel="noopener noreferrer"&gt;https://trpc.io/&lt;/a&gt; to take a look at their documentation.&lt;/p&gt;

&lt;p&gt;At this point you can either use the command line tool or VS Code's integrated terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add @trpc/client @trpc/server @trpc/react @trpc/next zod react-query superjson ws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Next Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a &lt;code&gt;backend&lt;/code&gt; folder in the root of your project&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;utils&lt;/code&gt; and &lt;code&gt;routers&lt;/code&gt; folder inside the &lt;code&gt;backend&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;Inside the &lt;code&gt;routers&lt;/code&gt; folder create an &lt;code&gt;index.ts&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Inside the &lt;code&gt;utils&lt;/code&gt; folder create a &lt;code&gt;context.ts&lt;/code&gt; and &lt;code&gt;createRouter.ts&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Inside the &lt;code&gt;lib&lt;/code&gt; folder, create a &lt;code&gt;trpc.ts&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;trp&lt;/code&gt; folder inside of &lt;code&gt;pages/api/&lt;/code&gt;, then add a &lt;code&gt;[trpc].ts&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The paths to files mentioned above should be as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- backend/routers/index.ts
- backend/utils/context.ts
- backend/utils/createRouter.ts
- lib/trpc.ts
- pages/api/trpc/[trpc].ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3 - Set Up Backend Folders
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;backend/utils/context&lt;/strong&gt;&lt;br&gt;
Since the app is making use of prisma and nextauth, these "values" can be passed through to the rest of the tRPC routes using the context for easy accessibility throughout.&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;getSession&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;next-auth/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;trpc&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;@trpc/server&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;trpcNext&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;@trpc/server/adapters/next&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;NodeHTTPCreateContextFnOptions&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;@trpc/server/adapters/node-http&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;IncomingMessage&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;http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ws&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;ws&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;prisma&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;@/lib/prisma&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the above import statements into the &lt;code&gt;context.ts&lt;/code&gt; file then copy the below section of code.&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;createContext&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;req&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="p"&gt;}:&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;trpcNext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CreateNextContextOptions&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;NodeHTTPCreateContextFnOptions&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IncomingMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ws&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;=&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;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getSession&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;req&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;prisma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;session&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;type&lt;/span&gt; &lt;span class="nx"&gt;Context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;trpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inferAsyncReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;backend/utils/createRouter&lt;/strong&gt;&lt;br&gt;
Copy the below code into the &lt;code&gt;createRouter.ts&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="k"&gt;import&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./context&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;trpc&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;@trpc/server&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;function&lt;/span&gt; &lt;span class="nf"&gt;createRouter&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;trpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Context&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;backend/routers/index&lt;/strong&gt;&lt;br&gt;
In this file, the tRPC App Router is created with all the different routes you would like to have. The below example is if you would like to have ALL your routes in the same 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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRouter&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;@/backend/utils/createRouter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;superjson&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;superjson&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&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;zod&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;appRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transformer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;superjson&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;set-username&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;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="o"&gt;!&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;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&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="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Username set successfully&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&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-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;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&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;user&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;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="o"&gt;!&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;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;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="c1"&gt;// export type definition of API&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;AppRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;appRouter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can imagine, the above code will become more and more as you add other routes and their respective logic. So a better way would be to group routes and place in another file then import those routes into the appRouter. Create another file i.e. &lt;code&gt;userRoutes.ts&lt;/code&gt; inside the &lt;code&gt;backend/routers&lt;/code&gt; folder. The refactored code would like something of the below nature.&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;// backend/routers/index.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;createRouter&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;@/backend/utils/createRouter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;superjson&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;superjson&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userRouter&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;./userRouter&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;appRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transformer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;superjson&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&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="nx"&gt;userRouter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// other merged routes here&lt;/span&gt;

&lt;span class="c1"&gt;// export type definition of API&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;AppRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;appRouter&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;// backend/routers/userRouter.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;z&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;zod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRouter&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;../utils/createRouter&lt;/span&gt;&lt;span class="dl"&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;userRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;set-username&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;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="o"&gt;!&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;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&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="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Username set successfully&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&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-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;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&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;user&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;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="o"&gt;!&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;findUnique&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you have added all the above code consider yourself temporarily done with the &lt;code&gt;backend/&lt;/code&gt; folder and you can now move onto the other files in the other folders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;lib/trpc.ts&lt;/strong&gt;&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;AppRouter&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;@/backend/routers&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;createReactQueryHooks&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;@trpc/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;trpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createReactQueryHooks&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AppRouter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;pages/api/trpc/[trpc].ts&lt;/strong&gt;&lt;br&gt;
This portion is the official setup of the tRPC API endpoint that will handle requests made to your defined routers in the App Router.&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;appRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AppRouter&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;@/backend/routers&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;inferProcedureOutput&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;@trpc/server&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;trpcNext&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;@trpc/server/adapters/next&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;createContext&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;@/backend/utils/context&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// export API handler&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;trpcNext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNextApiHandler&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;appRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;createContext&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="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;INTERNAL_SERVER_ERROR&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;// send to bug reporting&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something went wrong&lt;/span&gt;&lt;span class="dl"&gt;'&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="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;type&lt;/span&gt; &lt;span class="nx"&gt;inferQueryResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
    &lt;span class="nx"&gt;TRouteKey&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;AppRouter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_def&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;queries&lt;/span&gt;&lt;span class="dl"&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;inferProcedureOutput&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AppRouter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_def&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;queries&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;TRouteKey&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point you have completed adding the necessary code into all the files you have created. Now moving onto the final implementation of tRPC in the &lt;code&gt;pages/_app.tsx&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 - Edit pages/_app.tsx file
&lt;/h3&gt;

&lt;p&gt;Navigate to the &lt;code&gt;pages/_app.tsx&lt;/code&gt; file and make the following changes to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove the &lt;code&gt;export default MyApp&lt;/code&gt; line and paste the following code
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Initializing TRPC server on the Next.js server&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;withTRPC&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;@trpc/next&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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppRouter&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;@/backend/routers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Check to see the current environment then generate the appropriate URL&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getBaseUrl&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;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Browser should use current path&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;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VERCEL_URL&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;`https://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VERCEL_URL&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="c1"&gt;// SSR should use vercel url&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;3000&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="c1"&gt;// dev SSR should use localhost&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;withTRPC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AppRouter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/**
         * If you want to use SSR, you need to use the server's full URL
         * @link https://trpc.io/docs/ssr
         */&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&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="nf"&gt;getBaseUrl&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;/api/trpc`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="cm"&gt;/**
             * @link https://react-query.tanstack.com/reference/QueryClient
             */&lt;/span&gt;
            &lt;span class="c1"&gt;// queryClientConfig: { defaultOptions: { queries: { staleTime: 60 } } },&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * @link https://trpc.io/docs/ssr
     */&lt;/span&gt;
    &lt;span class="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})(&lt;/span&gt;&lt;span class="nx"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Phew!!!! That was a lot of code. At this point in time, you should be able to connect your "frontend" to your "backend" using the tRPC client instance created in your &lt;code&gt;lib/trpc.ts&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 - Using tRPC
&lt;/h3&gt;

&lt;p&gt;Now that everything has been implemented on the backend, we can now use the client instance wherever we use to use it. Let's try getting a user from the database using tRPC's hooks that are using React Query under the hood.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;trpc&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;@/utils/trpc&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;useSession&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;next-auth/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&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;UserComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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;session&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;trpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get-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;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&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;email&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;}]);&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&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;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;data&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;name&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;p&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;data&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;email&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;p&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;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;At this point, you can happily say you have implemented tRPC into your NextJS application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outro
&lt;/h2&gt;

&lt;p&gt;Believe me or not, I had written and completed the app using Next's built-in API routing and handling system but the code was messy, had typecasting all over the place in order to mimic some sort of end-to-end type safety between the backend and the client. I have found tRPC to be a really useful tool and look forward to using it more often. If you would like to checkout a github repo that uses tRPC without NextAuth take a look at &lt;a href="https://github.com/TheoBr/roundest-mon" rel="noopener noreferrer"&gt;Roundest by Theo Browne&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;tRPC - &lt;a href="https://trpc.io/" rel="noopener noreferrer"&gt;https://trpc.io/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Vercel - &lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;https://vercel.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Prisma - &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;https://www.prisma.io/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;NextJS - &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;https://nextjs.org/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Railway - &lt;a href="https://railway.app/" rel="noopener noreferrer"&gt;https://railway.app/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Typescript - &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;https://www.typescriptlang.org/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;NextAuth - &lt;a href="https://next-auth.js.org/" rel="noopener noreferrer"&gt;https://next-auth.js.org/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Tailwind CSS - &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;https://tailwindcss.com/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>prisma</category>
      <category>typescript</category>
      <category>nextauth</category>
    </item>
    <item>
      <title>Building My First Side Project - Part 1</title>
      <dc:creator>Johannes Mogashoa</dc:creator>
      <pubDate>Sun, 16 Jan 2022 06:49:56 +0000</pubDate>
      <link>https://dev.to/johannesmogashoa/building-my-first-side-project-part-1-13pf</link>
      <guid>https://dev.to/johannesmogashoa/building-my-first-side-project-part-1-13pf</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;So it has been a while since I got introduced to web development and the community. Wrote my first line of simple code back in 2016 but only formerly started coding in 2020 when I was doing my first year in varsity. I have been contemplating this whole side project thing for making my &lt;a href="https://johannesmogashoa.co.za" rel="noopener noreferrer"&gt;portfolio&lt;/a&gt; look appealing to prospective employers. Finally found a simple project to do: &lt;strong&gt;&lt;em&gt;&lt;u&gt;A Student Accommodation Booking Portal&lt;/u&gt;&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/WqxqV4WWv7yftHpO4o/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/WqxqV4WWv7yftHpO4o/giphy.gif" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I was recently trying to apply for accommodation and one of the residences didn't have a booking system. They were simply using a Google Forms to collect user information and to process everything. So I thought why not build a simple web app for them. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/kIZtwKntRPtGlfEuOh/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/kIZtwKntRPtGlfEuOh/giphy.gif" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Then What??
&lt;/h2&gt;

&lt;p&gt;In doing so, I opted for the following technologies when building this project:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;u&gt;Core Technologies:&lt;/u&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;React/NextJS&lt;/li&gt;
&lt;li&gt;Tailwindcss&lt;/li&gt;
&lt;li&gt;Prisma&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;SQLite DB&lt;/li&gt;
&lt;li&gt;NextAuth&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;u&gt;Experimental Technologies:&lt;/u&gt;
&lt;/h3&gt;

&lt;p&gt;These are technologies that I am interested in learning/working with but currently unsure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tRPC&lt;/li&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;li&gt;Zustand&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;This particular platform will include the following features: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication (Google, Facebook, Email Magic Link) - Powered by NextAuth&lt;/li&gt;
&lt;li&gt;Role-based Auth&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Profile Creation and Editing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Viewing of all the properties&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Application for accommodation and editing of application&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Application Status tracking&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Space Availability tracking&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Progress?
&lt;/h3&gt;

&lt;p&gt;So far not a lot has been done except for the following: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;project initialization with typescript&lt;/li&gt;
&lt;li&gt;adding tailwindcss&lt;/li&gt;
&lt;li&gt;adding and initializing prisma and schema&lt;/li&gt;
&lt;li&gt;adding nextauth&lt;/li&gt;
&lt;li&gt;setting up Google OAuth Credentials&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Current progress can be checked out here 👉 &lt;a href="https://github.com/JohannesMogashoa/student-res-booking" rel="noopener noreferrer"&gt;Github Link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/RbDKaczqWovIugyJmW/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/RbDKaczqWovIugyJmW/giphy.gif" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For now it's back to coding. Part 2 coming soon... cheers 🤘🤘&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>typescript</category>
      <category>react</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
