Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server side calls #436

Open
samulisuomi opened this issue Nov 18, 2023 · 2 comments
Open

Server side calls #436

samulisuomi opened this issue Nov 18, 2023 · 2 comments
Labels

Comments

@samulisuomi
Copy link

samulisuomi commented Nov 18, 2023

tRPC supports a concept they call "Server Side Calls", which means you can call the router endpoints inside the same Node process. This would be very useful in ts-rest as well, especially in Next.js – you could define the API logic in one central place, and use the operations not only from the client components over HTTP but also within the server.

I had to test this out, and I'm able to achieve this already by doing this hack in my server component:

// src/app/posts/page.tsx:

import { IncomingHttpHeaders } from 'http'
import { NextApiRequest, NextApiResponse } from 'next'

import postsRouter from '@/api/posts'

export default async function PostsPage() {
  const post = await postsRouter.postGet({
    params: { postId: '5c40e553-414e-4846-bf6b-66dc7f47f48a' },
    headers: {} as IncomingHttpHeaders,
    req: {} as NextApiRequest,
    res: {} as NextApiResponse,
  })

  return (
    <>
      {JSON.stringify((post.body as any)?.post) /* <-- this does correctly print the data! */}
    </>
  )
}

but it would be great to have an official way to do something similar.

Here are the other relevant files for future reference:
// src/api/posts.ts:

const postsRouter = createNextRoute(appApiContract.posts, {
  postGet: async ({ params: { postId } }) => {
    const post = await db
      .selectFrom('posts')
      .select(exposedPostColumns)
      .where('id', '=', postId)
      .executeTakeFirstOrThrow()

    return {
      status: 200,
      body: {
        post,
      },
    }
  },
})

export default postsRouter
// src/pages/api/[...ts-rest].ts

const router = createNextRoute(appApiContract, {
  posts: postsRouter,
})

export default createNextRouter(appApiContract, router, {
  jsonQuery: true,
  responseValidation: true,
})
// src/api/app-api-contract.ts:

const c = initContract()

const appApiContract = c.router({
  posts: c.router({
    postGet: {
      method: 'GET',
      path: '/posts/:postId',
      pathParams: z.object({
        postId: CustomUidSchema,
      }),
      responses: {
        200: z.object({
          post: PostSchema,
        }),
      },
      summary: 'Get a post by ID',
    },
  }),
})

export default appApiContract

This has been an awesome lib so far!

@steschi
Copy link

steschi commented Feb 23, 2024

Thanks for sharing this! I am looking for a rest-like tRPC alternative which allows for server side calls from within the same process as well as client side calls from the browser without the need to take care of the transport layer. This looks promising! Wondering if there are clever ways to avoid the type hacking and if there are any caveats.

@Gabrola Gabrola added enhancement New feature or request needs investigation labels Apr 15, 2024
@dBianchii
Copy link

This is a necessary feature imo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants