Saltar al contenido principal
Versión: 11.x

Enlace de transmisión por lotes HTTP

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

httpBatchStreamLink es un enlace terminal que agrupa un conjunto de operaciones individuales de tRPC en una única solicitud HTTP enviada a un único procedimiento tRPC (equivalente a httpBatchLink), pero no espera a que todas las respuestas del lote estén listas y transmite las respuestas tan pronto como hay datos disponibles.

Opciones

Las opciones son idénticas a las de httpBatchLink options.

Uso

Todo el uso y las opciones son idénticos a httpBatchLink.

nota

Si necesitas cambiar o establecer encabezados de respuesta (incluyendo cookies) desde tus procedimientos, ¡asegúrate de usar httpBatchLink en su lugar! Esto se debe a que httpBatchStreamLink no admite establecer encabezados una vez que la transmisión ha comenzado. Más información.

Puedes importar y agregar httpBatchStreamLink al array de links de esta manera:

client/index.ts
ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from '../server';
const client = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000',
}),
],
});
client/index.ts
ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from '../server';
const client = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000',
}),
],
});

Después, puedes aprovechar la agrupación colocando todos tus procedimientos en un Promise.all. El siguiente código producirá exactamente una solicitud HTTP y en el servidor exactamente una consulta a la base de datos:

ts
const somePosts = await Promise.all([
trpc.post.byId.query(1),
trpc.post.byId.query(2),
trpc.post.byId.query(3),
]);
ts
const somePosts = await Promise.all([
trpc.post.byId.query(1),
trpc.post.byId.query(2),
trpc.post.byId.query(3),
]);

Modo de transmisión

Al agrupar solicitudes, el comportamiento normal de httpBatchLink es esperar a que todas las solicitudes finalicen antes de enviar la respuesta. Si deseas enviar respuestas tan pronto como estén disponibles, puedes usar httpBatchStreamLink en su lugar. Esto es útil para solicitudes de larga duración.

client/index.ts
ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from '../server';
const client = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000',
}),
],
});
client/index.ts
ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from '../server';
const client = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000',
}),
],
});

Comparado con un httpBatchLink regular, httpBatchStreamLink:

  • Hace que las solicitudes se envíen con un encabezado trpc-accept: application/jsonl

  • Hace que la respuesta se envíe con transfer-encoding: chunked y content-type: application/jsonl

  • Elimina la clave data del objeto de argumentos pasado a responseMeta (porque con una respuesta transmitida, los encabezados se envían antes de que los datos estén disponibles)

Generadores asíncronos y promesas diferidas

Puedes probar esto en la página de inicio de tRPC.io: https://trpc.io/?try=minimal#try-it-out

ts
// @filename: server.ts
import { publicProcedure, router } from './trpc';
 
const appRouter = router({
examples: {
iterable: publicProcedure.query(async function* () {
for (let i = 0; i < 3; i++) {
await new Promise((resolve) => setTimeout(resolve, 500));
yield i;
}
}),
},
});
 
export type AppRouter = typeof appRouter;
 
 
// @filename: client.ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from './server';
 
const trpc = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000',
}),
],
});
const iterable = await trpc.examples.iterable.query();
const iterable: AsyncIterable<number, never, unknown>
 
for await (const value of iterable) {
console.log('Iterable:', value);
const value: number
}
ts
// @filename: server.ts
import { publicProcedure, router } from './trpc';
 
const appRouter = router({
examples: {
iterable: publicProcedure.query(async function* () {
for (let i = 0; i < 3; i++) {
await new Promise((resolve) => setTimeout(resolve, 500));
yield i;
}
}),
},
});
 
export type AppRouter = typeof appRouter;
 
 
// @filename: client.ts
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
import type { AppRouter } from './server';
 
const trpc = createTRPCClient<AppRouter>({
links: [
httpBatchStreamLink({
url: 'http://localhost:3000',
}),
],
});
const iterable = await trpc.examples.iterable.query();
const iterable: AsyncIterable<number, never, unknown>
 
for await (const value of iterable) {
console.log('Iterable:', value);
const value: number
}

Compatibilidad (lado del cliente)

La compatibilidad con navegadores debe ser idéntica al soporte de fetch.

Node.js / Deno

Para entornos distintos a los navegadores, la implementación de fetch debe admitir transmisión, lo que significa que la respuesta obtenida mediante await fetch(...) debe tener una propiedad body de tipo ReadableStream<Uint8Array> | NodeJS.ReadableStream, lo que implica que:

  • response.body.getReader es una función que devuelve un objeto ReadableStreamDefaultReader<Uint8Array>

  • o response.body es un Buffer de tipo Uint8Array

Esto incluye soporte para undici, node-fetch, la implementación nativa de fetch en Node.js y la implementación de fetch de WebAPI (navegadores).

React Native

La recepción de la transmisión depende de las APIs TextDecoder y TextDecoderStream, que no están disponibles en React Native. Es importante notar que si tu polyfill de TextDecoderStream no polifilea automáticamente ReadableStream y WritableStream, también necesitarás polifilearlos. Si aún deseas habilitar la transmisión, debes polifilear estos componentes.

También necesitarás sobrescribir la implementación de fetch predeterminada en las opciones de configuración de httpBatchStreamLink. En el siguiente ejemplo usaremos el paquete Expo fetch para la implementación de fetch.

typescript
httpBatchStreamLink({
fetch: (url, opts) =>
fetch(url, {
...opts,
reactNative: { textStreaming: true },
}),
...restOfConfig,
});
typescript
httpBatchStreamLink({
fetch: (url, opts) =>
fetch(url, {
...opts,
reactNative: { textStreaming: true },
}),
...restOfConfig,
});

Compatibilidad (lado del servidor)

⚠️ para aws lambda, httpBatchStreamLink no es compatible (simplemente se comportará como un httpBatchLink normal). No debería romper nada si se habilita, pero no tendrá ningún efecto.

⚠️ para cloudflare workers, necesitas habilitar la API ReadableStream mediante una bandera de características: streams_enable_constructors

Referencia

Puedes consultar el código fuente de este enlace en GitHub.

Configurar una opción de ping para mantener la conexión activa

Al configurar tu raíz de configuración, puedes pasar una opción jsonl para configurar un ping que mantenga la conexión activa.

ts
import { initTRPC } from '@trpc/server';
const t = initTRPC.create({
jsonl: {
pingMs: 1000,
},
});
ts
import { initTRPC } from '@trpc/server';
const t = initTRPC.create({
jsonl: {
pingMs: 1000,
},
});