Essentials
Requests & Responses
Handle HTTP input and output
Learn how to work with HTTP requests and return properly formatted JSON responses.
Request Basics
Access the current Symfony Request instance in controllers (injected as $this->request
):
public function store()
{
// All JSON/form body input
$data = $this->request->request->all();
// Specific fields (null if missing)
$email = $this->request->request->get('email');
// With default value
$name = $this->request->request->get('name', 'Guest');
}
Getting Input Data
JSON Body
// POST /api/users
// Body: {"name": "John", "email": "[email protected]"}
public function store()
{
$name = $this->request->request->get('name');
$email = $this->request->request->get('email');
// Or get all (JSON auto parsed)
$data = $this->request->request->all();
// ['name' => 'John', 'email' => '[email protected]']
}
Query Parameters
// GET /api/users?page=2&limit=10
public function index()
{
$page = (int) $this->request->query->get('page', 1);
$limit = (int) $this->request->query->get('limit', 20);
}
Route Parameters
// Route: /users/{id}/posts/{postId}
public function show(string $id, string $postId)
{
// Parameters injected automatically
}
Headers
$token = $this->request->headers->get('Authorization');
$contentType = $this->request->headers->get('Content-Type');
Files
public function upload()
{
$file = $this->request->files->get('avatar');
if ($file) {
$path = $file->move('/uploads', $file->getClientOriginalName());
}
}
Response Helpers
Glueful provides consistent JSON response helpers:
Success Responses
use Glueful\Http\Response;
// Basic success (default message = "Success")
return Response::success($data);
// {"success": true, "message": "Success", "data": {...}}
// Custom message
return Response::success($users, 'Users retrieved');
// {"success": true, "message": "Users retrieved", "data": [...]}
// Created (201)
return Response::created($user);
// {"success": true, "message": "Created successfully", "data": {...}}
// No content (204)
return Response::noContent();
// HTTP 204 empty body
Error Responses
// Not found (404)
return Response::notFound('User not found');
// {
// "success": false,
// "message": "User not found",
// "error": {
// "code": 404,
// "timestamp": "2024-01-15T10:30:00Z",
// "request_id": "req_ab12cd34ef",
// "details": { ... } // only when provided
// }
// }
// Unauthorized (401)
return Response::unauthorized('Invalid token');
// Forbidden (403)
return Response::forbidden('Access denied');
// Validation error (422) - details show field errors
return Response::validation(['email' => 'Email is required']);
// Custom error with extra context
return Response::error('Something went wrong', 500, ['operation' => 'import']);
Pagination
public function index()
{
$page = (int) $this->request->query->get('page', 1);
$perPage = 20;
$users = $this->db->table('users')
->limit($perPage)
->offset(($page - 1) * $perPage)
->get();
$total = $this->db->table('users')->count();
return Response::paginated($users, $total, $page, $perPage);
}
// Returns (flattened pagination + default message):
// {
// "success": true,
// "message": "Data retrieved successfully",
// "data": [...],
// "current_page": 1,
// "per_page": 20,
// "total": 100,
// "total_pages": 5,
// "has_next_page": true,
// "has_previous_page": false
// }
Complete Examples
Simple CRUD
class TaskController
{
public function index()
{
$tasks = $this->db->table('tasks')->get();
return Response::success($tasks);
}
public function store()
{
$data = $this->request->request->all();
$task = $this->db->table('tasks')->insert([
'title' => $data['title'],
'description' => $data['description'] ?? null,
'completed' => false
]);
return Response::created($task);
}
public function show(string $id)
{
$task = $this->db->table('tasks')
->where('uuid', $id)
->first();
if (!$task) {
return Response::notFound('Task not found');
}
return Response::success($task);
}
public function update(string $id)
{
$data = $this->request->request->all();
$updated = $this->db->table('tasks')
->where('uuid', $id)
->update($data);
if (!$updated) {
return Response::notFound('Task not found');
}
return Response::success(null, 'Task updated');
}
public function destroy(string $id)
{
$deleted = $this->db->table('tasks')
->where('uuid', $id)
->delete();
if (!$deleted) {
return Response::notFound('Task not found');
}
return Response::noContent();
}
}
With Validation
public function store()
{
$data = $this->request->request->all();
// Validate
$validated = $this->validate($data, [
'title' => 'required|min:3',
'email' => 'required|email'
]);
// Validation passed
$task = $this->db->table('tasks')->insert($validated);
return Response::created($task);
}
Search & Filter
public function index()
{
$query = $this->db->table('products');
// Search
if ($search = $this->request->query->get('search')) {
$query->where('name', 'LIKE', "%{$search}%");
}
// Filter by category
if ($category = $this->request->query->get('category')) {
$query->where('category', $category);
}
// Sort
$sortBy = $this->request->query->get('sort', 'created_at');
$sortOrder = $this->request->query->get('order', 'desc');
$query->orderBy($sortBy, $sortOrder);
// Paginate
$page = (int) $this->request->query->get('page', 1);
$perPage = 20;
$products = $query
->limit($perPage)
->offset(($page - 1) * $perPage)
->get();
$total = $query->count();
return Response::paginated($products, $total, $page, $perPage);
}
Request Methods
Checking Request Method
if ($this->request->isMethod('POST')) {
// Handle POST
}
if ($this->request->isMethod('GET')) {
// Handle GET
}
Getting All Headers
$headers = $this->request->headers->all();
Getting Client IP
$ip = $this->request->getClientIp();
Checking for AJAX
if ($this->request->isXmlHttpRequest()) {
// AJAX request
}
Response Customization
Custom Status Code
return Response::success($data)->setStatusCode(202);
Custom Headers
return Response::success($data)
->header('X-Custom-Header', 'value')
->header('X-Rate-Limit', '100');
Download Response
// Provide your own file bytes then mark as download
$contents = file_get_contents('/path/to/file.pdf');
return Response::success(['file' => base64_encode($contents)])
->asDownload('file.pdf', 'application/pdf');
Or serve a real file (stream) with the helper:
return response()->file('/path/to/file.pdf'); // inline disposition
// For attachment: response()->file('/path/to/file.pdf', 'file.pdf', [], 'attachment');
File Response
return response()->file('/path/to/image.jpg');
Common Patterns
API with Meta Data
return Response::successWithMeta($users, [
'filters_applied' => ['status' => 'active'],
'generated_at' => date('c')
]);
// Returns:
// {
// "success": true,
// "message": "Data retrieved successfully",
// "data": [...],
// "filters_applied": {"status":"active"},
// "generated_at": "2024-01-15T10:30:00Z"
// }
Error with Details
return Response::error('Quota exceeded', 403, [
'plan' => 'free',
'limit' => 1000,
'current' => 1000,
'upgrade_url' => '/pricing'
]);
Conditional Response
public function show(string $id)
{
$user = $this->db->table('users')
->where('uuid', $id)
->first();
return $user
? Response::success($user)
: Response::notFound('User not found');
}
Best Practices
Always Return JSON
// ✅ Good
return Response::success($data);
// ❌ Avoid
return $data; // Might not be properly formatted
Use Appropriate Status Codes
// Create → 201
return Response::created($user);
// Delete → 204
return Response::noContent();
// Not found → 404
return Response::notFound();
// Validation error → 422
return Response::validation($errors);
Include Error Context
// ✅ Helpful
return Response::notFound('Product #' . $id . ' not found');
// ❌ Less helpful
return Response::notFound();
Troubleshooting
Empty request body?
- Check
Content-Type: application/json
header is set - Verify JSON is valid
Parameters not available?
- Route parameters must match method signature
- Query parameters use
$this->request->query->get()
- Body parameters use
$this->request->request->all()
/->get()
Response not JSON?
- Always use
Response::
helpers - Check you're returning the Response object
- Ensure JSON body has valid syntax
Need raw request data?
- Use
RequestHelper::getRequestData()
or controller's protectedgetRequestData()
Correlate errors?
- Use the
request_id
in error responses for tracing (logged automatically)
Next Steps
- Validation - Validate request data
- Controllers - Organize request handling
- Database - Query and store data