Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Crear tu primer ApiResource

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Estamos a punto de construir una API para la importantísima tarea de permitir que los dragones muestren su tesoro. Ahora mismo, nuestro proyecto no tiene ni una sola entidad de base de datos... pero vamos a necesitar una para almacenar todo ese tesoro.

Generar nuestra primera entidad

Busca tu terminal y ejecuta primero

composer require maker --dev

para instalar Maker Bundle. Luego ejecuta:

php bin/console make:entity

¡Perfecto! Llamemos a nuestra entidad DragonTreasure. Entonces nos hace una pregunta que quizá no hayas visto antes: Mark this class as an API platform resource? Pregunta porque la API Platform está instalada. Di no porque vamos a hacer este paso manualmente dentro de un momento.

Bien, empecemos a añadir propiedades. Empieza con name como cadena, con una Longitud por defecto de 255, y haz que no sea anulable. Después, añade description con un tipo text, y haz que no sea anulable. También necesitamos un value, como... cuánto vale el tesoro. Eso será un integer no anulable. Y simplemente debemos tener un coolFactor: los dragones necesitan especificar lo impresionante que es este tesoro. Eso será un número del 1 al 10, así que que sea un integer no anulable. Luego, createdAt datetime_immutable que no sea anulable... y por último, añade una propiedad isPublished, que será de tipo boolean, también no anulable. Pulsa "intro" para terminar.

¡Uf! Hasta ahora no hay nada muy especial. Esto ha creado dos clases: DragonTreasureRepository (de la que no nos vamos a preocupar), y la propia entidad DragonTreasure con $id, $name, $description, $value, etc junto con los métodos getter y setter. Maravillosamente aburrido. Sin embargo, hay un pequeño error en esta versión de MakerBundle. Ha generado un método isIsPublished(). Cambiémoslo por getIsPublished().

Configurar la base de datos

Muy bien, ya tenemos nuestra entidad. Ahora necesitamos una migración para su tabla... ¡pero eso puede ser un poco difícil ya que aún no tenemos configurada nuestra base de datos! Voy a utilizar Docker para esto. La receta de DoctrineBundle nos dio un bonito archivo docker-compose.yml que arranca Postgres, así que... ¡vamos a usarlo! Ve a tu terminal y ejecuta:

docker-compose up -d

Si no quieres utilizar Docker, siéntete libre de arrancar tu propio motor de base de datos y luego, en .env o .env.local, configura DATABASE_URL. Como estoy utilizando Docker además del binario symfony, no necesito configurar nada. El servidor web Symfony verá automáticamente la base de datos de Docker y configurará la variable de entorno DATABASE_URL por mí.

Bien, para hacer la migración, ejecuta:

symfony console make:migration

Este symfony console es igual que ./bin/console excepto que inyecta la variable de entorno DATABASE_URL para que el comando pueda hablar con la base de datos Docker. ¡Perfecto! Gira y comprueba el nuevo archivo de migración... sólo para asegurarte de que no contiene ninguna sorpresa extraña. ¡Tiene buena pinta! Así que vuelve a girar y ejecuta esto con:

symfony console doctrine:migrations:migrate

¡Listo!

Exponiendo nuestro primer recurso API

Ahora tenemos una entidad y una tabla de base de datos. Pero si vas y actualizas la documentación... todavía no hay nada. Lo que tenemos que hacer es decirle a la API Platform que exponga nuestra entidad DragonTreasure como un recurso API. Para ello, ve encima de la clase y añade un nuevo atributo llamado ApiResource. Pulsa "tab" para añadir la declaración use.

¡Listo! En cuanto hagamos eso... y actualicemos... ¡guau! ¡La documentación está viva! Ahora muestra que tenemos seis rutas diferentes: Uno para recuperar todos los recursos DragonTreasure, uno para recuperar un DragonTreasure individual, uno para crear un DragonTreasure, dos que editan un DragonTreasure y uno para eliminarlo. Y esto es algo más que documentación. Estas rutas funcionan.

Ve y haz clic en "Probar", y luego en "Ejecutar". En realidad no devuelve nada porque nuestra base de datos está vacía, pero nos da un código de estado 200 con algo de JSON vacío. En breve hablaremos de todas las demás claves extravagantes de la respuesta.

Pero quiero mencionar una cosa. Como acabamos de ver, la forma más sencilla de crear un conjunto de rutas API es añadir este atributo ApiResource sobre tu clase de entidad. Pero en realidad puedes añadir este atributo sobre cualquier clase: no sólo entidades. Es algo de lo que hablaremos en un futuro tutorial: puede ser una buena forma de separar el aspecto de tu API del de tu entidad, especialmente en las API más grandes. Pero, de nuevo, eso es para más adelante. Ahora mismo, utilizar ApiResource sobre nuestra entidad va a funcionar de maravilla.

Descubramos un poco más esta genial documentación interactiva. ¿De dónde ha salido esto? ¿Cómo es que nuestra aplicación tiene por arte de magia un montón de rutas nuevas? ¿Y de verdad les gustan los tacos a los dragones? ¡Averigüémoslo a continuación!

Leave a comment!

14
Login or Register to join the conversation
Szymon Avatar

Hello,

When I run symfony console make:migration then:

[critical] Error thrown while running command "make:migration". Message: "An exception occurred in the driver: could not find driver"

In ExceptionConverter.php line 87:

  An exception occurred in the driver: could not find driver


In Exception.php line 28:

  could not find driver


In Driver.php line 34:

  could not find driver

How to fix it? I am working with PHP8.2 and Symfony6...

1 Reply

Hey Szymon!

I know this error! If you're using the code from the course, then we're using Postgres. The error means that you need to install the pgsql php extension - e.g. like described here (the exact setup instructions will depend on your operating system): https://stackoverflow.com/questions/10085039/postgresql-pdoexception-with-message-could-not-find-driver#answer-48858539

Or, if you'd rather use Mysql, you can skip the migrations and run doctrine:schema:update --force instead (after configuring your app to talk to your mysql database).

Let me know if this helps!

Cheers!

3 Reply
Szymon Avatar
Szymon Avatar Szymon | weaverryan | posted hace 6 meses | edited

yeah, that's right. I am using Windows, and I just removed semicolon in xampp/php/php.ini

extension=pdo_pgsql
...
extension=pgsql

and it's running good.

But it's kind weird for me, because I am not using XAMPP, I installed php directly in my computer, but most important is that working anyway :)

additional query: what is the difference between using MySQL and PostgreSQL in this tutorial? I remember in Symfony5 tutorial we used MySQL.
Is chance to see this database tables in friendly environemnt like phpMyAdmin or something similar? does it require a more difficult setup?

1 Reply

Hey Szymon,

In this tutorial, the only difference you'll find if you use MySQL instead of PostgreSQL is the migration files. The queries generated by Doctrine will be specific to MySQL, but besides that, nothing else will be different.

Is chance to see this database tables in friendly environemnt like phpMyAdmin or something similar? does it require a more difficult setup?

I found this tool for Postgres. However, I don't know how hard it might be to set it up. https://github.com/phppgadmin/phppgadmin

Cheers!

Reply
Ken Avatar

Are there anyway to create custom API such as api/hello-world without entity

Reply

Hey @Ken

Yes, APIPlatform does not force you to create entities for your resources, you can do the exact same thing with data model classes
Here are the docs: https://api-platform.com/docs/core/dto/#using-data-transfer-objects-dtos

Cheers!

Reply
Yorane Avatar

Hi !

Thanks for the tutorial :)
I have some trouble about the symfony console make:migration part.
Without modifing docker-compose.ymlfile, when I try to apply the migrations (after boot the container with docker compose up -d) i get the next error :

SQLSTATE[08006] [7] connection to server at "127.0.0.1", port 5432 failed: Connection refused

    Is the server running on that host and accepting TCP/IP connections?

Do you have a solution ?
For information, I'm working on Windows with WSL.

Thank you !

Reply

Hey @Yorane

I'm afraid I cannot help you with your Docker setup because I don't use it under WSL, but I have a question, does it only happens when you try to load the migrations?

Reply
Yorane Avatar

Hi MolloKhan,

It's OK, I resolved my problem :)
Not only, every time my server try to connect to the container database.

To resolve the problem, we have to change the IP address in the .envfile with the container IP.

1 Reply

Oh cool, well done @Yorane
Tip: when you use Docker, you need to run any command through the Symfony CLI, so it can inject the correct env var values
symfony console app:foo

Cheers!

Reply
Kev Avatar
Kev Avatar Kev | posted hace 3 meses | edited

Hey i always get this

500
Undocumented
Error: Internal Server Error.

This is my docker-compose.yaml regarding the mysql container

database:
    container_name: database
    image: mysql
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: dsv
      MYSQL_DATABASE: dsv_db
      MYSQL_USER: dsv
      MYSQL_PASSWORD: dsv
    ports:
      - '4306:3306'
      #to avoid lower versions/ or existing install / conflicts
      # this volume will create new mysql8 folder
    volumes:
      - ./mysql:/var/lib/mysql``

and my .env

DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8&charset=utf8mb4"

and response body:

{
  "@context": "/api/contexts/Error",
  "@type": "hydra:Error",
  "hydra:title": "An error occurred",
  "hydra:description": "An exception occurred in the driver: could not find driver",
  "trace": [

... more log below

I am sure i have the drivers i need but..any suggestion would be welcomed. Thank you!

Reply

Hey @Kev!

Well that's annoying! You're using Mysql, so the "could not find driver" is referring to the PHP pdo_mysql driver. Exactly HOW you install this depends on your system - e.g. with Ubuntu, it's often something like apt install php-mysql. Also, remember to restart your web server (e.g. the symfony binary) after installing the driver. And FINALLY. if you have multiple php binaries installed and you're not sure which one the symfony binary is using, you can always run symfony local:php:list to find out.

Cheers!

1 Reply
Kev Avatar

Hey @weaverryan ,

Thanks for your answer, the general idea is that i already have the php-mysql driver installed. I have it as a docker-compose procedure script for a container, AND i have it on my local ubuntu machine installed.

The default .env build with the default postrgres variable is the same result.

Weirdish issue really!

Cheers!

Reply

That IS weird. That usually means that some different, unexpected PHP binary is being used (that doesn't have the driver installed).... but these are a pain to figure out!

1 Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "api-platform/core": "^3.0", // v3.0.8
        "doctrine/annotations": "^1.0", // 1.14.2
        "doctrine/doctrine-bundle": "^2.8", // 2.8.0
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
        "doctrine/orm": "^2.14", // 2.14.0
        "nelmio/cors-bundle": "^2.2", // 2.2.0
        "nesbot/carbon": "^2.64", // 2.64.1
        "phpdocumentor/reflection-docblock": "^5.3", // 5.3.0
        "phpstan/phpdoc-parser": "^1.15", // 1.15.3
        "symfony/asset": "6.2.*", // v6.2.0
        "symfony/console": "6.2.*", // v6.2.3
        "symfony/dotenv": "6.2.*", // v6.2.0
        "symfony/expression-language": "6.2.*", // v6.2.2
        "symfony/flex": "^2", // v2.2.4
        "symfony/framework-bundle": "6.2.*", // v6.2.3
        "symfony/property-access": "6.2.*", // v6.2.3
        "symfony/property-info": "6.2.*", // v6.2.3
        "symfony/runtime": "6.2.*", // v6.2.0
        "symfony/security-bundle": "6.2.*", // v6.2.3
        "symfony/serializer": "6.2.*", // v6.2.3
        "symfony/twig-bundle": "6.2.*", // v6.2.3
        "symfony/ux-react": "^2.6", // v2.6.1
        "symfony/validator": "6.2.*", // v6.2.3
        "symfony/webpack-encore-bundle": "^1.16", // v1.16.0
        "symfony/yaml": "6.2.*" // v6.2.2
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
        "symfony/debug-bundle": "6.2.*", // v6.2.1
        "symfony/maker-bundle": "^1.48", // v1.48.0
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/stopwatch": "6.2.*", // v6.2.0
        "symfony/web-profiler-bundle": "6.2.*", // v6.2.4
        "zenstruck/foundry": "^1.26" // v1.26.0
    }
}
userVoice