Build Symfony REST API with OpenAPI and Swagger UI Integration

Build Symfony REST API with OpenAPI and Swagger UI Integration

Summary:

Learn how to create a REST API in Symfony 7.2 with a /api/users/{id} endpoint, document it using OpenAPI YAML, and integrate Swagger UI using nelmio/api-doc-bundle. This beginner-friendly guide walks you through a clean, hybrid setup from scratch.

June 5, 2025

This guide shows you how to build your first REST API endpoint (/api/users/{id}) in Symfony 7.2, document it with OpenAPI YAML, and integrate Swagger UI for interactive testing. Using nelmio/api-doc-bundle and a hybrid approach, we’ll keep code clean, generate openapi.yaml, and set up docs with minimal effort. 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)

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 below line,

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 command php bin/console make:entity User

  • Set name (string, not nullable).
  • Set email (string, not nullable).
// 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\Annotation\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.

 

Step 5: Configure OpenAPI Documentation

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: Users

 

Step 7: Set Up Swagger UI

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"}


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!

Anand Dattani

Author

Anand Dattani is a Senior Developer at BrainStream Technolabs. He is an experienced developer specializing in PHP and modern MVC frameworks, with expertise in backend architecture and building scalable web solutions.

Related Blog

Symfony

Migrating from FOSUserBundle to Symfony Security Bundle (with ResetPasswordBundle & VerifyEmailBundle)

If you're still using FOSUserBundle in your Symfony project, it's time to upgrade. FOSUserBundle was once the standard solution for user authentication and management in Symfony, but it is now deprecated and unsupported in Symfony 6 and beyond. The good...

Symfony

Secure Payment Gateway Integration with Symfony Webhooks

At Brainstream, we secure payment gateway webhooks for seamless integration with leading payment gateways using advanced Symfony techniques. This guide shares practical steps for safe, reliable payment processing.

Symfony

Building Secure Video Streaming with Signed URLs

Video streaming platforms, like an OTT video platform I’ve recently worked on, need to ensure that content is accessible only to authorised users. Without proper security, videos can be easily accessed or shared, leading to revenue loss or piracy. One...

newslatter_bg_image
newslatter_image

Keep up-to-date with our newsletter.

Sign up for our newsletter to receive weekly updates and news directly to your inbox.