GraphQL vs REST in PHP: A War of Architectures or Tools for Different Tasks?
\n\nWhen you open your code editor once again to write a new endpoint for your PHP application, you can't shake that feeling of déjà vu. Create a controller again? Write validation again? Or maybe it's time to try something new? The debate between GraphQL and REST in the PHP development world resembles the eternal argument between "Lara" and "Symfony" — everyone defends their stack until they're hoarse. But let's be honest: both approaches are not a religion, but tools. And today we'll break them down to the nuts and bolts, look at real code, and decide when REST API in PHP is your choice, and when you should take a closer look at GraphQL in PHP.
\n\nA Quick Primer: What's What?
\n\nREST (Representational State Transfer) is an architectural style built on the principles of resources and HTTP methods. You hit /api/users, you get a list of users. Want one? Add /api/users/42. Everything is logical, predictable, and straightforward.
GraphQL is a query language created by Facebook. You are not tied to URLs. You send a single request to a single endpoint (e.g., /graphql) and say: "Give me the name of user 42, their last 5 posts, and the number of likes under each." The server returns exactly what you asked for. Not a byte more.
It would seem that GraphQL is the winner on points. But don't rush to throw away good old REST. Each has its own pitfalls, especially in the context of PHP development.
\n\nArchitecture Comparison: From Theory to Code
\n\nREST: A Classic
\n\nIn PHP, REST is implemented through routing. Frameworks like Laravel or Symfony do this elegantly. An example of a typical REST controller in Laravel:
\n\n<?php\n\nnamespace App\\Http\\Controllers\\Api;\n\nuse App\\Models\\User;\nuse Illuminate\\Http\\Request;\n\nclass UserController extends Controller\n{\n public function index()\n {\n return User::all();\n }\n\n public function show($id)\n {\n $user = User::with('posts.comments')->findOrFail($id);\n return response()->json($user);\n }\n\n public function store(Request $request)\n {\n $validated = $request->validate([\n 'name' => 'required|string',\n 'email' => 'required|email|unique:users',\n ]);\n\n $user = User::create($validated);\n return response()->json($user, 201);\n }\n}\n\nThe advantages are obvious: simplicity of caching (HTTP cache, Varnish), clear URL structure, wide support for tools (Postman, Swagger). The downsides are the problems of over-fetching and under-fetching. If the frontend only needs user names, but you're pulling all model fields in the response — that's over-fetching. If you need a name and a list of friends, but you make two requests — that's under-fetching.
\n\nGraphQL: Flexibility with a Catch
\n\nFor implementing GraphQL in PHP, there are excellent libraries: webonyx/graphql-php (pure PHP) and lighthouse-php/lighthouse (for Laravel). An example of a schema and resolver using graphql-php:
\n\n<?php\n\nuse GraphQL\\GraphQL;\nuse GraphQL\\Type\\Definition\\ObjectType;\nuse GraphQL\\Type\\Definition\\Type;\nuse GraphQL\\Type\\Schema;\n\n$userType = new ObjectType([\n 'name' => 'User',\n 'fields' => [\n 'id' => Type::int(),\n 'name' => Type::string(),\n 'email' => Type::string(),\n 'posts' => [\n 'type' => Type::listOf($postType),\n 'resolve' => function ($user) {\n return getPostsByUserId($user['id']);\n }\n ],\n ],\n]);\n\n$queryType = new ObjectType([\n 'name' => 'Query',\n 'fields' => [\n 'user' => [\n 'type' => $userType,\n 'args' => [\n