# Server Middleware

## Content

**Middleware** is a key mechanism for the server to process connections and messages, used to execute custom logic before events (such as connection establishment or message reception) reach hooks. The server itself has no business logic and relies on middleware to implement specific functionality.
The middleware mechanism provided by the server allows developers to **customize the logic** for handling connections and messages. This document introduces its usage and features.

## **Use Cases**

* User authentication
* Permission validation
* Log management

## Registration

The [server.use](/spreadjs/api/collaboration/js-collaboration/classes/Server#use) API is used to register middleware. It supports two usages:

1. Single Registration

    ```typescript
    server.use('connect', async (context, next) => {
        console.log('Client connecting:', context.connection.id);
        await next();
    });
    server.use('message', async (context, next) => {
        console.log('Message received:', context.data);
        await next();
    });
    ```
2. Batch Registration

    ```typescript
    server.use({
        connect: async (context, next) => {
            console.log('Client connecting:', context.connection.id);
            await next();
        },
        message: async (context, next) => {
            console.log('Message received:', context.data);
            await next();
        }
    });
    ```

## Execution Order

Multiple registered middleware will be executed in the order of registration.

```typescript
server.use('connect', (context, next) => {
    console.log('Middleware1');
    await next();
});
server.use('connect', (context, next) => {
    console.log('Middleware2');
    await next();
});
server.use('connect', (context, next) => {
    console.log('Middleware3');
    await next();
});
server.on('connect', () => {
    console.log('Hook');
});
// output
//Middleware1
//Middleware2
//Middleware3
// Hook
```

## Errors

If the `next` method is called with an `error` parameter, the following occurs:

* Subsequent middleware execution is stopped.
* The server’s built-in error handler is triggered, the error is returned to the client, triggering the client's `error` event.
* For `connect` middleware, the connection request is rejected (since the connection is not yet established, the connect hook will not be triggered).

```typescript
// server side
server.use('connect', async (context, next) => {
    console.log('Middleware1');
    await next();
});
server.use('connect', async (context, next) => {
    console.log('Middleware2');
    await next(new Error('test middleware error'));
});
server.use('connect', async (context, next) => {
    console.log('Middleware3');
    await next();
});
server.on('connect', () => {
    console.log('Hook');
});

// Output:
//Middleware1
//Middleware2
```

**Client Receives Error**

```typescript
// client side
connection.on('error', (error) => {
    console.log(error.message); // will output "test middleware error"
});
```

## Short-Circuiting

If the `next()` function is not called within a middleware:

* Subsequent middleware execution is stopped and the event handling process will not execute.
* For `connect` middleware, ensure `next()` is always called; otherwise, the connection request will remain pending until it times out and is closed.
* For `message` middleware, short-circuiting can be used to terminate the processing flow early.

```typescript
// Server side
server.use('message', async (context, next) => {
    console.log('Middleware1');
    await next();
});
server.use('message', async (context, next) => {
    console.log('Middleware2');
    // Short-circuit: next() is not called
});
server.use('message', async (context, next) => {
    console.log('Middleware3');
    await next();
});
server.on('message', () => {
    console.log('Hook');
});

// Output:
// Middleware1
// Middleware2
```

## Interface

```typescript
export interface IMiddlewares {
    connect?: IMiddleware<IConnectMiddlewareContext>;  // When connecting
    message?: IMiddleware<IMessageMiddlewareContext>;  // When receive messages from clients
}
```

## Next Steps

Use Middleware for Authentication and Permission Validation, see [User Authentication and Permissions](/spreadjs/docs/spreadjs-collaboration-server/collaboration-framework/js-collaboration/user-authentication-and-permissions).