About us Guides Projects Contacts
Админка
please wait

Lumen is Laravel's micro-framework optimized for building lightning-fast APIs and microservices. By stripping away Laravel's full-stack features, Lumen delivers impressive performance while maintaining Laravel's elegant syntax. This guide covers building production APIs with Lumen from a senior developer's perspective.

Why Lumen

Lumen excels in specific scenarios:

  1. Performance: Faster than full Laravel for API-only apps
  2. Familiar Syntax: Same patterns as Laravel
  3. Microservices: Perfect for small, focused services
  4. Low Overhead: Only what you need, nothing more
  5. Easy Upgrade: Can migrate to Laravel when needed

Best for: APIs, microservices, webhook handlers, and services that don't need views, sessions, or cookies.

Installation

# Create a new Lumen project
composer create-project --prefer-dist laravel/lumen my-api
# Navigate to the project
cd my-api
# Start the development server
php -S localhost:8000 -t public

Project Structure

my-api/
├── app/
│ ├── Console/
│ ├── Events/
│ ├── Exceptions/
│ ├── Http/
│ │ ├── Controllers/
│ │ └── Middleware/
│ ├── Jobs/
│ ├── Listeners/
│ ├── Models/
│ └── Providers/
├── bootstrap/
│ └── app.php
├── config/
├── database/
│ ├── factories/
│ ├── migrations/
│ └── seeders/
├── public/
│ └── index.php
├── resources/
├── routes/
│ └── web.php
├── storage/
├── tests/
├── .env
└── composer.json

Configuration

Enable Features

In bootstrap/app.php, enable what you need:

<?php
require_once __DIR__.'/../vendor/autoload.php';
(new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
dirname(__DIR__)
))->bootstrap();
$app = new Laravel\Lumen\Application(
dirname(__DIR__)
);
// Enable facades (optional, for Laravel-style syntax)
$app->withFacades();
// Enable Eloquent ORM
$app->withEloquent();
// Register service providers
$app->register(App\Providers\AppServiceProvider::class);
$app->register(App\Providers\AuthServiceProvider::class);
// $app->register(App\Providers\EventServiceProvider::class);
// Load middleware
$app->middleware([
App\Http\Middleware\CorsMiddleware::class,
]);
$app->routeMiddleware([
'auth' => App\Http\Middleware\Authenticate::class,
'throttle' => App\Http\Middleware\ThrottleRequests::class,
]);
// Load routes
$app->router->group([
'namespace' => 'App\Http\Controllers',
], function ($router) {
require __DIR__.'/../routes/web.php';
});
return $app;

Environment Variables

.env:

APP_NAME=MyAPI
APP_ENV=local
APP_KEY=base64:your-random-32-character-key
APP_DEBUG=true
APP_URL=http://localhost
APP_TIMEZONE=UTC
LOG_CHANNEL=stack
LOG_SLACK_WEBHOOK_URL=
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myapi
DB_USERNAME=root
DB_PASSWORD=
CACHE_DRIVER=file
QUEUE_CONNECTION=sync

Routing

Basic Routes

routes/web.php:

<?php
/** @var \Laravel\Lumen\Routing\Router $router*/
// Health check
$router->get('/', function () {
return response()->json([
'name' => config('app.name'),
'version' => '1.0.0',
'status' => 'ok'
]);
});
// Resource routes
$router->get('/users', 'UserController@index');
$router->get('/users/{id}', 'UserController@show');
$router->post('/users', 'UserController@store');
$router->put('/users/{id}', 'UserController@update');
$router->delete('/users/{id}', 'UserController@destroy');
// Route groups
$router->group(['prefix' => 'api/v1'], function () use ($router) {
// Public routes
$router->post('/auth/login', 'AuthController@login');
$router->post('/auth/register', 'AuthController@register');
// Protected routes
$router->group(['middleware' => 'auth'], function () use ($router) {
$router->get('/me', 'AuthController@me');
$router->post('/auth/logout', 'AuthController@logout');
// Users
$router->get('/users', 'UserController@index');
$router->get('/users/{id}', 'UserController@show');
$router->put('/users/{id}', 'UserController@update');
$router->delete('/users/{id}', 'UserController@delete');
});
});

Route with Middleware

$router->group([
'prefix' => 'admin',
'middleware' => ['auth', 'admin'],
], function () use ($router) {
$router->get('/dashboard', 'AdminController@dashboard');
$router->get('/users', 'AdminController@users');
});

Controllers

Basic Controller

app/Http/Controllers/UserController.php:

<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
class UserController extends Controller
{
/**
* List all users with pagination.
*/
public function index(Request $request): JsonResponse
{
$this->validate($request, [
'page' => 'integer|min:1',
'limit' => 'integer|min:1|max:100',
'search' => 'string|max:100',
]);
$limit = $request->input('limit', 20);
$query = User::query();
if ($search = $request->input('search')) {
$query->where('name', 'like', "%{$search}%")
->orWhere('email', 'like', "%{$search}%");
}
$users = $query->paginate($limit);
return response()->json([
'data' => $users->items(),
'meta' => [
'total' => $users->total(),
'page' => $users->currentPage(),
'limit' => $users->perPage(),
'pages' => $users->lastPage(),
]
]);
}
/**
* Get a single user.
*/
public function show(int $id): JsonResponse
{
$user = User::find($id);
if (!$user) {
return response()->json([
'error' => 'User not found'
], 404);
}
return response()->json(['data' => $user]);
}
/**
* Create a new user.
*/
public function store(Request $request): JsonResponse
{
$this->validate($request, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
'password' => 'required|string|min:8',
]);
$user = User::create([
'name' => $request->input('name'),
'email' => $request->input('email'),
'password' => app('hash')->make($request->input('password')),
]);
return response()->json([
'data' => $user,
'message' => 'User created successfully'
], 201);
}
/**
* Update user.
*/
public function update(Request $request, int $id): JsonResponse
{
$user = User::find($id);
if (!$user) {
return response()->json([
'error' => 'User not found'
], 404);
}
$this->validate($request, [
'name' => 'string|max:255',
'email' => 'email|unique:users,email,' . $id,
]);
$user->update($request->only(['name', 'email']));
return response()->json([
'data' => $user,
'message' => 'User updated successfully'
]);
}
/**
* Delete user.
*/
public function destroy(int $id): JsonResponse
{
$user = User::find($id);
if (!$user) {
return response()->json([
'error' => 'User not found'
], 404);
}
$user->delete();
return response()->json(null, 204);
}
}

Middleware

CORS Middleware

app/Http/Middleware/CorsMiddleware.php:

<?php
namespace App\Http\Middleware;
use Closure;
class CorsMiddleware
{
public function handle($request, Closure $next)
{
$headers = [
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers' => 'Content-Type, Authorization, X-Requested-With',
'Access-Control-Max-Age' => '86400',
];
if ($request->isMethod('OPTIONS')) {
return response()->json(null, 200, $headers);
}
$response = $next($request);
foreach ($headers as $key => $value) {
$response->header($key, $value);
}
return $response;
}
}

Authentication Middleware

app/Http/Middleware/Authenticate.php:

<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Factory as Auth;
class Authenticate
{
protected $auth;
public function __construct(Auth $auth)
{
$this->auth = $auth;
}
public function handle($request, Closure $next, $guard = null)
{
if ($this->auth->guard($guard)->guest()) {
return response()->json([
'error' => 'Unauthorized'
], 401);
}
return $next($request);
}
}

Database Operations

Raw Queries

<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
class ProductController extends Controller
{
public function index(Request $request)
{
$this->validate($request, [
'price_min' => 'integer|min:0',
'price_max' => 'integer|min:0',
'page' => 'integer|min:0',
]);
$priceMin = $request->input('price_min', 0);
$priceMax = $request->input('price_max', 0);
$page = $request->input('page', 0);
$pageLength = 30;
$products = DB::select("
SELECT p.id, p.name, p.price, c.name as category
FROM products p
LEFT JOIN categories c ON p.category_id = c.id
WHERE TRUE
AND (:price_min = 0 OR p.price >= :price_min1)
AND (:price_max = 0 OR p.price <= :price_max1)
ORDER BY p.created_at DESC
LIMIT :page_length OFFSET :offset
", [
'price_min' => $priceMin,
'price_min1' => $priceMin,
'price_max' => $priceMax,
'price_max1' => $priceMax,
'page_length' => $pageLength,
'offset' => $page * $pageLength,
]);
if (empty($products)) {
return response()->json([
'message' => 'No products found'
], 404);
}
return response()->json([
'data' => $products
]);
}
}

Eloquent Models

app/Models/User.php:

<?php
namespace App\Models;
use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Laravel\Lumen\Auth\Authorizable;
class User extends Model implements AuthenticatableContract, AuthorizableContract
{
use Authenticatable, Authorizable, HasFactory;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
public function posts()
{
return $this->hasMany(Post::class);
}
}

Validation

In Controller

public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
'password' => 'required|min:8|confirmed',
'role' => 'in:user,admin',
'tags' => 'array',
'tags.*' => 'string|max:50',
]);
// Validation passed; continue...
}

Custom Error Response

app/Exceptions/Handler.php:

<?php
namespace App\Exceptions;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Validation\ValidationException;
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Throwable;
class Handler extends ExceptionHandler
{
public function render($request, Throwable $exception)
{
if ($exception instanceof ValidationException) {
return response()->json([
'error' => 'Validation failed',
'details' => $exception->errors()
], 422);
}
if ($exception instanceof ModelNotFoundException) {
return response()->json([
'error' => 'Resource not found'
], 404);
}
if ($exception instanceof AuthorizationException) {
return response()->json([
'error' => 'Forbidden'
], 403);
}
if ($exception instanceof HttpException) {
return response()->json([
'error' => $exception->getMessage()
], $exception->getStatusCode());
}
// Log unexpected errors
if (env('APP_DEBUG')) {
return response()->json([
'error' => $exception->getMessage(),
'trace' => $exception->getTrace()
], 500);
}
return response()->json([
'error' => 'Internal server error'
], 500);
}
}

UTF-8 JSON Response

Ensure proper encoding:

return response()->json($data, 200, [], JSON_UNESCAPED_UNICODE);

Or globally in middleware:

public function handle($request, Closure $next)
{
$response = $next($request);
if ($response->headers->get('Content-Type') === 'application/json') {
$response->setEncodingOptions(JSON_UNESCAPED_UNICODE);
}
return $response;
}

API Documentation

Use mpociot/laravel-apidoc-generator:

composer require mpociot/laravel-apidoc-generator
# Generate docs
php artisan apidoc:generate

Key Takeaways

  1. Enable only what you need: Facades and Eloquent are optional
  2. Use route groups: Organize and apply middleware efficiently
  3. Validate everything: Never trust input
  4. Handle errors gracefully: Custom exception handler
  5. Keep controllers thin: Move logic to services
  6. Consider upgrading: Migrate to Laravel if you need more features

Lumen delivers exceptional performance for API workloads—perfect for microservices where every millisecond counts.

 
 
 
Языки
Темы
Copyright © 1999 — 2026
ZK Interactive