
Build a Symfony REST API with OpenAPI and Swagger UI Integration
To add Swagger UI to a Symfony REST API, install nelmio/api-doc-bundle, describe your endpoints with OpenAPI attributes and config/packages/nelmio_api_doc.yaml, then generate openapi.yaml and serve it through Swagger UI at /docs.
This guide walks through every step in Symfony 7.2, from creating a new project to testing GET /api/users/{id} directly in the browser.
Follow these steps from scratch to create a fully documented API!
Prerequisites
- PHP 8.2+
- MySQL 8.0.42
- Composer
- Symfony CLI
- Node.js and npm (for Swagger UI)
Why Document a Symfony API with OpenAPI and Swagger?
Clear API documentation helps developers understand, test, and integrate Symfony REST APIs without repeatedly checking backend code.
OpenAPI provides a structured format for describing endpoints, request parameters, responses, and authentication requirements. Meanwhile, Swagger UI turns that information into an interactive interface where developers can explore and test API requests directly in a browser.
For growing development teams, this makes onboarding easier and improves collaboration between frontend and backend developers. It also helps external partners integrate with your platform more efficiently.
With NelmioApiDocBundle, Symfony developers can generate OpenAPI documentation from application routes and PHP attributes, reducing the effort needed to maintain API documentation as an application evolves.
Step 1: Create the Symfony Project
Create a new Symfony project:
composer create-project symfony/skeleton brainstream_symfony7_api_demo cd brainstream_symfony7_api_demo
Install required packages:
composer require symfony/orm-pack symfony/maker-bundle nelmio/api-doc-bundle:^5.3 doctrine/doctrine-fixtures-bundle
Configure your MySQL database in .env.local
Add the line below,
DATABASE_URL="mysql://user:your_secure_password@localhost:3306/brainstream_symfony7_api_demo?serverVersion=8.0&charset=utf8mb4" Create the database: Run command php bin/console doctrine:database:create
Step 2: Create the User Entity
Generate a User entity with id, name, and email:
Run the command: php bin/console make:entity User
- Set name (string, not nullable).
- Set email (string, not nullable).
For production applications, developers should review schema changes carefully. If you need to migrate your database without downtime, consider backward-compatible migrations, online schema operations, and controlled deployment strategies.
// entity src/Entity/User.php content
<?php
// src/Entity/User.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ORM\Table(name: 'user')]
class User
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column]
private string $name;
#[ORM\Column]
private string $email;
public function getId(): ?int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getEmail(): string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
}
Generate and apply migrations:
php bin/console make:migration
php bin/console doctrine:migrations:migrate
Step 3: Add Sample Data with Fixtures
Create a fixture to insert a sample user.
// Add below content in it
<?php
// src/DataFixtures/AppFixtures.php
namespace App\DataFixtures;
use App\Entity\User;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
class AppFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
$user = new User();
$user->setName('Jan Dox');
$user->setEmail('jan@example.com');
$manager->persist($user);
$manager->flush();
}
}
Load the fixture:
php bin/console doctrine:fixtures:load --no-interaction This creates a user with id=1.
Step 4: Build the API Endpoint
Create a controller for /api/users/{id}:
//Create UserController, Add below content in it
<?php
// src/Controller/UserController.php
namespace App\Controller;
use App\Entity\User;
use OpenApi\Attributes as OA;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Attribute\Route;
class UserController
{
#[Route('/api/users/{id}', methods: ['GET'])]
#[OA\Tag(name: 'Users')]
public function getUser(User $user): JsonResponse
{
return new JsonResponse([
'id' => $user->getId(),
'name' => $user->getName(),
'email' => $user->getEmail(),
]);
}
}
The #[OA\Tag] tags the endpoint for Swagger UI.Building a larger API? See our Symfony development services for help with secure REST API development, third-party integrations, and scalable backend applications.
Step 5: Configure OpenAPI Docs with NelmioApiDocBundle
Define API details in config/packages/nelmio_api_doc.yaml as below.
documentation:
info:
title: Brainstream Symfony API
version: 1.0.0
paths:
/api/users/{id}:
get:
summary: Get user by ID
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
description: User details
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
description: User not found
components:
schemas:
User:
type: object
properties:
id: { type: integer }
name: { type: string }
email: { type: string }
example:
id: 1
name: Jan Dox
email: jan@example.com
areas:
path_patterns: ['^/api']
models:
names:
- { alias: User, type: App\Entity\User }Step 6: Generate OpenAPI YAML
Generate openapi.yaml:
mkdir -p public/docs
php bin/console nelmio:apidoc:dump --format=yaml > public/docs/openapi.yaml
Automate in composer.json, add below to scripts block.
"scripts": {
"generate-docs": "php bin/console nelmio:apidoc:dump --format=yaml > public/docs/openapi.yaml"
}
Run: composer generate-docs
The generated openapi.yaml looks like:
openapi: 3.0.0
info:
title: 'Brainstream Symfony API'
version: 1.0.0
paths:
'/api/users/{id}':
get:
tags:
- Users
summary: 'Get user by ID'
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
description: 'User details'
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
description: 'User not found'
components:
schemas:
User:
required:
- id
- name
- email
properties:
id:
type: integer
name:
type: string
email:
type: string
type: object
example:
id: 1
name: 'Jan Dox'
email: jan@example.com
tags:
- name: UsersStep 7: Set Up Swagger UI in Symfony
Install Swagger UI via npm:
npm install swagger-ui-dist
Copy the dist folder to public/docs:
cp -r node_modules/swagger-ui-dist/* public/docs/
Update public/docs/index.html:
Replace the url in SwaggerUIBundle:
const ui = SwaggerUIBundle({
url: "/docs/openapi.yaml",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
layout: "StandaloneLayout"
});
Note: If Node.js isn’t installed, download the Swagger UI tarball from https://github.com/swagger-api/swagger-ui/releases/tag/v5.17.14, extract it, and copy the dist folder to public/docs.
Create a /docs route:
// Add below content in it
<?php
// src/Controller/DocsController.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class DocsController
{
#[Route('/docs', name: 'api_docs')]
public function index(): Response
{
return new Response(file_get_contents(__DIR__ . '/../../public/docs/index.html'));
}
}
Clear symfony cache: php bin/console cache:clear
Start the symfony internal server: symfony server:start
Visit https://127.0.0.1:8000/docs to see Swagger UI. Test /api/users/{id} with id=1 which will give you the below json response.
{"id":1,"name":"Jan Dox","email":"jan@example.com"}FAQs
1. What is zero-downtime database migration?
Zero-downtime database migration is the process of moving or upgrading a production database while keeping the application available, often using replication or Change Data Capture (CDC) to synchronize data before a controlled cutover.
2. Can NelmioApiDocBundle render Swagger UI without npm?
Yes. NelmioApiDocBundle provides a built-in Swagger UI controller. Configure the Swagger UI route and install the required Symfony Twig and Asset packages. This approach avoids manually installing and copying swagger-ui-dist through npm.
3. Should I use API Platform instead of NelmioApiDocBundle?
It depends on your project. API Platform is useful when you need a framework for building APIs with features such as resource handling, validation, and automatic documentation. NelmioApiDocBundle is useful when you already have custom Symfony controllers and want to generate OpenAPI documentation without changing your existing API architecture.
4. How do I protect the /docs page in production?
You can restrict documentation routes using Symfony security access-control rules, authentication, or environment-specific routing. Avoid exposing internal API details or sensitive examples through publicly accessible documentation.
Conclusion
You’ve built and documented your first REST API endpoint in Symfony 7.2! This hybrid approach generates clear OpenAPI docs, powering Swagger UI. Try adding more endpoints and share your API confidently!
If you need professional support for a larger Symfony project, compare the top Symfony development companies in India before choosing your development partner.
Need a Production-Ready Symfony API?
Need help building or scaling a production-ready Symfony API? Work with a Symfony development company or hire Symfony developers to plan, develop, and maintain your application.
Get a Free Symfony Consultation
Table of contents
BLOGS
Learn & Grow with Us
Get the latest updates on trends and strategies that shape the business world. Our insights are here to keep you informed and inspired.

2026 Generative AI Playbook: A Strategic Guide for Business Leaders
The digital landscape has officially crossed a Rubicon. If 2023…

Agentic Commerce in 2026: How AI Agents Are Changing Online Shopping
Agentic commerce is online shopping where AI agents discover, compare,…

AI Advisory & Roadmap Services: How Businesses Build Smarter AI Strategies?
Artificial intelligence is changing how businesses operate. However, many companies…

AI Chatbots in Healthcare: Benefits and Use Cases That Are Transforming Patient Care
AI Chatbots in Healthcare are changing faster than ever. Patients…











