Skip to content

Commit

Permalink
Update docs of connect-query for v0.4+ (#66)
Browse files Browse the repository at this point in the history
  • Loading branch information
paul-sachs authored Oct 5, 2023
1 parent 079fd88 commit 9c95fa4
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 157 deletions.
103 changes: 75 additions & 28 deletions docs/web/query/api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,41 @@ const createQueryService: <Service extends ServiceType>({
`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.example,
...createUnaryHooks($queryService.example),
};

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
Expand All @@ -57,8 +66,8 @@ const TransportProvider: FC<PropsWithChildren<{

Broadly speaking, "transport" joins two concepts:

1. The protocol of communication. For this there are two options: the [Connect Protocol](https://connectrpc.com/docs/protocol/), or the [gRPC-Web Protocol](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md).
1. The protocol options. The primary important piece of information here is the `baseUrl`, but there are also other potentially critical options like request credentials and binary wire format encoding options.
1. The protocol of communication. For this there are two options: the [Connect Protocol](https://connectrpc.com/docs/protocol/), or the [gRPC-Web Protocol](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md).
1. The protocol options. The primary important piece of information here is the `baseUrl`, but there are also other potentially critical options like request credentials and binary wire format encoding options.

With these two pieces of information in hand, the transport provides the critical mechanism by which your app can make network requests.

Expand Down Expand Up @@ -96,15 +105,15 @@ 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>) => O;
```

Use this to create a data object that can be used as `placeholderData` or initialData.

## `UnaryHooks.createUseQueryOptions`
## `UnaryFunctions.createUseQueryOptions`

```ts
const createUseQueryOptions: (
Expand All @@ -124,51 +133,89 @@ 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<I>,
context?: QueryFunctionContext<ConnectQueryKey<I>>
) => Promise<O>;
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 its transport.

## `UnaryFunctions.createUseInfiniteQueryOptions`

```ts
const createUseInfiniteQueryOptions: <ParamKey extends keyof PlainMessage<I>>(
input: DisableQuery | PartialMessage<I>,
options: {
pageParamKey: ParamKey;
getNextPageParam: (lastPage: O, allPages: O[]) => unknown;
onError?: (error: ConnectError) => void;
transport?: Transport | undefined;
callOptions?: CallOptions | undefined;
}
) => {
enabled: boolean;
queryKey: ConnectQueryKey<I>;
queryFn: (
context: QueryFunctionContext<ConnectQueryKey<I>, PlainMessage<I>[ParamKey]>
) => Promise<O>;
getNextPageParam: GetNextPageParamFunction<O>;
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 its transport.

## `UnaryFunctions.getPartialQueryKey`

```ts
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<I>) => ConnectQueryKey<I>;
```

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<I, O>;
```

This is the metadata associated with this method.

## `UnaryHooks.setQueryData`
## `UnaryFunctions.setQueryData`

```ts
const setQueryData: (
updater: PartialMessage<O> | (
(prev?: O) => PartialMessage<O>
),
input?: PartialMessage<I>,
) => [
queryKey: ConnectQueryKey<I>,
updater: (prev?: O) => O | undefined
];
updater: PartialMessage<O> | ((prev?: O) => PartialMessage<O>),
input?: PartialMessage<I>
) => [queryKey: ConnectQueryKey<I>, 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: (
Expand Down
68 changes: 31 additions & 37 deletions docs/web/query/code-generation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -65,7 +65,6 @@ plugins:
opt: target=ts
```
To generate code for all protobuf files within your project, simply run:
```bash
Expand All @@ -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
.
Expand All @@ -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
.
Expand All @@ -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

Expand All @@ -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`.
Expand Down Expand Up @@ -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),
};
```
Loading

0 comments on commit 9c95fa4

Please sign in to comment.