{"id":4174,"date":"2022-07-02T16:31:57","date_gmt":"2022-07-02T16:31:57","guid":{"rendered":"https:\/\/codevoweb.com\/?p=4174"},"modified":"2023-05-06T08:29:08","modified_gmt":"2023-05-06T08:29:08","slug":"trpc-api-reactjs-nodejs-mongodb-project-setup","status":"publish","type":"post","link":"https:\/\/codevoweb.com\/trpc-api-reactjs-nodejs-mongodb-project-setup\/","title":{"rendered":"Build tRPC API with React.js, Express &#038; Node.js: Project Setup"},"content":{"rendered":"\n<p><a href=\"https:\/\/trpc.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">tRPC<\/a> aka <a href=\"https:\/\/www.npmjs.com\/package\/create-t3-app\" target=\"_blank\" rel=\"noreferrer noopener\">t3-stack<\/a> is a light library for building end-to-end typesafe APIs for Next.js and Node apps without writing schemas or installing libraries for code generation. This article will teach you how to set up tRPC with React.js, Express, and Node.js using <a href=\"https:\/\/classic.yarnpkg.com\/en\/docs\/workspaces\/\" target=\"_blank\" rel=\"noreferrer noopener\">Yarn Workspaces<\/a>.<\/p>\n\n\n\n<p>tRPC API with React.js, Express, and Node.js Series:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"\/trpc-api-reactjs-nodejs-mongodb-project-setup\">Build tRPC API with React.js, Node.js &amp; MongoDB: Project Setup<\/a><\/li>\n\n\n\n<li><a href=\"\/trpc-api-with-reactjs-nodejs-access-and-refresh-tokens\">Build tRPC API with React.js &amp; Node.js: Access and Refresh Tokens<\/a><\/li>\n\n\n\n<li><a href=\"\/fullstack-app-trpc-reactjs-nodejs-jwt-authentication\">Full-Stack App tRPC, React.js, &amp; Node.js: JWT Authentication<\/a><\/li>\n<\/ol>\n\n\n\n<p>Read more articles:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/golang-mongodb-jwt-authentication-authorization\">Golang &amp; MongoDB: JWT Authentication and Authorization<\/a><\/li>\n\n\n\n<li><a href=\"\/api-golang-mongodb-send-html-emails-gomail\">API with Golang + MongoDB: Send HTML Emails with Gomail<\/a><\/li>\n\n\n\n<li><a href=\"\/api-golang-gin-gonic-mongodb-forget-reset-password\">API with Golang, Gin Gonic &amp; MongoDB: Forget\/Reset Password<\/a><\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"850\" height=\"478\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/Build-tRPC-API-with-React.js-Node.js-MongoDB-Project-Setup.webp\" alt=\"Build tRPC API with React.js, Node.js &amp; MongoDB Project Setup\" class=\"wp-image-4248\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/Build-tRPC-API-with-React.js-Node.js-MongoDB-Project-Setup.webp 850w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/Build-tRPC-API-with-React.js-Node.js-MongoDB-Project-Setup-300x169.webp 300w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/Build-tRPC-API-with-React.js-Node.js-MongoDB-Project-Setup-768x432.webp 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/Build-tRPC-API-with-React.js-Node.js-MongoDB-Project-Setup-100x56.webp 100w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/Build-tRPC-API-with-React.js-Node.js-MongoDB-Project-Setup-700x394.webp 700w\" sizes=\"auto, (max-width: 850px) 100vw, 850px\" \/><\/figure>\n\n\n<style>.kb-table-of-content-nav.kb-table-of-content-id_c85589-60 .kb-table-of-content-wrap{padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;border-top:1px solid #abb8c3;border-right:1px solid #abb8c3;border-bottom:1px solid #abb8c3;border-left:1px solid #abb8c3;}.kb-table-of-content-nav.kb-table-of-content-id_c85589-60 .kb-table-of-contents-title-wrap{padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;}.kb-table-of-content-nav.kb-table-of-content-id_c85589-60 .kb-table-of-contents-title-wrap{color:#ffffff;}.kb-table-of-content-nav.kb-table-of-content-id_c85589-60 .kb-table-of-contents-title{color:#ffffff;font-weight:regular;font-style:normal;}.kb-table-of-content-nav.kb-table-of-content-id_c85589-60 .kb-table-of-content-wrap .kb-table-of-content-list{color:#ffffff;font-weight:regular;font-style:normal;margin-top:10px;margin-right:0px;margin-bottom:0px;margin-left:-5px;}@media all and (max-width: 1024px){.kb-table-of-content-nav.kb-table-of-content-id_c85589-60 .kb-table-of-content-wrap{border-top:1px solid #abb8c3;border-right:1px solid #abb8c3;border-bottom:1px solid #abb8c3;border-left:1px solid #abb8c3;}}@media all and (max-width: 767px){.kb-table-of-content-nav.kb-table-of-content-id_c85589-60 .kb-table-of-content-wrap{border-top:1px solid #abb8c3;border-right:1px solid #abb8c3;border-bottom:1px solid #abb8c3;border-left:1px solid #abb8c3;}}<\/style>\n\n\n<h2 class=\"wp-block-heading\">What is tRPC?<\/h2>\n\n\n\n<p><a href=\"https:\/\/trpc.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">tRPC<\/a> is a tool that leverages the full power of modern TypeScript to build end-to-end type-safety APIs with Node.js and Next.js without defining schemas. It allows us to share the Typescript types directly between the backend and the frontend without relying on code generation.<\/p>\n\n\n\n<p>Currently, GraphQL is the go-to library for building type-safety APIs to solve some of the downsides of RESTful APIs. However, since GraphQL is a query language, it doesn&#8217;t take full advantage of TypeScript to implement type-safety APIs.<\/p>\n\n\n\n<p>This is where <a href=\"https:\/\/trpc.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">tRPC<\/a> comes in, this tool uses the full power of Typescript to create a type-safe client and server by only using inference<\/p>\n\n\n\n<span id=\"ezoic-pub-video-placeholder-107\"><\/span>\n\n\n\n<h2 class=\"wp-block-heading\">Setup MongoDB and Redis with Docker-compose<\/h2>\n\n\n\n<p>MongoDB is an open-source NoSQL database management program that uses JSON-like documents called <a href=\"https:\/\/www.mongodb.com\/json-and-bson\" target=\"_blank\" rel=\"noreferrer noopener\">BSON<\/a> with optional schemas to store data.<\/p>\n\n\n\n<p>The quickest way to run the MongoDB database server on a machine is to use a Docker container so am going to assume you already have <a href=\"https:\/\/docs.docker.com\/get-docker\/\" target=\"_blank\" rel=\"noreferrer noopener\">Docker installed<\/a> on your machine.<\/p>\n\n\n\n<p>By default, Docker-compose is also installed along with Docker to allow you to run multiple containers using a <code>docker-compose.yaml<\/code> file.<\/p>\n\n\n\n<p>Create a new folder called <code>trpc-node-react<\/code> with your preferred local terminal and open the folder with your text editor of choice.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir trpc-node-react<\/code><\/pre>\n\n\n\n<p>In the root directory, create a <code>docker-compose.yml<\/code> file and add the following Docker configurations:<\/p>\n\n\n\n<p> <strong>docker-compose.yml<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\"><code>\nversion: '3.8'\nservices:\n  mongo:\n    image: mongo:latest\n    container_name: mongo\n    env_file:\n      - .\/.env\n    environment:\n      MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME}\n      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}\n      MONGO_INITDB_DATABASE: ${MONGO_INITDB_DATABASE}\n    volumes:\n      - mongo:\/data\/db\n    ports:\n      - '6000:27017'\n  redis:\n    image: redis:latest\n    container_name: redis\n    ports:\n      - '6379:6379'\n    volumes:\n      - redis:\/data\nvolumes:\n  mongo:\n  redis:\n\n<\/code>\n<\/pre>\n\n\n\n<p>The configurations above will allow us to run both the Redis and MongoDB servers on our machine.<\/p>\n\n\n\n<p>Now create a <code>.env<\/code> file in the root project to contain the credentials required by the Mongo Docker image to configure the MongoDB server.<\/p>\n\n\n\n<p><strong>.env<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\"><code>\nMONGO_INITDB_ROOT_USERNAME=admin\nMONGO_INITDB_ROOT_PASSWORD=password123\nMONGO_INITDB_DATABASE=trpc_mongodb\n<\/code>\n<\/pre>\n\n\n\n<p>With those configurations in place, run this command to start the Redis and MongoDB Docker containers:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker-compose up -d<\/code><\/pre>\n\n\n\n<p>Run this command to stop the containers:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker-compose down<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Setup a Monolithic Repository with Yarn Workspaces<\/h2>\n\n\n\n<p>To begin, let&#8217;s build a monorepo using Yarn. Yarn is a package manager developed and maintained by the folks at Facebook and it comes with a tool called&nbsp;<a href=\"https:\/\/yarnpkg.com\/lang\/en\/docs\/workspaces\/\" target=\"_blank\" rel=\"noopener\">Yarn workspaces<\/a> for organizing a project codebase using a monolithic repository aka monorepo.<\/p>\n\n\n\n<p>Create a <code>package.json<\/code> file in the root workspace:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>touch package.json<\/code><\/pre>\n\n\n\n<p>Add the following code to the newly-created&nbsp;<code>package.json<\/code>&nbsp;file:<\/p>\n\n\n\n<pre class=\"line-numbers language-json\"><code>\n{\n  \"name\": \"trpc-node-react\",\n  \"private\": \"true\",\n  \"scripts\": {},\n  \"workspaces\": [\n    \"packages\/*\"\n  ]\n}\n<\/code>\n<\/pre>\n\n\n\n<p>Since workspaces are not meant to be published, you need to make the package.json private to avoid accidentally publishing the root workspace.<\/p>\n\n\n\n<p>Also, we used a wildcard (*) in the &#8220;<strong>workspaces<\/strong>&#8221; property array to tell Yarn to include all the packages inside the&nbsp;&#8220;<em><strong>packages<\/strong><\/em>&#8221;&nbsp;folder.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Add a script to run both the tRPC client and server<\/h3>\n\n\n\n<p>Now we need a way to run both packages \u2014 the tRPC React client and the Node.js client simultaneously. For this example, we will use the&nbsp;<a href=\"https:\/\/www.npmjs.com\/package\/concurrently\" target=\"_blank\" rel=\"noopener\"><code>concurrently<\/code><\/a> and <code>wsrun<\/code> packages to run the start scripts of both packages in parallel.<\/p>\n\n\n\n<p>Add <code>concurrently<\/code> and <code>wsrun<\/code> to the root <strong>package.json<\/strong>:<\/p>\n\n\n\n<pre class=\"line-numbers language-js\"><code>\nyarn add -W -D concurrently wsrun\n<\/code>\n<\/pre>\n\n\n\n<p>Add this script to the root workspace&nbsp;<strong>package.json<\/strong> to run the start scripts of the tRPC client and server in parallel.<\/p>\n\n\n\n<p><strong>package.json<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-json\"><code>\n{\n  \"name\": \"trpc-node-react\",\n  \"private\": \"true\",\n  \"scripts\": {\n    \"start\": \"concurrently \\\"wsrun --parallel start\\\"\"\n  },\n  \"workspaces\": [\n    \"packages\/*\"\n  ],\n  \"devDependencies\": {\n    \"concurrently\": \"^7.2.2\",\n    \"wsrun\": \"^5.2.4\"\n  }\n}\n<\/code>\n<\/pre>\n\n\n\n<p>Create a <code>.gitignore<\/code> file in the root workspace and add the <strong>node_modules<\/strong> to exclude them from your commits.<\/p>\n\n\n\n<p><strong>.gitignore<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\"><code>\nnode_modules\n<\/code>\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Creating the Node.js tRPC Express Server<\/h2>\n\n\n\n<p>Now it&#8217;s time to set up the <strong>tRPC<\/strong> Express Node.js server. Create a folder named &#8220;<strong>server<\/strong>&#8221; inside the &#8220;<strong>packages<\/strong>&#8221; folder.<\/p>\n\n\n\n<p>Open the built-in terminal in your text editor and change the directory to the <code>packages\/server<\/code> folder:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd packages\/server<\/code><\/pre>\n\n\n\n<p>Run this command to initialize a Node.js Typescript project with Yarn:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn init -y &amp;&amp; yarn add -D typescript &amp;&amp; npx tsc --init \n<\/code>\n<\/pre>\n\n\n\n<p>Now replace the content of the newly-created &#8220;<strong>tsconfig.json<\/strong>&#8221; file with the following configurations:<\/p>\n\n\n\n<p><strong>packages\/server\/tsconfig.json<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-json\"><code>\n{\n  \"compilerOptions\": {\n    \"target\": \"es2018\",\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true,\n    \"module\": \"commonjs\",\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"strictPropertyInitialization\": false,\n    \"skipLibCheck\": true\n  }\n}\n<\/code>\n<\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>experimentalDecorators<\/code> &#8211; If set to &#8220;<strong>true<\/strong>&#8220;, <a href=\"https:\/\/github.com\/tc39\/proposal-decorators\" target=\"_blank\" rel=\"noreferrer noopener\">experimental support for decorators<\/a> will be enabled.<\/li>\n\n\n\n<li><code>emitDecoratorMetadata<\/code> &#8211; If set to &#8220;<strong>true<\/strong>&#8221; experimental support for emitting type metadata for the decorators will be enabled.<\/li>\n\n\n\n<li><code>strictPropertyInitialization<\/code> &#8211; If set to &#8220;<strong>false<\/strong>&#8220;, Typescript won&#8217;t raise errors when we declare the Typegoose class properties without initializing them in a constructor.<\/li>\n<\/ul>\n\n\n\n<p>Install the dependencies needed to set up the <strong>tRPC<\/strong> server with ExpressJs:<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn add @trpc\/server@next cors dotenv express mongoose redis &amp;&amp; yarn add -D @types\/express @types\/node @types\/cors morgan @types\/morgan ts-node-dev\n<\/code>\n<\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/@trpc\/server\" target=\"_blank\" rel=\"noreferrer noopener\">@trpc\/server<\/a><\/code> &#8211; for implementing <strong>tRPC<\/strong> endpoints and routers<\/li>\n\n\n\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/cors\" target=\"_blank\" rel=\"noreferrer noopener\">cors<\/a><\/code> &#8211; to allow the <strong>tRPC<\/strong> server to accept requests from cross-origin domains.<\/li>\n\n\n\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/dotenv\" target=\"_blank\" rel=\"noreferrer noopener\">dotenv<\/a><\/code> &#8211; to load the environment variables into the Node.js environment.<\/li>\n\n\n\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/express\" target=\"_blank\" rel=\"noreferrer noopener\">express<\/a><\/code> &#8211; a lightweight Node.js web application framework for building web and mobile applications.<\/li>\n\n\n\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/mongoose\" target=\"_blank\" rel=\"noreferrer noopener\">mongoose<\/a><\/code> &#8211; a library that uses schemas to define MongoDB models.<\/li>\n\n\n\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/redis\" target=\"_blank\" rel=\"noreferrer noopener\">redis<\/a><\/code> &#8211; a Node.js library for interacting with a Redis server<\/li>\n\n\n\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/ts-node-dev\" target=\"_blank\" rel=\"noreferrer noopener\">ts-node-dev<\/a><\/code> &#8211; to hot-reload the <strong>tRPC<\/strong> Express server.<\/li>\n\n\n\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/morgan\" target=\"_blank\" rel=\"noreferrer noopener\">morgan<\/a><\/code> &#8211; for logging HTTP requests in the terminal<\/li>\n<\/ul>\n\n\n\n<p>Since the security of the <strong>tRPC<\/strong> application is really important to us, create a <code>.env<\/code> file in the <code>packages\/server<\/code> folder and add the following data.<\/p>\n\n\n\n<pre class=\"line-numbers language-js\"><code>\nNODE_ENV=development\n\nORIGIN=http:\/\/localhost:3000\n\nMONGODB_URI=mongodb:\/\/admin:password123@localhost:6000\/trpc_mongodb?authSource=admin\n<\/code>\n<\/pre>\n\n\n\n<p>Add the start script to the <code>packages\/server\/package.json<\/code> file to initialize the <strong>tRPC<\/strong> Express server.<\/p>\n\n\n\n<p><strong>packages\/server\/package.json<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\"><code>\n{\n\"scripts\": {\n    \"start\": \"ts-node-dev --respawn --transpile-only src\/app.ts\"\n  }\n}\n<\/code>\n<\/pre>\n\n\n\n<p>In the <code>packages\/server<\/code> folder, create an &#8220;<strong>src<\/strong>&#8221; folder, and within the &#8220;<strong>src<\/strong>&#8221; folder create a &#8220;<strong>config<\/strong>&#8221; and &#8220;<strong>utils<\/strong>&#8221; folders.<\/p>\n\n\n\n<p>Now create <code>default.ts<\/code> file in the &#8220;<strong>config<\/strong>&#8221; folder to import and export the environment variables we stored in the <code>packages\/server\/.env<\/code> file.<\/p>\n\n\n\n<p><strong>packages\/server\/src\/config\/default.ts<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-ts\"><code>\nimport path from 'path';\nrequire('dotenv').config({ path: path.join(__dirname, '..\/..\/.env') });\n\nconst customConfig: { port: number; origin: string; dbUri: string } = {\n  port: 8000,\n  origin: process.env.ORIGIN as unknown as string,\n\n  dbUri: process.env.MONGODB_URI as unknown as string,\n};\n\nexport default customConfig;\n\n<\/code>\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Connect the tRPC Server to Redis and MongoDB<\/h3>\n\n\n\n<p>Now that we have the Redis and MongoDB servers running in the Docker containers, let&#8217;s create some helper functions to connect them to the <strong>tRPC<\/strong> application.<\/p>\n\n\n\n<p><strong>packages\/server\/src\/utils\/connectDB.ts<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-ts\"><code>\nimport mongoose from 'mongoose';\nimport customConfig from '..\/config\/default';\n\nconst dbUrl = customConfig.dbUri;\n\nconst connectDB = async () =&gt; {\n  try {\n    await mongoose.connect(dbUrl);\n    console.log('? Database connected...');\n  } catch (error: any) {\n    console.log(error);\n    process.exit(1);\n  }\n};\n\nexport default connectDB;\n<\/code>\n<\/pre>\n\n\n\n<p><strong>packages\/server\/src\/utils\/connectRedis.ts<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-ts\"><code>\nimport { createClient } from 'redis';\n\nconst redisUrl = `redis:\/\/localhost:6379`;\nconst redisClient = createClient({\n  url: redisUrl,\n});\n\nconst connectRedis = async () =&gt; {\n  try {\n    await redisClient.connect();\n    console.log('? Redis client connected...');\n    redisClient.set(\n      'tRPC',\n      '??Welcome to rRPC with React.js, Express and Typescript!'\n    );\n  } catch (err: any) {\n    console.log(err.message);\n    process.exit(1);\n  }\n};\n\nconnectRedis();\n\nredisClient.on('error', (err) =&gt; console.log(err));\n\nexport default redisClient;\n<\/code>\n<\/pre>\n\n\n\n<p>In the above code, we evoked the <code>redisClient.set()<\/code> method available on the Redis client instance to add a message to the Redis database with a &#8220;<strong>tRPC<\/strong>&#8221; key.<\/p>\n\n\n\n<p>Later, we will retrieve that message from the Redis database and return it to the &#8220;<strong>tRPC<\/strong>&#8221; client.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Initialize the tRPC Express Server<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Create the tRPC Context<\/h4>\n\n\n\n<p>Let&#8217;s create an app context that will be generated for every incoming request and the results will be propagated to all the resolvers. This will enable us to pass down contextual data to our resolvers.<\/p>\n\n\n\n<p><strong>packages\/server\/src\/app.ts<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-ts\"><code>\nimport path from &quot;path&quot;;\nimport dotenv from &quot;dotenv&quot;;\nimport express from &quot;express&quot;;\nimport morgan from &quot;morgan&quot;;\nimport cors from &quot;cors&quot;;\nimport * as trpcExpress from &quot;@trpc\/server\/adapters\/express&quot;;\nimport connectDB from &quot;.\/utils\/connectDB&quot;;\nimport redisClient from &quot;.\/utils\/connectRedis&quot;;\nimport customConfig from &quot;.\/config\/default&quot;;\nimport { inferAsyncReturnType, initTRPC } from &quot;@trpc\/server&quot;;\n\ndotenv.config({ path: path.join(__dirname, &quot;.\/.env&quot;) });\n\nconst createContext = ({\n  req,\n  res,\n}: trpcExpress.CreateExpressContextOptions) =&gt; ({ req, res });\n\nexport type Context = inferAsyncReturnType&lt;typeof createContext&gt;;\n\/\/ [...]\n<\/code>\n<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Create the tRPC Router<\/h4>\n\n\n\n<p>Now let&#8217;s create a router to enable us to manage the <strong>tRPC<\/strong> endpoints. With the router defined, we can add:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Query routes &#8211; for fetching data <\/li>\n\n\n\n<li>Mutation routes &#8211; for modifying data (<strong>Create<\/strong>, <strong>Update <\/strong>and <strong>Delete<\/strong> data)<\/li>\n\n\n\n<li>Subscription routes &#8211; allows us to subscribe to data over WebSockets.<\/li>\n<\/ul>\n\n\n\n<p><strong>packages\/server\/src\/app.ts<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-ts\"><code>\n\/\/ [...]\nconst t = initTRPC.context&lt;Context&gt;().create();\n\nconst appRouter = t.router({\n  sayHello: t.procedure.query(async () =&gt; {\n    const message = await redisClient.get(&quot;tRPC&quot;);\n    return { message };\n  }),\n});\n\nexport type AppRouter = typeof appRouter;\n<\/code>\n<\/pre>\n\n\n\n<p>Here we initialized the tRPC server by calling the <code>.context&lt;Context&gt;()<\/code> and <code>.create()<\/code> methods on <code>initTRPC<\/code> . Then, we create a new tRPC router and added a <strong>sayHello<\/strong> query procedure call. The <strong>sayHello<\/strong> procedure will be evoked by the tRPC client to return the message we stored in the Redis database.<\/p>\n\n\n\n<p>Lastly, we exposed the <code>AppRouter<\/code> typescript type to enable the React client to know the different queries, mutations, and subscriptions available on the <strong>tRPC<\/strong> server.<\/p>\n\n\n\n<p>AppRouter maintains all the routes, what the routes take as inputs, and what the routes return as outputs.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Start the Express tRPC Server<\/h4>\n\n\n\n<p><strong>packages\/server\/src\/app.ts<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-ts\"><code>\n\/\/ [...]\nconst app = express();\nif (process.env.NODE_ENV !== &quot;production&quot;) app.use(morgan(&quot;dev&quot;));\n\napp.use(\n  cors({\n    origin: [customConfig.origin, &quot;http:\/\/localhost:3000&quot;],\n    credentials: true,\n  })\n);\napp.use(\n  &quot;\/api\/trpc&quot;,\n  trpcExpress.createExpressMiddleware({\n    router: appRouter,\n    createContext,\n  })\n);\n\nconst port = customConfig.port;\napp.listen(port, () =&gt; {\n  console.log(`\ud83d\ude80 Server listening on port ${port}`);\n\n  \/\/ CONNECT DB\n  connectDB();\n});\n<\/code>\n<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Complete Express tRPC Server<\/h4>\n\n\n\n<p><strong>packages\/server\/src\/app.ts<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-ts\"><code>\nimport path from &quot;path&quot;;\nimport dotenv from &quot;dotenv&quot;;\nimport express from &quot;express&quot;;\nimport morgan from &quot;morgan&quot;;\nimport cors from &quot;cors&quot;;\nimport * as trpcExpress from &quot;@trpc\/server\/adapters\/express&quot;;\nimport connectDB from &quot;.\/utils\/connectDB&quot;;\nimport redisClient from &quot;.\/utils\/connectRedis&quot;;\nimport customConfig from &quot;.\/config\/default&quot;;\nimport { inferAsyncReturnType, initTRPC } from &quot;@trpc\/server&quot;;\n\ndotenv.config({ path: path.join(__dirname, &quot;.\/.env&quot;) });\n\nconst createContext = ({\n  req,\n  res,\n}: trpcExpress.CreateExpressContextOptions) =&gt; ({ req, res });\n\nexport type Context = inferAsyncReturnType&lt;typeof createContext&gt;;\n\nconst t = initTRPC.context&lt;Context&gt;().create();\n\nconst appRouter = t.router({\n  sayHello: t.procedure.query(async () =&gt; {\n    const message = await redisClient.get(&quot;tRPC&quot;);\n    return { message };\n  }),\n});\n\nexport type AppRouter = typeof appRouter;\n\nconst app = express();\nif (process.env.NODE_ENV !== &quot;production&quot;) app.use(morgan(&quot;dev&quot;));\n\napp.use(\n  cors({\n    origin: [customConfig.origin, &quot;http:\/\/localhost:3000&quot;],\n    credentials: true,\n  })\n);\napp.use(\n  &quot;\/api\/trpc&quot;,\n  trpcExpress.createExpressMiddleware({\n    router: appRouter,\n    createContext,\n  })\n);\n\nconst port = customConfig.port;\napp.listen(port, () =&gt; {\n  console.log(`\ud83d\ude80 Server listening on port ${port}`);\n\n  \/\/ CONNECT DB\n  connectDB();\n});\n<\/code>\n<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Turn the tRPC Express App into a Library<\/h4>\n\n\n\n<p>Add a <code>\"main\": \"src\/app.ts\"<\/code> to the <code>packages\/server\/package.json<\/code> to turn the <strong>tRPC<\/strong> server into a library. This will allow us to connect both the <strong>tRPC<\/strong> React.js client to the Node.js server. <\/p>\n\n\n\n<p><strong>packages\/server\/package.json<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"829\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/turn-tRPC-server-to-a-library-1024x829.png\" alt=\"turn tRPC server to a library\" class=\"wp-image-4227\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/turn-tRPC-server-to-a-library-1024x829.png 1024w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/turn-tRPC-server-to-a-library-300x243.png 300w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/turn-tRPC-server-to-a-library-768x622.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/turn-tRPC-server-to-a-library-100x81.png 100w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/turn-tRPC-server-to-a-library-556x450.png 556w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/turn-tRPC-server-to-a-library.png 1125w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><strong>packages\/server\/package.json<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-json\"><code>\n{\n  \"name\": \"server\",\n  \"version\": \"1.0.0\",\n  \"main\": \"src\/app.ts\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"start\": \"ts-node-dev --respawn --transpile-only src\/app.ts\"\n  },\n  \"dependencies\": {\n    \"@trpc\/server\": \"^10.0.0-proxy-beta.26\",\n    \"cors\": \"^2.8.5\",\n    \"dotenv\": \"^16.0.3\",\n    \"express\": \"^4.18.2\",\n    \"mongoose\": \"^6.7.0\",\n    \"redis\": \"^4.3.1\"\n  },\n  \"devDependencies\": {\n    \"@types\/cors\": \"^2.8.12\",\n    \"@types\/morgan\": \"^1.9.3\",\n    \"morgan\": \"^1.10.0\",\n    \"ts-node-dev\": \"^2.0.0\",\n    \"typescript\": \"^4.8.4\"\n  }\n}\n\n<\/code>\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Creating the React.js tRPC Client<\/h2>\n\n\n\n<p>First and foremost, change the directory <code>cd<\/code> into the &#8220;<strong>packages<\/strong>&#8221; folder to enable us to generate a basic React.js app with &#8220;<a href=\"https:\/\/create-react-app.dev\/\" target=\"_blank\" rel=\"noreferrer noopener\">create-react-app<\/a>&#8220;.<\/p>\n\n\n\n<p>Run this command to create a React.js boilerplate app in a <code>packages\/client<\/code> folder.<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn create react-app client --template typescript\n<\/code><\/pre>\n\n\n\n<p>Replace the content of the <code>packages\/client\/tsconfig.json<\/code> file with the following:<\/p>\n\n\n\n<pre class=\"line-numbers language-json\"><code>\n{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\"\n  },\n  \"include\": [\"src\"]\n}\n\n<\/code><\/pre>\n\n\n\n<p>Now let&#8217;s connect the <strong>tRPC<\/strong> server to the React client by installing the API server as a library on the client.<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn add server@1.0.0\n<\/code><\/pre>\n\n\n\n<p>Where &#8220;<strong>server<\/strong>&#8221; is the property name in the <code>packages\/server\/package.json<\/code> file and the &#8220;<strong>@1.0.0<\/strong>&#8221; is the version provided in it. This will enable the React.js app to import the <code>AppRouter<\/code> type we exported from the <strong>tRPC<\/strong> server.<\/p>\n\n\n\n<p>Next, install the dependencies required to set up the <strong>tRPC<\/strong> Client<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn add @trpc\/client@next @trpc\/server@next @trpc\/react-query@next @tanstack\/react-query\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code><a href=\"https:\/\/react-query.tanstack.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">react-query<\/a><\/code> &#8211; a library for managing server state<\/li>\n\n\n\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/@trpc\/react\" target=\"_blank\" rel=\"noopener\">@trpc\/react<\/a><\/code> &#8211; is  a thin wrapper around React Query<\/li>\n\n\n\n<li><code><a href=\"https:\/\/www.npmjs.com\/package\/@trpc\/client\" target=\"_blank\" rel=\"noreferrer noopener\">@trpc\/client<\/a><\/code> &#8211; for creating the <strong>tRPC<\/strong> client<\/li>\n\n\n\n<li><code>@trpc\/server<\/code> &#8211; It&#8217;s a peer dependency of <code>@trpc\/client<\/code> .<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Create the tRPC Client<\/h3>\n\n\n\n<p>Now let&#8217;s create the React Query hooks that are specific to our API server with the <code>createTRPCReact()<\/code> provided by <code>@trpc\/react-query<\/code> binding.<\/p>\n\n\n\n<p><strong>packages\/client\/src\/trpc.ts<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-ts\"><code>\nimport { createTRPCReact } from &quot;@trpc\/react-query&quot;;\nimport type { AppRouter } from &quot;server&quot;;\n\nexport const trpc = createTRPCReact&lt;AppRouter&gt;();\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Calling our tRPC API Endpoint<\/h3>\n\n\n\n<p>Now let&#8217;s configure the React.js client with <strong>tRPC<\/strong> and <strong>React Query<\/strong> before making our first <strong>tRPC<\/strong> request to our API server.<\/p>\n\n\n\n<p><strong>packages\/client\/src\/App.tsx<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-tsx\"><code>\nimport { useState } from &quot;react&quot;;\nimport { QueryClientProvider, QueryClient } from &quot;@tanstack\/react-query&quot;;\nimport { ReactQueryDevtools } from &quot;@tanstack\/react-query-devtools&quot;;\nimport { getFetch, httpBatchLink, loggerLink } from &quot;@trpc\/client&quot;;\nimport { trpc } from &quot;.\/trpc&quot;;\n\nfunction AppContent() {\n  const hello = trpc.sayHello.useQuery();\n  return &lt;main className=&quot;p-2&quot;&gt;{JSON.stringify(hello.data, null, 2)}&lt;\/main&gt;;\n}\n\nfunction App() {\n  const [queryClient] = useState(\n    () =&gt;\n      new QueryClient({\n        defaultOptions: {\n          queries: {\n            staleTime: 5 * 1000,\n          },\n        },\n      })\n  );\n\n  const [trpcClient] = useState(() =&gt;\n    trpc.createClient({\n      links: [\n        loggerLink(),\n        httpBatchLink({\n          url: &quot;http:\/\/localhost:8000\/api\/trpc&quot;,\n          fetch: async (input, init?) =&gt; {\n            const fetch = getFetch();\n            return fetch(input, {\n              ...init,\n              credentials: &quot;include&quot;,\n            });\n          },\n        }),\n      ],\n    })\n  );\n  return (\n    &lt;trpc.Provider client={trpcClient} queryClient={queryClient}&gt;\n      &lt;QueryClientProvider client={queryClient}&gt;\n        &lt;AppContent \/&gt;\n        &lt;ReactQueryDevtools initialIsOpen={false} \/&gt;\n      &lt;\/QueryClientProvider&gt;\n    &lt;\/trpc.Provider&gt;\n  );\n}\n\nexport default App;\n<\/code><\/pre>\n\n\n\n<p>Change directory into the root Yarn workspace and  run <code>yarn start<\/code> to start the <strong>tRPC<\/strong> client and server.<\/p>\n\n\n\n<p>You should see the message we stored in the Redis database in the browser.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"885\" height=\"1024\" src=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/tRPC-server-and-client-Redis-message-885x1024.png\" alt=\"tRPC server and client Redis message\" class=\"wp-image-4240\" srcset=\"https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/tRPC-server-and-client-Redis-message-885x1024.png 885w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/tRPC-server-and-client-Redis-message-259x300.png 259w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/tRPC-server-and-client-Redis-message-768x889.png 768w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/tRPC-server-and-client-Redis-message-86x100.png 86w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/tRPC-server-and-client-Redis-message-389x450.png 389w, https:\/\/codevoweb.com\/wp-content\/uploads\/2022\/07\/tRPC-server-and-client-Redis-message.png 933w\" sizes=\"auto, (max-width: 885px) 100vw, 885px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Setup tailwindCss with the React.js tRPC Client<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Install tailwindCss and its dependencies<\/h4>\n\n\n\n<p> Now change the directory to the <code>packages\/client<\/code> folder and install tailwindCss and its peer dependencies via Yarn.<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nyarn add -D tailwindcss postcss autoprefixer\n<\/code><\/pre>\n\n\n\n<p>Run the init command to generate the <code>tailwind.config.js<\/code> and <code>postcss.config.js<\/code> files in the <code>packages\/client<\/code> folder.<\/p>\n\n\n\n<pre class=\"line-numbers language-shell\"><code>\nnpx tailwindcss init -p\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Add the Template Paths to the Configuration File<\/h4>\n\n\n\n<p>Next, add the paths to the template files in the&nbsp;<code>tailwind.config.js<\/code>&nbsp;file, and also, remember to include your custom colors and fonts.<\/p>\n\n\n\n<p><strong>packages\/client\/tailwind.config.js<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-js\"><code>\n\/** @type {import('tailwindcss').Config} *\/\nmodule.exports = {\n  content: ['.\/src\/**\/*.{js,jsx,ts,tsx}'],\n  theme: {\n    extend: {\n      colors: {\n        'ct-dark-600': '#222',\n        'ct-dark-200': '#e5e7eb',\n        'ct-dark-100': '#f5f6f7',\n        'ct-blue-600': '#2363eb',\n        'ct-yellow-600': '#f9d13e',\n      },\n      container: {\n        center: true,\n        padding: '1rem',\n        screens: {\n          lg: '1125px',\n          xl: '1125px',\n          '2xl': '1125px',\n        },\n      },\n    },\n  },\n  plugins: [],\n};\n\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Add the tailwindCss directives to your CSS<\/h4>\n\n\n\n<p>Create a&nbsp;<code>.\/packages\/client\/src\/global.css<\/code>&nbsp;file and add the&nbsp;<code>@tailwind<\/code>&nbsp;directives. You also need to include your custom font to override the default font that comes with TailwindCSS.<\/p>\n\n\n\n<p><strong>packages\/client\/src\/global.css<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-css\"><code>\n@import url('https:\/\/fonts.googleapis.com\/css2?family=Poppins:wght@300;400;500;600;700&amp;display=swap');\n\n@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n  html {\n    font-family: 'Poppins', sans-serif;\n  }\n}\n\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Import the CSS file<\/h4>\n\n\n\n<p>Now, import the newly-created&nbsp;<code>packages\/client\/src\/global.css<\/code>&nbsp;file into the&nbsp;<code>packages\/client\/src\/index.tsx<\/code>&nbsp;file.<\/p>\n\n\n\n<p><strong>packages\/client\/src\/index.tsx<\/strong><\/p>\n\n\n\n<pre class=\"line-numbers language-ts\"><code>\nimport React from 'react';\nimport ReactDOM from 'react-dom\/client';\nimport App from '.\/App';\nimport '.\/global.css';\nconst root = ReactDOM.createRoot(\n  document.getElementById('root') as HTMLElement\n);\nroot.render(\n  &lt;react.strictmode&gt;\n    &lt;app&gt;\n  &lt;\/react.strictmode&gt;\n);\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Congrats on reaching the end. In this comprehensive article, you&#8217;ve learned how to set up <strong>tRPC<\/strong> with React.js, Node.js, Redis, and MongoDB.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">tRPC Client and Server Project Setup Source Code<\/h2>\n\n\n\n<p>You can find the complete <a href=\"https:\/\/github.com\/wpcodevo\/trpc-react-node-mongodb\/tree\/trpc-node-react-setup\" target=\"_blank\" rel=\"noreferrer noopener\">source code on GitHub<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>tRPC aka t3-stack is a light library for building end-to-end typesafe APIs for Next.js and Node apps without writing schemas or installing libraries for code&#8230;<\/p>\n","protected":false},"author":1,"featured_media":4248,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[54,47],"tags":[42,56,55],"class_list":["post-4174","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-react","category-nodejs","tag-nodejs-api","tag-react","tag-reactjs"],"acf":[],"_links":{"self":[{"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/posts\/4174","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/comments?post=4174"}],"version-history":[{"count":1,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/posts\/4174\/revisions"}],"predecessor-version":[{"id":11297,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/posts\/4174\/revisions\/11297"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/media\/4248"}],"wp:attachment":[{"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/media?parent=4174"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/categories?post=4174"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codevoweb.com\/wp-json\/wp\/v2\/tags?post=4174"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}