syncRoutes
Check whether the client and server routes are in sync.
When you deploy a server where a route's types changed, an app that is already open still sends data in the old shape, and the server may reject or misread it. Use this middleware to stop such a call, so your app can ask the user to reload.
With each call, the client sends a route sync id: an id for the types of every route it calls. When the server's id differs, the call stops before the route runs and your code gets an error.
Changes That Stop a Call
The id changes when the route's params type or return type changes, or the way they are encoded. Only the compact parser encodes them differently. In a batch, every route is checked, and one changed route stops the whole batch.
| Change on the server | The call |
|---|---|
| The route's params type | Stopped |
| The route's return type | Stopped |
The parser of the route or router switches to or from compact | Stopped |
| mion upgraded, and the client was built with the old version | Stopped, for every route |
The route's options, like a query turned into a mutation | Runs |
| A middleware's params type | Runs. The middleware's own validation rejects data that no longer fits. |
| A route added | Other routes keep running |
| The route removed | Not checked. The call fails because the route is not found. |
Adding the Middleware
Add mionSyncRoutes from @mionjs/router/middlewares at the root of your routes. If you also use mionFetchMetadata, put that one first.
import {createMionRouter, Routes} from '@mionjs/router';
import {mionFetchMetadata, mionSyncRoutes} from '@mionjs/router/middlewares';
const mion = createMionRouter();
const routes = {
mionFetchMetadata,
// before your own middleware and routes, so a stopped call runs nothing else
mionSyncRoutes,
sayHello: mion.route((ctx, name: string): string => `Hello ${name}`),
} satisfies Routes;
const myApi = mion.initRoutes(routes);
export type MyApi = typeof myApi;
mionSyncRoutes still runs on a stopped call, and so does any middleware with alwaysRun. See Stopping the Request.Setting Up the Client
Call useSyncRoutes from @mionjs/client/middlewares with the client's middlewares.mionSyncRoutes. It sends the route sync ids and handles the errors the server answers with.
import {isRpcError} from '@mionjs/core';
import {initClient} from '@mionjs/client';
import {useSyncRoutes} from '@mionjs/client/middlewares';
import type {MyApi} from './sync-routes.routes.ts';
const {routes, middlewares} = initClient<MyApi>({
baseURL: 'http://localhost:3000',
});
// once, next to initClient
useSyncRoutes(middlewares.mionSyncRoutes);
Handling a Stopped Call
A stopped call returns no value. The error is in response.mionSyncRoutes, with the type route-types-mismatch and the changed route ids in errorData.routeIds.
const [greeting, , response] = await routes.sayHello('Ana').call();
const syncError = response.mionSyncRoutes;
// the route's types changed on the server since this app was built
if (isRpcError(syncError) && syncError.type === 'route-types-mismatch')
location.reload();
else console.log(greeting);
| Route metadata | What the client does | What you do |
|---|---|---|
| Bundled at build time (the default) | Returns the error. | Reload the app to pick up a newer client build, or ship one. |
| Fetched from the server with mionFetchMetadata | Drops its saved copy, fetches the new metadata and sends the call again, once. | Nothing. You see the error only if the second try fails too. |
Calls Without Ids
A call that sends no id is stopped with route-sync-required. This happens on the first call of a route whose metadata the client has not fetched yet. The error includes the route's metadata, so useSyncRoutes saves that metadata and sends the call again.
useSyncRoutes the client sends no ids, so every call ends with route-sync-required. The same goes for any other caller, like curl or a client in another language.Build Check
When the client bundles route metadata, the build fails with rpc-client-optional-middleware-not-set-up if a route runs mionSyncRoutes and nothing in the client uses middlewares.mionSyncRoutes. Look up the name in All Diagnostics.