mmkal / fetchomatic

Wrap fetch with retries, timeout, logging, caching, error handling and more
Apache License 2.0
1 stars 0 forks source link

Nextjs route helper #5

Open mmkal opened 1 year ago

mmkal commented 1 year ago

Idea: a very very thin wrapper that gives types to nextjs API routes.

// src/app/foo/route.ts
import {defineNextJSRouteHandler} from 'fetchomatic/next'
import {z} from 'zod'

const handler = defineNextJSRouteHandler({
  input: z.object({foo: z.string()}),
  resolve: async request => {
    const message = `The first few letters in foo are ${request.input.foo.slice(0, 3)}`
    const allSearchParams = Object.fromEntries(request.nextURL.searchParams)
    return {message, allSearchParams}
  },
})

export {handler as GET, handler as POST}

export type FooFetchomaticable = typeof handler._fetchomaticable
// src/app/foo/client.ts
import {type FooFetchomaticable} from './route.ts'
import {fetchomatic} from 'fetchomatic'

export const fetchFoo = fetchomatic<FooFetchomaticable>(fetch, {
  url: '/foo',
})
// src/app/page.tsx
import {fetchFoo} from './foo/client'
export default async function HomePage() {
  const res = await fetchFoo.get({ foo: 'bar' })
  const json = await res.json()
  return <div>Message: {json.message}</div>
}

Definitely stepping on trpc toes, but it's much simpler and more granular at the nextjs api route level.

mmkal commented 1 year ago

Could have recommended string configs to allow the server telling the client how it should be used:

// src/app/foo/route.ts
import {defineNextJSRouteHandler} from 'fetchomatic/next'
import {z} from 'zod'

const handler = defineNextJSRouteHandler({
  input: z.object({foo: z.string()}),
  async request => {
    const message = `The first few letters in foo are ${request.input.foo.slice(0, 3)}`
    const allSearchParams = Object.fromEntries(request.nextURL.searchParams)
    return {message, allSearchParams}
  },
}).withRecommendedConfig({
  retries: 1,
  retryDelay: 1000,
})

export {handler as GET, handler as POST}

export type FooFetchomaticable = typeof handler._fetchomaticable
// src/app/foo/client.ts
import {type FooFetchomaticable} from './route.ts'
import {fetchomatic} from 'fetchomatic'

export const fetchFoo = fetchomatic<FooFetchomaticable>(fetch, {
  url: '/foo',
  useRecommendedConfig: 'retries=1&retryDelay=1000' // optional field, but type is strict
})
// src/app/page.tsx
import {fetchFoo} from './foo/client'
export default async function HomePage() {
  const res = await fetchFoo.get({ foo: 'bar' })
  const json = await res.json()
  return <div>Message: {json.message}</div>
}