title | order | layout |
---|---|---|
Appendix: Client middleware |
140 |
page |
The middleware in Vaadin is a special TypeScript async callback function that is executed by the frontend client during calls to backend. It intercepts the request and the response for every call. The middleware has access to the call context information, including the endpoint and the method names, the supplied parameters, and other client call options.
The middleware could be used for processing requests and their responses. The typical use cases are:
-
Performance measurement
-
Logging the requests
-
Retrying
-
Batching
-
Caching the response
-
Custom request and response headers and body handling
Here is an example logging middleware with the structure explained.
import {Middleware, MiddlewareContext, MiddlewareNext} from '@vaadin/flow-frontend/Connect';
// A middleware is an async function, that receives the `context` and `next`
export const MyLogMiddleware: Middleware = async function(
context: MiddlewareContext,
next: MiddlewareNext
) {
// The context object contains the call arguments. See the `call` method
// of the `ConnectClient` class for their descriptions.
const {endpoint, method, params} = context;
console.log(
`Sending request to endpoint: ${endpoint} ` +
`method: ${method} ` +
`parameters: ${JSON.stringify(params)} `
);
// Also, the context contains the `request`, which is a Fetch API `Request`
// instance to be sent over the network.
const request: Request = context.request;
console.log(`${request.method} ${request.url}`);
// Call the `next` async function to send the request and get the response.
const response: Response = await next(context);
// The response is a Fetch API `Response` object.
console.log(`Received response: ${response.status} ${response.statusText}`);
console.log(await response?.text());
// A middleware returns a response.
return response;
}
Note
|
Request and Response are Fetch API interfacesThe Vaadin middleware does not invent a new data structure to represent the network request and response, but uses the interfaces declared by the Fetch API specification instead. See the MDN web docs to learn more about the Request API and Response API. |
To use a middleware, when the Vaadin TypeScript client is instantiated, include your middleware in the middlewares
array option:
import {ConnectClient} from '@vaadin/flow-frontend/Connect';
import {MyLogMiddleware} from './my-log-middleware';
const client = new ConectClient({
endpoint: '/connect',
middlewares: [MyLogMiddleware]
});
export default client;
Alternatively, you can modify the middlewares
array property on the existing client, for example, if you use a generated client:
import client from './generated/connect-client.default';
import {MyLogMiddleware} from './my-log-middleware';
client.middlewares = [MyLogMiddleware];
Note
|
If you modify the middlewares array, only calls initiated after the modification will use the new middlewares array. To avoid issues related with that, it is better to avoid the modification of middlewares, or only modify the middlewares before the first call. |
To make a low-level modification on the request in a middleware, replace the context.request
with a new Fetch API Request
instance:
import {Middleware, MiddlewareContext, MiddlewareNext} from '@vaadin/flow-frontend/Connect';
// An example middleware that uses a different server for selected requests
export const MyApiDispatcherMiddleware: Middleware = async function(
context: MiddlewareContext,
next: MiddlewareNext
) {
if (context.endpoint === 'ExternalEndpoint') {
const url = context.request.url.replace(
'https//my-app.example.com',
'https://external-endpoint.example.com'
);
context.request = new Request(url, context.request);
}
return await next(context);
};
A middleware can also replace the response by returning a custom Response
instance:
import {Middleware, MiddlewareContext, MiddlewareNext} from '@vaadin/flow-frontend/Connect';
// An example middleware that returns an empty response instead of calling the backend endpoint
export const MyStubMiddleware: Middleware = async function(
context: MiddlewareContext,
next: MiddlewareNext
) {
if (context.endpoint === 'StubEndpoint') {
//
return new Response('{}');
}
return await next(context);
}