{"id":23955,"date":"2022-11-17T10:25:56","date_gmt":"2022-11-17T18:25:56","guid":{"rendered":"https:\/\/coderpad.io\/?p=23955"},"modified":"2023-06-05T13:50:36","modified_gmt":"2023-06-05T20:50:36","slug":"how-to-build-a-web-application-with-typescript-and-remix","status":"publish","type":"post","link":"https:\/\/coderpad.io\/blog\/development\/how-to-build-a-web-application-with-typescript-and-remix\/","title":{"rendered":"How To Build A Web Application with TypeScript and Remix"},"content":{"rendered":"\n<p>Remix is a full-stack web framework that focuses on the user interface and works backwards through web standards to provide a quick, slick, and dependable user experience. It focuses on web standards and modern web app UX, allowing you to create better websites quickly. In addition, it can run anywhere because it is built on the Web Fetch API.\u00a0<\/p>\n\n\n\n<p>Remix runs natively on Cloudflare Workers and includes support for both serverless and traditional Node.js environments. In addition, it was designed to address web applications&#8217; page speed issues to provide a better user experience.<\/p>\n\n\n\n<p>In this article, you&#8217;ll learn the Remix framework and how to use it by building a full-stack web application using Remix and TypeScript.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Prerequisites<\/strong><\/h2>\n\n\n\n<p>To get the best out of this tutorial, ensure you have met the following requirements:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/nodejs.org\/en\/\" target=\"_blank\" rel=\"noopener\">Node.js<\/a> version 14 or later installed<\/li>\n\n\n\n<li><a href=\"https:\/\/www.postgresql.org\/\" target=\"_blank\" rel=\"noopener\">PostgreSQL<\/a> database installed<\/li>\n\n\n\n<li>Knowledge of<a href=\"https:\/\/www.typescriptlang.org\/\" target=\"_blank\" rel=\"noopener\"> TypeScript<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Setting up a new Remix project<\/strong><\/h2>\n\n\n\n<p>With the above requirements met, proceed to set up a new Remix project by running the command below in your terminal:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">$ npx create-remix@latest<\/code><\/span><\/pre>\n\n\n<p>The command above will prompt you to choose the configurations for the project. First, you&#8217;ll call our app <code>task-app<\/code>, choose <strong>Just the basics<\/strong>, then the <strong>Remix App Server<\/strong> deploy target, use <strong>TypeScript<\/strong>, and have it run the installation for you.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/11\/img_63767cb479d19.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Installation prompt from the <code>npx create-remix@latest<\/code> command.<\/figcaption><\/figure>\n\n\n\n<p>After the installation is complete, the command will create the following folder structures below:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\">\ud83d\udce6<span class=\"hljs-selector-tag\">task-app<\/span>\n\n\u2523 \ud83d\udcc2<span class=\"hljs-selector-tag\">app<\/span>\n\n\u2503 \u2523 \ud83d\udcc2<span class=\"hljs-selector-tag\">routes<\/span>\n\n\u2503 \u2503 \u2517 \ud83d\udcdc<span class=\"hljs-selector-tag\">index<\/span><span class=\"hljs-selector-class\">.tsx<\/span>\n\n\u2503 \u2523 \ud83d\udcdc<span class=\"hljs-selector-tag\">entry<\/span><span class=\"hljs-selector-class\">.client<\/span><span class=\"hljs-selector-class\">.tsx<\/span>\n\n\u2503 \u2523 \ud83d\udcdc<span class=\"hljs-selector-tag\">entry<\/span><span class=\"hljs-selector-class\">.server<\/span><span class=\"hljs-selector-class\">.tsx<\/span>\n\n\u2503 \u2517 \ud83d\udcdc<span class=\"hljs-selector-tag\">root<\/span><span class=\"hljs-selector-class\">.tsx<\/span>\n\n\u2523 \ud83d\udcc2<span class=\"hljs-selector-tag\">public<\/span>\n\n\u2503 \u2517 \ud83d\udcdc<span class=\"hljs-selector-tag\">favicon<\/span><span class=\"hljs-selector-class\">.ico<\/span>\n\n\u2523 \ud83d\udcdc<span class=\"hljs-selector-class\">.eslintrc<\/span><span class=\"hljs-selector-class\">.js<\/span>\n\n\u2523 \ud83d\udcdc<span class=\"hljs-selector-class\">.gitignore<\/span>\n\n\u2523 \ud83d\udcdc<span class=\"hljs-selector-tag\">README<\/span><span class=\"hljs-selector-class\">.md<\/span>\n\n\u2523 \ud83d\udcdc<span class=\"hljs-selector-tag\">package<\/span><span class=\"hljs-selector-class\">.json<\/span>\n\n\u2523 \ud83d\udcdc<span class=\"hljs-selector-tag\">remix<\/span><span class=\"hljs-selector-class\">.config<\/span><span class=\"hljs-selector-class\">.js<\/span>\n\n\u2523 \ud83d\udcdc<span class=\"hljs-selector-tag\">remix<\/span><span class=\"hljs-selector-class\">.env<\/span><span class=\"hljs-selector-class\">.d<\/span><span class=\"hljs-selector-class\">.ts<\/span>\n\n\u2517 \ud83d\udcdc<span class=\"hljs-selector-tag\">tsconfig<\/span><span class=\"hljs-selector-class\">.json<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now run the application locally on a computer with the command <code>npm run dev<\/code> and navigate to <a href=\"http:\/\/localhost:3001\/\" target=\"_blank\" rel=\"noopener\">http:\/\/localhost:300<\/a><strong> <\/strong>on your browser.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/11\/img_63767cb5de885.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">The Remix framework&#8217;s welcome page.<\/figcaption><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Connect to a database<\/strong><\/h2>\n\n\n\n<p>Now, let&#8217;s connect your application to a database to allow you to save the user&#8217;s record. First, we&#8217;ll combine the application with a PostgreSQL database using the Prisma ORM. To get started, you&#8217;ll need to install the Prisma package in your project by running the commands below.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">$ npm install Prisma --save-dev<\/code><\/span><\/pre>\n\n\n<p>Then initialize Prisma using the CLI tool by running the command below:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">$ npx prisma init --datasource-provider postgresql<\/code><\/span><\/pre>\n\n\n<p>The above command will create a new Prisma directory in the project root folder with a Prisma schema file and configures PostgreSQL as your database with some dummy credentials. First, you&#8217;ll need to update <code>DATABASE_URL<\/code> in the .env file created by the prisma command with your database credentials.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Create schema<\/strong><\/h2>\n\n\n\n<p>With the database configurations all set up, let&#8217;s create a schema to define how the data stored in our database will be organized. To do that, open the <code>Prisma\/schema.prisma<\/code> file and replace the code with the code snippets below.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ This is your Prisma schema file,<\/span>\n<span class=\"hljs-comment\">\/\/ learn more about it in the docs: https:\/\/pris.ly\/d\/prisma-schema<\/span>\n\ngenerator client {\n  provider = <span class=\"hljs-string\">\"Prisma-client-js\"<\/span>\n}\n\ndata source DB {\n  provider = <span class=\"hljs-string\">\"PostgreSQL\"<\/span>\n  URL      = env(<span class=\"hljs-string\">\"DATABASE_URL\"<\/span>)\n}\n\nmodel Task {\n  id        <span class=\"hljs-built_in\">String<\/span>  <span class=\"hljs-meta\">@id<\/span> <span class=\"hljs-meta\">@default<\/span>(UUID())\n  name      <span class=\"hljs-built_in\">String<\/span>\n  completed <span class=\"hljs-built_in\">Boolean<\/span>\n  createdAt DateTime <span class=\"hljs-meta\">@default<\/span>(now())\n  updatedAt DateTime <span class=\"hljs-meta\">@updatedAt<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In the code snippet above, we define a <code>Task<\/code> schema with the fields we want in our task table in our database. The <code>id<\/code> field will be a randomly generated string achieved using the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Universally_unique_identifier\" target=\"_blank\" rel=\"noopener\">UUID<\/a> library. We have the <code>name<\/code> field, which is also a string, a <code>completed<\/code> field to know the task\u2019s status, a boolean, and <code>createAt<\/code> and <code>UpdateAt<\/code> fields to keep track of when the task was created and updated.<\/p>\n\n\n\n<p>Now let&#8217;s run a migration to create a database table from the schema you define with the command below.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">$ npx Prisma migrate dev --name init<\/code><\/span><\/pre>\n\n\n<p>The above command will create a new SQL migration file in the <code>prisma\/migrations<\/code> directory and run the SQL migration file against the database. At this point, your database is set for use.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Create application components<\/strong><\/h2>\n\n\n\n<p>Components in Remix have been created in the <code>app<\/code> folder in the <code>routes<\/code> directory. Inside the routes folder, you can create the components for your application.\u00a0<\/p>\n\n\n\n<p>By default, Remix creates an <code>index.ts<\/code> file with an <code>Index<\/code> component. This component is rendered when you visit the root URL of the web application. Since we are only causing the tasks in the application, we&#8217;ll update the <code>routes\/index.ts<\/code> file with the code snippet below.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Index<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"task-tab\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h4<\/span>&gt;<\/span>Task List<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h4<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">hr<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">action<\/span>=<span class=\"hljs-string\">\"\"<\/span> <span class=\"hljs-attr\">method<\/span>=<span class=\"hljs-string\">\"POST\"<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"form\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"name\"<\/span> \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span>&gt;<\/span>Add<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"task-list\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Task 1<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"checkbox\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"brand\"<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"\"<\/span> \/&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\"><strong>Style the application<\/strong><\/h2>\n\n\n\n<p>To make the application look appealing, you need to add some styling to the application. We&#8217;ll create a custom style and export at route layout boundaries (<code>root.ts<\/code> file) in the route function in the links export function. Create a <code>styles<\/code> directory in the <code>app<\/code> folder to get started.\u00a0<\/p>\n\n\n\n<p>In the styles directory, create a <code>global.css<\/code> file and add the following:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\">* {\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">0px<\/span>;\n  <span class=\"hljs-attribute\">margin<\/span>: <span class=\"hljs-number\">0px<\/span>;\n  <span class=\"hljs-attribute\">box-sizing<\/span>: border-box;\n  <span class=\"hljs-attribute\">font-family<\/span>: Verdana, Geneva, Tahoma, sans-serif;\n}\n<span class=\"hljs-selector-class\">.container<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">align-items<\/span>: center;\n  <span class=\"hljs-attribute\">justify-content<\/span>: center;\n  <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">100vh<\/span>;\n}\n<span class=\"hljs-selector-class\">.container<\/span> <span class=\"hljs-selector-class\">.task-tab<\/span> {\n  <span class=\"hljs-attribute\">box-shadow<\/span>: <span class=\"hljs-built_in\">rgba<\/span>(<span class=\"hljs-number\">50<\/span>, <span class=\"hljs-number\">50<\/span>, <span class=\"hljs-number\">93<\/span>, <span class=\"hljs-number\">0.25<\/span>) <span class=\"hljs-number\">0px<\/span> <span class=\"hljs-number\">13px<\/span> <span class=\"hljs-number\">27px<\/span> -<span class=\"hljs-number\">5px<\/span>,\n    <span class=\"hljs-built_in\">rgba<\/span>(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0.3<\/span>) <span class=\"hljs-number\">0px<\/span> <span class=\"hljs-number\">8px<\/span> <span class=\"hljs-number\">16px<\/span> -<span class=\"hljs-number\">8px<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">20px<\/span>;\n}\n<span class=\"hljs-selector-class\">.container<\/span> <span class=\"hljs-selector-class\">.task-tab<\/span> <span class=\"hljs-selector-tag\">h4<\/span> {\n  <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">5px<\/span>;\n  <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">25px<\/span>;\n}\n\n<span class=\"hljs-selector-class\">.container<\/span> <span class=\"hljs-selector-class\">.task-tab<\/span> <span class=\"hljs-selector-class\">.form<\/span> {\n  <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">400px<\/span>;\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">margin-top<\/span>: <span class=\"hljs-number\">5px<\/span>;\n}\n\n<span class=\"hljs-selector-class\">.container<\/span> <span class=\"hljs-selector-class\">.task-tab<\/span> <span class=\"hljs-selector-class\">.form<\/span> <span class=\"hljs-selector-tag\">button<\/span> {\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">10px<\/span>;\n  <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">1px<\/span> solid <span class=\"hljs-built_in\">rgb<\/span>(<span class=\"hljs-number\">217<\/span>, <span class=\"hljs-number\">217<\/span>, <span class=\"hljs-number\">217<\/span>);\n  <span class=\"hljs-attribute\">border-left<\/span>: <span class=\"hljs-number\">0px<\/span>;\n}\n<span class=\"hljs-selector-class\">.container<\/span> <span class=\"hljs-selector-class\">.task-tab<\/span> <span class=\"hljs-selector-class\">.form<\/span> <span class=\"hljs-selector-tag\">input<\/span> {\n  <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">10px<\/span>;\n  <span class=\"hljs-attribute\">outline<\/span>: none;\n  <span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">1px<\/span> solid <span class=\"hljs-built_in\">RGB<\/span>(<span class=\"hljs-number\">217<\/span>, <span class=\"hljs-number\">217<\/span>, <span class=\"hljs-number\">217<\/span>);\n  <span class=\"hljs-attribute\">border-right<\/span>: <span class=\"hljs-number\">0px<\/span>;\n}\n<span class=\"hljs-selector-class\">.container<\/span> <span class=\"hljs-selector-class\">.task-list<\/span> <span class=\"hljs-selector-tag\">ul<\/span> <span class=\"hljs-selector-tag\">li<\/span> {\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">10px<\/span>;\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">justify-content<\/span>: space-between;\n  <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-built_in\">rgb<\/span>(<span class=\"hljs-number\">230<\/span>, <span class=\"hljs-number\">235<\/span>, <span class=\"hljs-number\">235<\/span>);\n  <span class=\"hljs-attribute\">margin-top<\/span>: <span class=\"hljs-number\">10px<\/span>;\n  <span class=\"hljs-attribute\">margin-bottom<\/span>: <span class=\"hljs-number\">10px<\/span>;\n}\n<span class=\"hljs-selector-class\">.container<\/span> <span class=\"hljs-selector-class\">.task-list<\/span> <span class=\"hljs-selector-tag\">ul<\/span> <span class=\"hljs-selector-tag\">li<\/span> <span class=\"hljs-selector-class\">.done<\/span> {\n  <span class=\"hljs-attribute\">text-decoration<\/span>: line-through;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then update the root.ts file to import and make the styles available to your components.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/...<\/span>\n<span class=\"hljs-keyword\">import<\/span> styles <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"~\/styles\/global.css\"<\/span>;\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">links<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> &#91;{ rel: <span class=\"hljs-string\">\"stylesheet\"<\/span>, href: styles }];\n}\n<span class=\"hljs-comment\">\/\/...<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now refresh your browser and you should see the output below.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/11\/img_63767cb6c212f.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">The Task List application with a cancelled task 1.<\/figcaption><\/figure>\n<\/div>\n\n\n<p>At this point, we have a hard-coded task in our application. First, let&#8217;s create some routes to create and read data from our database.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Create API routes<\/h2>\n\n\n\n<p>API routes in Remix are created in the <code>app\/routes\/api<\/code> folder. Every file in the <code>api<\/code> folder is treated as an API route. We&#8217;ll create three routes to create a new task, read the tasks and update the status of the task. But first, we need to initialize the Prisma client to allow you to send queries to your database. <\/p>\n\n\n\n<p>Create a <code>config<\/code> folder in the <code>app<\/code> directory to do that. Then inside the config folder, create a <code>dbConfig.ts<\/code> file and add the code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { PrismaClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@prisma\/client\"<\/span>;\n<span class=\"hljs-keyword\">let<\/span> prisma: PrismaClient;\n\n<span class=\"hljs-keyword\">declare<\/span> global {\n  <span class=\"hljs-keyword\">const<\/span> DB: PrismaClient | <span class=\"hljs-literal\">undefined<\/span>;\n}\n\n<span class=\"hljs-keyword\">if<\/span> (process.env.NODE_ENV === <span class=\"hljs-string\">\"production\"<\/span>) {\n  prisma = <span class=\"hljs-keyword\">new<\/span> PrismaClient();\n  prisma.$connect();\n} <span class=\"hljs-keyword\">else<\/span> {\n  <span class=\"hljs-keyword\">if<\/span> (!global.db) {\n    global.db = <span class=\"hljs-keyword\">new<\/span> PrismaClient();\n    global.db.$connect();\n  }\n  prisma = global.db;\n}\n\n<span class=\"hljs-keyword\">export<\/span> { prisma };<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In the code snippet above, we initialized the <code>PrismaClient<\/code> in a variable <code>prisma<\/code> to create a connection with our application and database, ensuring that a new connection is not created when our application reloads the development environment.<\/p>\n\n\n\n<p>Next, create a <code>createTask.ts<\/code> file in the <code>api<\/code> folder and add the code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-keyword\">type<\/span> { ActionFunction } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@remix-run\/node\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { prisma } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/..\/config\/dbConfig\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> action: ActionFunction = <span class=\"hljs-keyword\">async<\/span> ({ request }) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-keyword\">await<\/span> request.json();\n  <span class=\"hljs-keyword\">const<\/span> newTask = <span class=\"hljs-keyword\">await<\/span> prisma.task.create({\n    data: { name: data.name, completed: <span class=\"hljs-literal\">false<\/span> },\n  });\n  <span class=\"hljs-keyword\">return<\/span> newTask;\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In the code snippet above, we imported the <code>ActionFunction<\/code> type for TypeScript, which we&#8217;ll use to show the type for our <code>action<\/code> function. When you make a <strong>POST<\/strong>, <strong>PUT<\/strong>, and <strong>DELETE<\/strong> requests to Remix API, it will locate the action function and execute the code in the function. Next, we created an action function to add new records to the database using the <code>prisma<\/code> client initiated in the dbConfig file. The prisma client object provides us with the methods required to perform CRUD operations on our database.<\/p>\n\n\n\n<p>Now update the <code>index.ts<\/code> file to send a request to the API to create a new task with the code snippet below.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Index<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#91;task, setTask] = useState(<span class=\"hljs-string\">''<\/span>);\n\n  <span class=\"hljs-keyword\">const<\/span> createTask = <span class=\"hljs-keyword\">async<\/span> () =&gt;\n    <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">\"http:\/\/localhost:3000\/api\/createTask\"<\/span>, {\n      <span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">\"POST\"<\/span>,\n      <span class=\"hljs-attr\">body<\/span>: <span class=\"hljs-built_in\">JSON<\/span>.stringify({\n        <span class=\"hljs-attr\">name<\/span>: Task\n      })\n    })\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"task-tab\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h4<\/span>&gt;<\/span>Task List<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h4<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">hr<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"form\"<\/span> <span class=\"hljs-attr\">onSubmit<\/span>=<span class=\"hljs-string\">{createTask}<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"name\"<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{(e)<\/span> =&gt;<\/span> setTask(e.target.value)} \/&gt;\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span>&gt;<\/span>Add<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"task-list\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Task 1<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"checkbox\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"brand\"<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"\"<\/span> \/&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\"><strong>Read data from the database<\/strong><\/h2>\n\n\n\n<p>Next, create a <code>getTasks.ts<\/code> file in the <code>api<\/code> folder and add the code snippets below to get all the tasks in your database.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-keyword\">type<\/span> { LoaderFunction } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@remix-run\/node\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { prisma } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"..\/..\/config\/dbConfig\"<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> loader: LoaderFunction = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n  <span class=\"hljs-keyword\">return<\/span> prisma.task.findMany();\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Here, we imported the <code>LoaderFunction<\/code> type to specify the type for our loader function. Like the action function, Remix executes the code in a loader function whenever you send a GET request to the API. So we used the <code>prima.findMany<\/code> method to get all the tasks in our database.<\/p>\n\n\n\n<p>Finally, update the code in the <code>index.ts<\/code> file to loop through all the tasks from our API and display and render them on our UI:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/...<\/span>\n<span class=\"hljs-keyword\">import<\/span> { json } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@remix-run\/node\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { useLoaderData } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@remix-run\/react\"<\/span>;\n\ntype Task = {\n  <span class=\"hljs-attr\">id<\/span>: string;\n  name: string;\n  completed: boolean;\n  createdAt: <span class=\"hljs-built_in\">Date<\/span>;\n  updatedAt: <span class=\"hljs-built_in\">Date<\/span>;\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">loader<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> res = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">\"http:\/\/localhost:3000\/api\/getTask\"<\/span>);\n  <span class=\"hljs-keyword\">return<\/span> json(<span class=\"hljs-keyword\">await<\/span> res.json());\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Index<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-comment\">\/\/...<\/span>\n  <span class=\"hljs-keyword\">const<\/span> tasks = useLoaderData();\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"container\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"task-tab\"<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h4<\/span>&gt;<\/span>Task List<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h4<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">hr<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"form\"<\/span> <span class=\"hljs-attr\">onSubmit<\/span>=<span class=\"hljs-string\">{createTask}<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"name\"<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{(e)<\/span> =&gt;<\/span> setTask(e.target.value)} \/&gt;\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span>&gt;<\/span>Add<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"task-list\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n            {tasks.map((task: Task) =&gt; (\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{task.id}<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{task.completed<\/span> ? '<span class=\"hljs-attr\">done<\/span>' <span class=\"hljs-attr\">:<\/span> \"\"}&gt;<\/span>{task.name}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"checkbox\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"brand\"<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"\"<\/span> \/&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n            ))}\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In the code snippet above, we imported the JSON function to parse the response return from the API, <code>useLoaderData<\/code> hook to load the data from the returned in the <code>loader<\/code> function to your components. Then we created a task to define the structure of data from the API, and then we looped through the task data and rendered them on the component.<\/p>\n\n\n\n<p>Now, go ahead and add some tasks to the application, and you should see a similar output to the one on the screenshot below, depending on the tasks you&#8217;ve created.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/d2h1bfu6zrdxog.cloudfront.net\/wp-content\/uploads\/2022\/11\/img_63767cb74d6b5.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">The Task List final application.<\/figcaption><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Conclusion<\/strong><\/h2>\n\n\n\n<p>In this tutorial, you learned to build a web application with TypeScript and Remix. You learned how to set up a Remix app, connect the Remix application to a database using Prisma, create an application schema with prisma, and perform create and read operations.The code used in this article can be found in this <a href=\"https:\/\/github.com\/uma-victor1\/remix-task-app\" target=\"_blank\" rel=\"noopener\">GitHub repository<\/a>.<\/p>\n\n\n\n<p>Remix is an exciting tool, and I recommend checking out the Remix<a href=\"https:\/\/remix.run\/docs\/en\/v1\" target=\"_blank\" rel=\"noopener\"> documentation<\/a> to learn more. Finally, I hope you enjoyed this article, and happy coding!<\/p>\n\n\n\n<p><em>Uma Victor is a software developer based in Nigeria who is familiar with a variety of different web technologies and frameworks. He is also keen on finding ways to explain things as simple as possible. You can reach out to me on\u00a0<a href=\"https:\/\/twitter.com\/umavictor_\" target=\"_blank\" rel=\"noreferrer noopener\">twitter<\/a>.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Remix is a full-stack web framework that focuses on the user interface and works backwards through web standards to provide a quick, slick, and dependable user experience. Learn how to build a full-stack web application with Typescript and the Remix framework in this article.<\/p>\n","protected":false},"author":1,"featured_media":24437,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[9],"tags":[],"persona":[29],"blog-programming-language":[61,41],"keyword-cluster":[],"class_list":["post-23955","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development"],"acf":[],"_links":{"self":[{"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/posts\/23955","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/comments?post=23955"}],"version-history":[{"count":65,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/posts\/23955\/revisions"}],"predecessor-version":[{"id":24476,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/posts\/23955\/revisions\/24476"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/media\/24437"}],"wp:attachment":[{"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/media?parent=23955"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/categories?post=23955"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/tags?post=23955"},{"taxonomy":"persona","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/persona?post=23955"},{"taxonomy":"blog-programming-language","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/blog-programming-language?post=23955"},{"taxonomy":"keyword-cluster","embeddable":true,"href":"https:\/\/coderpad.io\/wp-json\/wp\/v2\/keyword-cluster?post=23955"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}