Request & Response
XinAdmin defines a unified request-response format, with frontend axios and backend Laravel collaborating to implement automated request handling, error prompting, and exception handling.
Response Data Structure
interface ResponseStructure<T = any> {
success: boolean // Whether the request succeeded
msg: string // Response message
data?: T // Response data
errorCode?: number // Error code
showType?: number // Display type: 0-success message, 1-warning message, 2-error message, 3-success notification, 4-warning notification, 5-error notification, 99-silent
status?: number // HTTP status code
description?: string // Detailed description
placement?: string // Notification position: top/topLeft/topRight/bottom/bottomLeft/bottomRight
}
Success Response Example
{
"success": true,
"data": {
"id": 1,
"name": "Administrator"
},
"msg": "ok",
"showType": 0
}
Failure Response Example
{
"success": false,
"data": [],
"msg": "Username or password incorrect",
"showType": 1
}
ShowType Display Types
ShowType is used to control how frontend prompts are displayed, defined in App\Enum\ShowType.
Backend Response Trait
Controllers inheriting from BaseController can use response methods provided by the RequestJson trait.
Success Response
// Return success response with data
return $this->success(['id' => 1, 'name' => 'test']);
// Return success response with message
return $this->success('Operation successful');
// Return success response with empty data
return $this->success();
Error Response
// Return error response with message
return $this->error('Operation failed');
// Return error response with data
return $this->error(['field' => 'Username already exists'], 'Failed to create user');
Warning Response
// Return warning response
return $this->warn('Data expired, please refresh page');
Notification Response
// Notification response, supports custom position and type
return $this->notification(
'Operation Reminder', // Notification title
'Your session is about to expire', // Notification description
ShowType::WARN_NOTIFICATION, // Notification type
'topRight' // Notification position
);
Throwing Responses
Instead of returning responses, you can throw responses to interrupt execution:
// Throw success response and interrupt
$this->throwSuccess(['id' => 1], 'Created successfully');
// Throw error response and interrupt
$this->throwError('Insufficient permissions');
// Throw warning response and interrupt
$this->throwWarn('Data not saved');
Use Case: Interrupt execution in the middle of business logic without manually return.
public function create(Request $request)
{
// Throw directly on validation failure
if (!$request->name) {
$this->throwError('Name cannot be empty');
}
// Continue execution if validation passes
$this->service->create($request->all());
return $this->success();
}
Frontend Request Wrapper
Frontend uses axios wrapper to uniformly handle request responses.
Request Configuration
// Create axios instance
const instance = axios.create({
baseURL: import.meta.env.VITE_BASE_URL || '',
timeout: 10000,
responseType: 'json',
withCredentials: false,
});
Automatic Handling
Frontend automatically handles:
- Auto-attach Token: Except for login endpoint, automatically adds
Authorization: Bearer {token} to request header
- Auto-attach Language: Automatically attaches
User-Language to request header
- Request Deduplication: Duplicate requests with same parameters are automatically cancelled
- Error Prompting: Automatically displays Message or Notification based on
showType
- 401 Handling: Automatically redirects to login page
HTTP Status Code Handling
Business Error Handling
When success: false, handled according to showType:
switch (showType) {
case 0: // Message success prompt
if (msg) message.success(msg);
break;
case 1: // Message warning prompt
if (msg) message.warning(msg);
break;
case 2: // Message error prompt
if (msg) message.error(msg);
break;
case 3: // Notification success
if (msg) notification.success({ message: msg });
break;
case 4: // Notification warning
if (msg) notification.warning({ message: msg });
break;
case 5: // Notification error
if (msg) notification.error({ message: msg });
break;
case 99: // Silent, no prompt displayed
break;
}
Paginated Data
type ListResponse<T> = {
data: T[] // Data list
page: number // Current page number
total: number // Total record count
per_page: number // Items per page
current_page: number // Current page number
}
Response Example
{
"success": true,
"data": {
"data": [
{ "id": 1, "name": "User1" },
{ "id": 2, "name": "User2" }
],
"page": 1,
"total": 100,
"per_page": 10,
"current_page": 1
},
"msg": "ok",
"showType": 0
}
Usage Examples
Backend Controller
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\BaseController;
use App\Services\Admin\UserService;
use Illuminate\Http\JsonResponse;
use Xin\AnnoRoute\RequestAttribute;
use Xin\AnnoRoute\Route\GetRoute;
use Xin\AnnoRoute\Route\PostRoute;
#[RequestAttribute('/admin/user', 'admin.user')]
class UserController extends BaseController
{
public function __construct(
protected UserService $service
) {}
#[GetRoute('/{id}')]
public function show(int $id): JsonResponse
{
$user = $this->service->find($id);
if (!$user) {
return $this->error('User not found');
}
return $this->success($user);
}
#[PostRoute]
public function store(Request $request): JsonResponse
{
$data = $request->validate([
'name' => 'required|string|max:50',
'email' => 'required|email|unique:users',
]);
try {
$user = $this->service->create($data);
return $this->success($user, 'User created successfully');
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
#[PostRoute('/batch-import')]
public function batchImport(Request $request): JsonResponse
{
$file = $request->file('file');
if (!$file) {
return $this->throwError('Please upload file');
}
// Large data import, may take longer
$result = $this->service->import($file);
if ($result['failed'] > 0) {
// Has failed data, show warning
return $this->warn($result, 'Import completed, but ' . $result['failed'] . ' records failed');
}
return $this->success($result, 'Import successful');
}
}
Frontend Call
import createAxios from '@/utils/request';
// Get user details
async function getUser(id: number) {
const response = await createAxios({
url: `/admin/user/${id}`,
method: 'get',
});
return response.data.data;
}
// Create user
async function createUser(data: UserData) {
const response = await createAxios({
url: '/admin/user',
method: 'post',
data,
});
return response.data.data;
}
// Batch import
async function importUsers(file: File) {
const formData = new FormData();
formData.append('file', file);
const response = await createAxios({
url: '/admin/user/batch-import',
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data' },
});
return response.data.data;
}
Exception Handling
Global Exception Handling
ExceptionsHandler uniformly handles uncaught exceptions:
// Validation exception
if ($exception instanceof ValidationException) {
return $this->error($exception->errors(), 'Parameter validation failed');
}
// Business exception
if ($exception instanceof RepositoryException) {
return $this->error($exception->getMessage());
}
// Authentication exception
if ($exception instanceof AuthenticationException) {
return $this->error([], 'Please login first')->setStatusCode(401);
}
HttpResponseException
Business code can directly return responses by throwing HttpResponseException:
use App\Exceptions\HttpResponseException;
public function update(Request $request, int $id)
{
$user = User::find($id);
if (!$user) {
throw new HttpResponseException([
'success' => false,
'msg' => 'User not found',
'showType' => ShowType::ERROR_MESSAGE,
]);
}
// ...
}
Best Practices
Always use $this->success() or $this->error() to return responses in controllers, maintaining consistency.
2. Choose showType Appropriately
- Regular operation feedback: Use default Message
- Important operations requiring user confirmation: Use Notification
- Background silent processing: Use SILENT
3. Error Message Localization
// Use language pack
return $this->error(__('user.not_found'));
4. Frontend Unified Error Handling
Avoid manually handling response errors in business code, rely on frontend's unified interceptor handling.