# Error Handling and Pagination

## Error Handling

All service methods can throw `FailureResponse`:

```typescript
import { FailureResponse } from '@applica-software-guru/iam-client';

try {
  await iam.auth.login({ username: 'user@test.com', password: 'wrong' });
} catch (error) {
  if (error instanceof FailureResponse) {
    if (error.handled) {
      // Known application error (e.g. invalid credentials, user not active)
      console.log(error.message); // 'iam.error.invalid-credentials'
    } else {
      // Unexpected error (network failure, server down, etc.)
      console.error(error.message);
    }
  }
}
```

### FailureResponse

| Property  | Type      | Description                                                                     |
| --------- | --------- | ------------------------------------------------------------------------------- |
| `handled` | `boolean` | `true` if the error is a known application error; `false` for unexpected errors |
| `message` | `string`  | Error code (e.g. `iam.error.invalid-credentials`) or error message              |

### Static constructors

```typescript
FailureResponse.handled('iam.error.invalid-credentials'); // known error
FailureResponse.unhandled('Internal Server Error'); // unexpected error
```

### Common Error Codes

| Code                            | Description                    |
| ------------------------------- | ------------------------------ |
| `iam.error.invalid-credentials` | Invalid credentials            |
| `iam.error.unauthorized`        | Missing or invalid token       |
| `iam.error.not-authorized`      | Insufficient permissions (403) |
| `iam.error.user-not-active`     | User is disabled               |
| `iam.error.bad-activation-code` | Invalid activation code        |

### HTTP status mapping

The `HttpClient` automatically maps HTTP status codes to `FailureResponse`:

| HTTP Status   | Result                                                |
| ------------- | ----------------------------------------------------- |
| 200-299       | Success (JSON parsed)                                 |
| 401           | `FailureResponse.handled('iam.error.unauthorized')`   |
| 403           | `FailureResponse.handled('iam.error.not-authorized')` |
| Other 4xx/5xx | `FailureResponse.unhandled(statusText)`               |

After HTTP success, `requestAndValidate()` also checks `responseCode === 'ok'` and throws `FailureResponse.handled(responseCode)` if not.

---

## Pagination

Services with search endpoints (`users`, `tenants`, `projects`, `devices`) support pagination:

```typescript
const result = await iam.users.search({
  keyword: 'test',
  pageable: {
    page: 0, // Page number (0-indexed)
    rowsPerPage: 25 // Items per page
  }
});

console.log(result.users.content); // User[]
console.log(result.users.totalElements); // Total number of results
console.log(result.users.totalPages); // Total number of pages
console.log(result.users.number); // Current page number
console.log(result.users.size); // Page size
```

If `pageable` is not specified, the backend returns all results (unpaged).

### Response structure

Each search response contains a paginated field named after the entity (e.g. `users`, `tenants`, `projects`, `devices`):

```typescript
{
  responseCode: 'ok',
  users: {             // or tenants, projects, devices
    content: [...],    // Array of entities
    totalElements: 42,
    totalPages: 3,
    number: 0,
    size: 20
  }
}
```
