DEV Community

Cover image for tRPC: a smart way to manage APIs
Giorgio Boa
Giorgio Boa

Posted on • Edited on

tRPC: a smart way to manage APIs

In past, I suffered a lot of the pain of maintaining a schema or some sort of type definition in my typescript applications.
If your frontend and backend are written in typescript and you suffered the same headaches, this article is for you.


In some projects with Swagger I generated schemas based on .yaml files 😒, but when you create new features is quite common to change API(s) so you end up with a lot of definitions/schemas generations. πŸ˜…
It's the same with graphql because you need to learn graphql language to describe your API(s) and then every time you change something you have to generate the updated API definitions/schemas.
Up to here only bad news πŸ˜‚ but fortunately you can solve all these pains with tRPC.

Getting started

The best way to start with tRPC is using the Next.js example from the tRPC GitHub repository because is created and maintained by the core team and follows the best practices.

Here we can test the solution with a fully configured project with:

Requirements

  • Node >= 14
  • Docker up and running in your local machine (for Postgres)

Next.js example

With these commands you can start from scratch with the application:

yarn:

yarn create next-app --example https://github.com/trpc/trpc --example-path examples/next-prisma-starter trpc-prisma-starter
cd trpc-prisma-starter
yarn
yarn dx
Enter fullscreen mode Exit fullscreen mode

npm:

npx create-next-app --example https://github.com/trpc/trpc --example-path examples/next-prisma-starter trpc-prisma-starter
cd trpc-prisma-starter
yarn
yarn dx
Enter fullscreen mode Exit fullscreen mode

Then after the initial setup at http://localhost:3000 you can add new posts and read the post text with the View more link.

Example screenshot

So far so good! πŸ’ͺ

Show me the code

Soon the tRPC team will release the new version 10 anyways these concepts are always good.

Server

Let's focus on these files in our server codebase

Here we have a function to create our router and as you can see we are using trpc.router straight from @trpc/server library.

  • /src/server/createRouter.ts

CreateRouter

Similar to GraphQL, tRPC makes a distinction between query and mutation endpoints. Let's add an add mutation:

  • /src/server/routers/post.ts

PostRouter

mutation needs a few parameters:

  • name: string: The name of this endpoint
  • input: Optional. This should be a function that validates/casts the input of this endpoint and either returns a strongly typed value (if valid) or throws an error (if invalid). Alternatively, you can pass a Zod, Superstruct, or Yup schema.
  • resolve: It's a function with a single req argument, the validated input is passed into req.input. This is the actual implementation of the endpoint, you can use prisma or you can write your logic. Here we are using prisma.post.create to save our data in the database.

Here we define a router somewhere in our server code base.
.merge function (line 7) helps us to split endpoints into multiple files and this is a best practice to obtain a clean code.
Finally, we export the AppRouter type, typescript infers to this type the right shape ready to be used in our client.

  • /src/server/routers/_app.ts

AppRouter

Client

The Next.js application needs to be configured to work with tRPC. First thing first we need to wrap the whole application with withTRPC higher-order component

  • /src/pages/_app.tsx

_app.ts

Then we need to create a set of strongly-typed hooks using your API's type signature import type { AppRouter } from '~/server/routers/_app';

  • src/utils/trpc.ts

hooks

Then we can make an API request

  • src/pages/index.tsx

index page

As you can see we are using the hook we created before to call the mutation.

Aha moment 🀯

Now I simulate a change in my API definition

  • changed add to add_new
  • added newField inside input object

serveApi

Wow 🀩 Typescript interface is smart enough to complain immediately about that

ClientError1

ClientError2


Final thought

This library is very convenient when:

  • you have private APIs and you don't need documentation to share with the rest of the world
  • you have a full stack typescript project

I like it because it's fast and intuitive
I hope this article convinces you to give it a try.

You canΒ follow me on Twitter, where I'm posting or retweeting interesting articles.

See ya! πŸ‘‹

Top comments (1)

Collapse
 
mrqwenty profile image
Matteo Pelosi

Great solution! πŸ˜ŽπŸ‘ŒπŸ»