From 5d156b6e114a1b3c92c9a94c210c19527bc0447d Mon Sep 17 00:00:00 2001 From: Paul Sachs Date: Mon, 2 Oct 2023 13:43:58 -0400 Subject: [PATCH] Update docs from main of connect-query --- docs/web/query/api.mdx | 99 ++++++++++++++++------ docs/web/query/code-generation.mdx | 68 +++++++-------- docs/web/query/faq.mdx | 128 ++++++++++++----------------- docs/web/query/getting-started.mdx | 55 +++++++------ 4 files changed, 187 insertions(+), 163 deletions(-) diff --git a/docs/web/query/api.mdx b/docs/web/query/api.mdx index e3dde3b..88a9b1d 100644 --- a/docs/web/query/api.mdx +++ b/docs/web/query/api.mdx @@ -17,32 +17,41 @@ const createQueryService: ({ `createQueryService` is the main entrypoint for Connect-Query. -Pass in a service and you will receive an object with properties for each of your services and values that provide hooks for those services that you can then give to Tanstack Query. The `ServiceType` TypeScript interface is provided by Protobuf-ES (`@bufbuild/protobuf`) while generated service definitions are provided by Connect-Web (`@connectrpc/connect-web`). +Pass in a service and you will receive an object with properties for each of your services and values that provide hooks for those services that you can then give to Tanstack Query. The `ServiceType` TypeScript interface is provided by Protobuf-ES (`@bufbuild/protobuf`) while generated service definitions are provided by Connect-Web (`@connectrpc/connect-web`). -`Transport` refers to the mechanism by which your client will make the actual network calls. If you want to use a custom transport, you can optionally provide one with a call to `useTransport`, which Connect-Query exports. Otherwise, the default transport from React context will be used. This default transport is placed on React context by the `TransportProvider`. Whether you pass a custom transport or you use `TransportProvider`, in both cases you'll need to use one of `@connectrpc/connect-web`'s exports `createConnectTransport` or `createGrpcWebTransport`. +`Transport` refers to the mechanism by which your client will make the actual network calls. If you want to use a custom transport, you can optionally provide one with a call to `useTransport`, which Connect-Query exports. Otherwise, the default transport from React context will be used. This default transport is placed on React context by the `TransportProvider`. Whether you pass a custom transport or you use `TransportProvider`, in both cases you'll need to use one of `@connectrpc/connect-web`'s exports `createConnectTransport` or `createGrpcWebTransport`. Note that the most memory performant approach is to use the transport on React Context by using the `TransportProvider` because that provider is memoized by React, but also that any calls to `createQueryService` with the same service is cached by this function. Here's an example of a simple usage: ```ts -export const { say } = createQueryService({ +const queryService = createQueryService({ service: { methods: { - say: { - name: "Say", + example: { + name: "Example", kind: MethodKind.Unary, - I: SayRequest, - O: SayResponse, + I: ExampleRequest, + O: ExampleResponse, }, }, - typeName: "connectrpc.eliza.v1.ElizaService", + typeName: "your.company.com.example.v1.ExampleService", }, }); -const { data, isLoading, ...etc } = useQuery(say.useQuery()); +const example = { + ...queryService.say, + ...createUnaryHooks($queryService.say), +}; + +const { data, isLoading, ...etc } = useQuery(example.useQuery()); ``` +## `createUnaryHooks` + +This creates some helper functions for unary methods that automatically include the transport from context. It's a distinct function from `createQueryService` so the core function can be separate from specific React APIs. + ## `TransportProvider` > Note: This API can only be used with React @@ -96,7 +105,7 @@ const useTransport: () => Transport; Use this helper to get the default transport that's currently attached to the React context for the calling component. -## `UnaryHooks.createData` +## `UnaryFunctions.createData` ```ts const createData: (data: PartialMessage) => O; @@ -104,7 +113,7 @@ const createData: (data: PartialMessage) => O; Use this to create a data object that can be used as `placeholderData` or initialData. -## `UnaryHooks.createUseQueryOptions` +## `UnaryFunctions.createUseQueryOptions` ```ts const createUseQueryOptions: ( @@ -124,11 +133,54 @@ const createUseQueryOptions: ( }; ``` -`createUseQueryOptions` is intended to be used with TanStack's [`useQuery`](https://tanstack.com/query/v4/docs/react/reference/useQuery) hook. The difference is that `createUseQueryOptions` is not a hook. Since hooks cannot be called conditionally, it can sometimes be helpful to use `createUseQueryOptions` to prepare an input to TanStack's `useQuery`. +`createUseQueryOptions` is intended to be used with TanStack's [`useQuery`](https://tanstack.com/query/v4/docs/react/reference/useQuery) hook. The difference is that `createUseQueryOptions` is not a hook. Since hooks cannot be called conditionally, it can sometimes be helpful to use `createUseQueryOptions` to prepare an input to TanStack's `useQuery`. It is also useful to use alongside TanStack's [`useQueries`](https://tanstack.com/query/v4/docs/react/reference/useQueries) hook since hooks cannot be called in loops. -## `UnaryHooks.getPartialQueryKey` +## `UnaryFunctions.createUseMutationOptions` + +```ts +const createUseMutationOptions: (options: { + onError?: (error: ConnectError) => void; + transport?: Transport | undefined; + callOptions?: CallOptions | undefined; +}) => { + mutationFn: ( + input: PartialMessage, + context?: QueryFunctionContext> + ) => Promise; + onError?: (error: ConnectError) => void; +}; +``` + +`createUseMutationOptions` is intended to be used with TanStack's [`useMutation`](https://tanstack.com/query/v4/docs/react/reference/useMutation) hook. The difference is that `createUseMutationOptions` is not a hook and doesn't read from `TransportProvider` for it's transport. + +## `UnaryFunctions.createUseInfiniteQueryOptions` + +```ts +const createUseInfiniteQueryOptions: >( + input: DisableQuery | PartialMessage, + options: { + pageParamKey: ParamKey; + getNextPageParam: (lastPage: O, allPages: O[]) => unknown; + onError?: (error: ConnectError) => void; + transport?: Transport | undefined; + callOptions?: CallOptions | undefined; + } +) => { + enabled: boolean; + queryKey: ConnectQueryKey; + queryFn: ( + context: QueryFunctionContext, PlainMessage[ParamKey]> + ) => Promise; + getNextPageParam: GetNextPageParamFunction; + onError?: (error: ConnectError) => void; +}; +``` + +`createUseInfiniteQueryOptions` is intended to be used with TanStack's [`useInfiniteQuery`](https://tanstack.com/query/v4/docs/react/reference/useInfiniteQuery) hook. The difference is that `createUseInfiniteQueryOptions` is not a hook and doesn't read from `TransportProvider` for it's transport. + +## `UnaryFunctions.getPartialQueryKey` ```ts const getPartialQueryKey: () => ConnectPartialQueryKey; @@ -136,15 +188,15 @@ const getPartialQueryKey: () => ConnectPartialQueryKey; This helper is useful for getting query keys matching a wider set of queries associated to this Connect `Service`, per TanStack Query's [partial matching](https://tanstack.com/query/v4/docs/react/guides/query-invalidation#query-matching-with-invalidatequeries) mechanism. -## `UnaryHooks.getQueryKey` +## `UnaryFunctions.getQueryKey` ```ts const getQueryKey: (input?: DisableQuery | PartialMessage) => ConnectQueryKey; ``` -This helper is useful to manually compute the [`queryKey`](https://tanstack.com/query/v4/docs/react/guides/query-keys) sent to TanStack Query. This function has no side effects. +This helper is useful to manually compute the [`queryKey`](https://tanstack.com/query/v4/docs/react/guides/query-keys) sent to TanStack Query. This function has no side effects. -## `UnaryHooks.methodInfo` +## `UnaryFunctions.methodInfo` ```ts const methodInfo: MethodInfoUnary; @@ -152,23 +204,18 @@ const methodInfo: MethodInfoUnary; This is the metadata associated with this method. -## `UnaryHooks.setQueryData` +## `UnaryFunctions.setQueryData` ```ts const setQueryData: ( - updater: PartialMessage | ( - (prev?: O) => PartialMessage - ), - input?: PartialMessage, -) => [ - queryKey: ConnectQueryKey, - updater: (prev?: O) => O | undefined -]; + updater: PartialMessage | ((prev?: O) => PartialMessage), + input?: PartialMessage +) => [queryKey: ConnectQueryKey, updater: (prev?: O) => O | undefined]; ``` This helper is intended to be used with TanStack Query `QueryClient`'s [`setQueryData`](https://tanstack.com/query/v4/docs/react/reference/QueryClient#queryclientsetquerydata) function. -## `UnaryHooks.setQueriesData` +## `UnaryFunctions.setQueriesData` ```ts const setQueriesData: ( diff --git a/docs/web/query/code-generation.mdx b/docs/web/query/code-generation.mdx index 66c0dfe..fc284f1 100644 --- a/docs/web/query/code-generation.mdx +++ b/docs/web/query/code-generation.mdx @@ -7,8 +7,8 @@ The code generator for Connect-Query, a expansion pack for [TanStack Query](http ## Installation -`protoc-gen-connect-query` is a code generator plugin for Protocol Buffer compilers like [buf](https://github.com/bufbuild/buf) and [protoc](https://github.com/protocolbuffers/protobuf/releases). It generates clients from your Protocol Buffer schema, and works in tandem with -[@bufbuild/protoc-gen-es](https://www.npmjs.com/package/@bufbuild/protoc-gen-es), the code generator plugin for all Protocol Buffer base types. The code those two plugins generate requires the runtime libraries [@connectrpc/connect-query](https://www.npmjs.com/package/@connectrpc/connect-query), and [@bufbuild/protobuf](https://www.npmjs.com/package/@bufbuild/protobuf). +`protoc-gen-connect-query` is a code generator plugin for Protocol Buffer compilers like [buf](https://github.com/bufbuild/buf) and [protoc](https://github.com/protocolbuffers/protobuf/releases). It generates clients from your Protocol Buffer schema, and works in tandem with +[@bufbuild/protoc-gen-es](https://www.npmjs.com/package/@bufbuild/protoc-gen-es), the code generator plugin for all Protocol Buffer base types. The code those two plugins generate requires the runtime libraries [@connectrpc/connect-query](https://www.npmjs.com/package/@connectrpc/connect-query), and [@bufbuild/protobuf](https://www.npmjs.com/package/@bufbuild/protobuf). To install `buf`, the plugins and their runtime libraries, run: @@ -65,7 +65,6 @@ plugins: opt: target=ts ``` - To generate code for all protobuf files within your project, simply run: ```bash @@ -90,10 +89,9 @@ PATH=$PATH:$(pwd)/node_modules/.bin \ Note that we are adding `node_modules/.bin` to the `$PATH`, so that the protocol buffer compiler can find them. - ## Generated Output -Connect-Query will create one output file for every service in every protofile. Say you have the following file structure: +Connect-Query will create one output file for every service in every protofile. Say you have the following file structure: ```tree . @@ -102,7 +100,7 @@ Connect-Query will create one output file for every service in every protofile. └── curry.proto ``` -Where `pizza.proto` contains `DetroitStyleService` and `ChicagoStyleService`, and where `curry.proto` contains `VindalooService`. Your generated output will look like this: +Where `pizza.proto` contains `DetroitStyleService` and `ChicagoStyleService`, and where `curry.proto` contains `VindalooService`. Your generated output will look like this: ```tree . @@ -114,7 +112,7 @@ Where `pizza.proto` contains `DetroitStyleService` and `ChicagoStyleService`, an └── curry-VindalooService_connectquery.ts ``` -The reason each service gets a separate file is to facilitate intellisense and language server protocol imports. Notice that one file per input proto is generated by `protoc-gen-es` (`pizza_pb.ts` and `curry_pb.ts`), and that one file per service is created by `protoc-gen-connect-query` (making up the remainder). The Protobuf-ES generated files (`*_pb.ts`) are important because those files are referenced from the `*_connectquery.ts` files. +The reason each service gets a separate file is to facilitate intellisense and language server protocol imports. Notice that one file per input proto is generated by `protoc-gen-es` (`pizza_pb.ts` and `curry_pb.ts`), and that one file per service is created by `protoc-gen-connect-query` (making up the remainder). The Protobuf-ES generated files (`*_pb.ts`) are important because those files are referenced from the `*_connectquery.ts` files. ## Plugin options @@ -124,10 +122,10 @@ This option controls whether the plugin generates JavaScript, TypeScript, or Typ Say, for example, you used [`example.proto`](#exampleproto): -| Target | Generated output | -| - | - | -| `target=js` | `example-TodoService_connectquery.js` | -| `target=ts` | `example-TodoService_connectquery.ts` | +| Target | Generated output | +| ------------ | --------------------------------------- | +| `target=js` | `example-TodoService_connectquery.js` | +| `target=ts` | `example-TodoService_connectquery.ts` | | `target=dts` | `example-TodoService_connectquery.d.ts` | Multiple values can be given by separating them with `+`, for example `target=js+dts`. @@ -161,37 +159,33 @@ import { Empty, Todo, Todos } from "./example_pb.js"; export const typeName = "example.v1.TodoService"; +const $queryService = createQueryService({ service: TodoService }); + +export const TodoService = { + methods: { + getTodos: { + name: "GetTodos", + kind: MethodKind.Unary, + I: Empty, + O: Todos, + }, + }, + typeName, +} as const; + /** * @generated from rpc example.v1.TodoService.GetTodos */ -export const getTodos = createQueryService({ - service: { - methods: { - getTodos: { - name: "GetTodos", - kind: MethodKind.Unary, - I: Empty, - O: Todos, - }, - }, - typeName: "example.v1.TodoService", - }, -}).getTodos; +export const getTodos = { + ...$queryService.getTodos, + ...createUnaryHooks($queryService.getTodos), +}; /** * @generated from rpc example.v1.TodoService.AddTodo */ -export const addTodo = createQueryService({ - service: { - methods: { - addTodo: { - name: "AddTodo", - kind: MethodKind.Unary, - I: Todo, - O: Todos, - }, - }, - typeName: "example.v1.TodoService", - }, -}).addTodo; +export const getTodos = { + ...$queryService.addTodos, + ...createUnaryHooks($queryService.addTodos), +}; ``` diff --git a/docs/web/query/faq.mdx b/docs/web/query/faq.mdx index 93b8ca8..190fc8b 100644 --- a/docs/web/query/faq.mdx +++ b/docs/web/query/faq.mdx @@ -3,135 +3,109 @@ title: Frequently Asked Questions sidebar_position: 100 --- -## How do I pass other TanStack Query options? +### How do I pass other TanStack Query options? Say you have an query that looks something like this: ```ts import { useQuery } from '@tanstack/react-query'; import { example } from 'your-generated-code/example-ExampleService_connectquery'; + export const Example: FC = () => { const { data } = useQuery(example.useQuery({})); return
{data}
; }; ``` -On line 4, `example.useQuery({})` just returns an object with a few TanStack Query options preconfigured for you (for example, `queryKey` and `queryFn` and `onError`). All of the Connect-Query hooks APIs work this way, so you can always inspect the TypeScript type to see which specific TanStack query options are configured. +On line 5, `example.useQuery({})` just returns an object with a few TanStack Query options preconfigured for you (for example, `queryKey` and `queryFn` and `onError`). All of the Connect-Query hooks APIs work this way, so you can always inspect the TypeScript type to see which specific TanStack query options are configured. That means, that if you want to add extra TanStack Query options, you can simply spread the object resulting from Connect-Query: ```ts - const { data } = useQuery({ - ...example.useQuery({}), - // Add any extra TanStack Query options here. - // TypeScript will ensure they're valid! - refetchInterval: 1000, - }); -``` - -:::note - -Why does it work this way? - -You may be familiar with other projects that directly wrap react-query directly (such as tRPC). We worked with the TanStack team to develop this API and determined that it's most flexible to simply return an options object. +const { data } = useQuery({ + ...example.useQuery({}), -1. You have full control over what's actually passed to TanStack Query. For example, if you have a query where you'd like to modify the `queryKey`, you can do so directly. -1. It provides full transparency into what Connect Query is actually doing. This means that if you want to see what _exactly_ Connect Query is doing, you can simply inspect the object. This makes for a much more straightforward experience when you're debugging your app. -1. This means that the resulting call is plain TanStack Query in every way, which means that you can still integrate with any existing TanStack Query plugins or extensions you may already be using. -1. Not wrapping TanStack Query itself means that you can immediately use Connect-Query with any new functionality or options of TanStack Query. + // Add any extra TanStack Query options here. + // TypeScript will ensure they're valid! + refetchInterval: 1000, +}); +``` -::: +> Why does it work this way? +> +> You may be familiar with other projects that directly wrap react-query directly (such as tRPC). We worked with the TanStack team to develop this API and determined that it's most flexible to simply return an options object. +> +> 1. You have full control over what's actually passed to TanStack Query. For example, if you have a query where you'd like to modify the `queryKey`, you can do so directly. +> 1. It provides full transparency into what Connect Query is actually doing. This means that if you want to see what _exactly_ Connect Query is doing, you can simply inspect the object. This makes for a much more straightforward experience when you're debugging your app. +> 1. This means that the resulting call is plain TanStack Query in every way, which means that you can still integrate with any existing TanStack Query plugins or extensions you may already be using. +> 1. Not wrapping TanStack Query itself means that you can immediately use Connect-Query with any new functionality or options of TanStack Query. -## Is this ready for production? +### Is this ready for production? -Buf has been using Connect-Query in production for some time. Also, there is 100% mandatory test coverage in this project which covers quite a lot of edge cases. That said, this package is given a `v0.x` semver to designate that it's a new project, and we want to make sure the API is exactly what our users want before we call it "production ready". That also means that some parts of the API may change before `v1.0` is reached. +Buf has been using Connect-Query in production for some time. Also, there is 100% mandatory test coverage in this project which covers quite a lot of edge cases. That said, this package is given a `v0.x` semver to designate that it's a new project, and we want to make sure the API is exactly what our users want before we call it "production ready". That also means that some parts of the API may change before `v1.0` is reached. -## What is Connect-Query's relationship to Connect-Web and Protobuf-ES? +### What is Connect-Query's relationship to Connect-Web and Protobuf-ES? Here is a high-level overview of how Connect-Query fits in with Connect-Web and Protobuf-ES:
Expand to see a detailed dependency graph -![connect-query Dependency Graph](./connect-query_dependency_graph.png) + + +connect-query_dependency_graph
-Your Protobuf files serve as the primary input to the code generators `protoc-gen-connect-query` and `protoc-gen-es`. Both of these code generators also rely on primitives provided by Protobuf-ES. The Buf CLI produces the generated output. The final generated code uses `Transport` from Connect-Web and generates a final Connect-Query API. +Your Protobuf files serve as the primary input to the code generators `protoc-gen-connect-query` and `protoc-gen-es`. Both of these code generators also rely on primitives provided by Protobuf-ES. The Buf CLI produces the generated output. The final generated code uses `Transport` from Connect-Web and generates a final Connect-Query API. -## What is `Transport`? +### What is `Transport` -`Transport` is a regular JavaScript object with two methods, `unary` and `serverStream`. See the definition in the Connect-Web codebase [here](https://github.com/connectrpc/connect-es/blob/main/packages/connect-web/src/transport.ts). `Transport` defines the mechanism by which the browser can call a gRPC-Web or Connect backend. Read more about Transport on the [connect docs](https://connectrpc.com/docs/web/choosing-a-protocol). +`Transport` is a regular JavaScript object with two methods, `unary` and `stream`. See the definition in the Connect-Web codebase [here](https://github.com/connectrpc/connect-es/blob/main/packages/connect/src/transport.ts). `Transport` defines the mechanism by which the browser can call a gRPC-web or Connect backend. Read more about Transport on the [connect docs](https://connectrpc.com/docs/web/choosing-a-protocol). -## What if I already use Connect-Web? +### What if I already use Connect-Web? You can use Connect-Web and Connect-Query together if you like! -## What if I use gRPC-Web? - -Connect-Query also supports gRPC-Web! All you need to do is make sure you call `createGrpcWebTransport` instead of `createConnectTransport`. +### What if I use gRPC-web? -That said, we encourage you to check out the [Connect protocol](https://connectrpc.com/docs/protocol/), a simple, HTTP-based protocol that works over HTTP/1.1 or HTTP/2. It supports server-streaming methods just like gRPC-Web, but is easy to debug in the network inspector. +Connect-Query also supports gRPC-web! All you need to do is make sure you call `createGrpcWebTransport` instead of `createConnectTransport`. -## Do I have to use a code generator? +That said, we encourage you to check out the [Connect protocol](https://connectrpc.com/docs/protocol/), a simple, POST-only protocol that works over HTTP/1.1 or HTTP/2. It supports server-streaming methods just like gRPC-Web, but is easy to debug in the network inspector. -No. The code generator just calls [`createQueryService`](#createqueryservice) with the arguments already added, but you are free to do that yourself if you wish. +### Do I have to use a code generator? -## What if I have a custom `Transport`? +No. The code generator just calls `createQueryService` and `createUnaryHooks` with the arguments already added, but you are free to do that yourself if you wish. -If the `Transport` attached to React Context via the `TransportProvider` isn't working for you, then you can override transport at every level. For example, you can pass a custom transport directly to the lowest-level API like `UnaryHooks.useQuery`, but you can also pass it to `createQueryHooks` or even as high as `createQueryService`. It's an optional argument for all of those cases and if you choose to omit the `transport` property, the `Transport` provided by `TransportProvider` will be used (only where necessary). +### What if I have a custom `Transport`? -## Does this only work with React? +If the `Transport` attached to React Context via the `TransportProvider` isn't working for you, then you can override transport at every level. For example, you can pass a custom transport directly to the lowest-level API like `UnaryHooks.useQuery`, but you can also pass it to `createQueryHooks` or even as high as `createQueryService`. It's an optional argument for all of those cases and if you choose to omit the `transport` property, the `Transport` provided by `TransportProvider` will be used (only where necessary). -You can use Connect-Query with any TanStack variant (React, Solid, Svelte, Vue). However, since the hooks APIs like [`UnaryHooks.useQuery`](#unaryhooksusequery) and [`UnaryHooks.useMutation`](#unaryhooksusemutation) automatically infer `Transport` from React Context, these APIs will only work with React, as of now. There is nothing else React specific in the Connect-Query codebase. As we expand the scope of the project, we do hope to support all APIs on all TanStack Query variants. +### Does this only work with React? -| Connect-Query API | React | Solid | Svelte | Vue | -| ----------------------- | ------------------ | ------------------ | ------------------ | ------------------ | -| `createQueryService` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| `createQueryHooks` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| `isSupportedMethod` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| `disableQuery` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| `unaryHooks` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| `createData` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| `createUseQueryOptions` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| `getPartialQueryKey` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| `getQueryKey` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| `methodInfo` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| `setQueryData` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| `setQueriesData` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | -| `useInfiniteQuery` | :heavy_check_mark: | :x: | :x: | :x: | -| `useMutation` | :heavy_check_mark: | :x: | :x: | :x: | -| `useQuery` | :heavy_check_mark: | :x: | :x: | :x: | -| `useQuery` | :heavy_check_mark: | :x: | :x: | :x: | -| `useTransport` | :heavy_check_mark: | :x: | :x: | :x: | -| `TransportProvider` | :heavy_check_mark: | :x: | :x: | :x: | +You can use Connect-Query with any TanStack variant (React, Solid, Svelte, Vue). All methods which are part of the `UnaryFunctions` type can be used by any framework. The only APIs which are React specific are the `TransportProvider`, and any APIs starting with `use`. -> Tip: If you're a TanStack Query user that uses something other than React, we'd love to hear from you. Please reach out to us on the [Buf Slack](https://buf.build/links/slack). +> Tip: If you're a TanStack Query user that uses something other than React, we'd love to hear from you. Please reach out to us on the [Buf Slack](https://buf.build/links/slack). -### SolidJS Example +### How do I do Prefetching? -Say, for example, you're using Solid together with TanStack Query's `useQuery` API. In this case you can use `UnaryHooks.createUseQueryOptions` instead of `UnaryHooks.useQuery`. The only difference is that `createUseQueryOptions` requires you to pass in a `Transport` because it is not a hook and hooks are where transport is automatically inferred. +When you might not have access to React context, you can use the `create` series of functions and provide a transport directly. For example: -Here's an example using SolidJS: - -```tsx -import { createQuery } from "@tanstack/solid-query"; -import { getTodos } from "./example-ElizaService_connectquery"; +```ts +import { say } from "./gen/eliza-ElizaService_connectquery"; -function Component() { - const options = example.createUseQueryOptions( - { name: 'My First Todo' }, - { transport } +function prefetch() { + return queryClient.prefetchQuery( + say.createUseQueryOptions({ sentence: "Hello", transport: myTransport }) ); - const query = createQuery({ - ...options, - queryKey: () => options.queryKey - }); - return
{whatever}
} ``` -## What about Streaming? +### What about Streaming? Connect-Query currently only supports Unary RPC methods, which use a simple request/response style of communication similar to GET or POST requests in REST. This is because it aligns most closely with TanStack Query's paradigms. However, we understand that there may be use cases for Server Streaming, Client Streaming, and Bidirectional Streaming, and we're eager to hear about them. @@ -141,4 +115,4 @@ To get started, we invite you to open a pull request with an example project in If you're not yet at the point of creating an example project, feel free to open an issue in the repository and describe your use case. We'll follow up with questions to better understand your needs. -Your input and ideas are crucial in shaping the future development of Connect-Query. We appreciate your input and look forward to hearing from you. +Your input and ideas are crucial in shaping the future development of Connect-Query. We appreciate your input and look forward to hearing from you. diff --git a/docs/web/query/getting-started.mdx b/docs/web/query/getting-started.mdx index 4649cca..c398b4b 100644 --- a/docs/web/query/getting-started.mdx +++ b/docs/web/query/getting-started.mdx @@ -3,11 +3,11 @@ title: Getting started sidebar_position: 1 --- -Connect-Query is an expansion pack for [TanStack Query](https://tanstack.com/query) (react-query), written in TypeScript and thoroughly tested. It enables effortless communication with servers over the [Connect Protocol](https://connectrpc.com/docs/protocol) or the gRPC-Web Protocol. +Connect-Query is an expansion pack for [TanStack Query](https://tanstack.com/query) (react-query), written in TypeScript and thoroughly tested. It enables effortless communication with servers over the [Connect Protocol](https://connectrpc.com/docs/protocol) or the gRPC-Web Protocol. # Quickstart -Connect-Query will immediately feel familiar to you if you've used TanStack Query. It provides a set of convenient helpers that you can pass to the same TanStack Query functions you're already using: +Connect-Query will immediately feel familiar to you if you've used TanStack Query. It provides a set of convenient helpers that you can pass to the same TanStack Query functions you're already using: ```ts import { useQuery } from '@tanstack/react-query'; @@ -21,46 +21,55 @@ export const Example: FC = () => { **_That's it!_** -The [code generator](https://www.npmjs.com/package/@connectrpc/protoc-gen-connect-query) does all the work of turning your Protobuf file into something you can easily import. TypeScript types all populate out-of-the-box. Your documentation is also converted to [TSDoc](https://tsdoc.org/). +The [code generator](https://www.npmjs.com/package/@connectrpc/protoc-gen-connect-query) does all the work of turning your Protobuf file into something you can easily import. TypeScript types all populate out-of-the-box. Your documentation is also converted to [TSDoc](https://tsdoc.org/). -One of the best features of this library is that once you write your schema in Protobuf form, the TypeScript types are generated and then inferred. You never again need to specify the types of your data since the library does it automatically. +One of the best features of this library is that once you write your schema in Protobuf form, the TypeScript types are generated and then inferred. You never again need to specify the types of your data since the library does it automatically. -
- +
+

- - play the above video to see the TypeScript types in action - + play the above video to see the TypeScript types in action

- ## Generated Code -This example shows the best developer experience using code generation. Here's what that generated code looks like: +This example shows the best developer experience using code generation. Here's what that generated code looks like: ```ts title="your-generated-code/example-ExampleService_connectquery" -import { createQueryService } from "@connectrpc/connect-query"; +import { + createQueryService, + createUnaryHooks, +} from "@connectrpc/connect-query"; import { MethodKind } from "@bufbuild/protobuf"; import { ExampleRequest, ExampleResponse } from "./example_pb.js"; -export const example = createQueryService({ - service: { - methods: { - example: { - name: "Example", - kind: MethodKind.Unary, - I: ExampleRequest, - O: ExampleResponse, - }, +export const typeName = "your.company.com.example.v1.ExampleService"; + +export const ExampleService = { + methods: { + example: { + name: "Example", + kind: MethodKind.Unary, + I: ExampleRequest, + O: ExampleResponse, }, - typeName: "your.company.com.example.v1.ExampleService", }, -}).example; + typeName, +} as const; + +const $queryService = createQueryService({ service: ExampleService }); + +export const say = { + ...$queryService.say, + ...createUnaryHooks($queryService.say), +}; ``` If you want to use Connect-Query dynamically without code generation, you can call [`createQueryService`](#createqueryservice) exactly as the generated code does.