Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Hydra: Describiendo las clases de la API, las operaciones y más

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Así que, al menos a alto nivel, entendemos que cada recurso tendrá una clave @typey que esta página -a través de las claves supportedClass y supportedProperty - define qué significa ese tipo, qué propiedades tiene y mucha información sobre cada propiedad.

Ahora mismo, sólo tenemos un recurso API, por lo que sólo tenemos una entrada ensupportedClass, ¿verdad? ¡Pues sorpresa! Hay otra llamada Entrypoint! Y otra llamada ConstraintViolation, que define el recurso que se devuelve cuando nuestra API tiene un error de validación.

El recurso del punto de entrada

Hablemos de esta clase Entrypoint: es una idea bastante bonita. Ya sabemos que cuando vamos a /api, obtenemos, más o menos, la versión HTML de una "página de inicio" de la API. Pues bien, ¡también hay una versión JSON-LD de esta página! Hay un enlace para verla al final de esta página, pero vamos a llegar a ella de otra manera.

Busca tu terminal: podemos utilizar curl para ver el aspecto de la "página principal" para el formato JSON-LD:

curl -X GET 'https://localhost:8000/api' -H "accept: application/ld+json"

En otras palabras: haz una petición GET a /api, pero anuncia que quieres que te devuelvan el formato JSON-LD. También enviaré eso a jq - una utilidad que hace que JSON tenga un aspecto bonito - simplemente sáltate eso si no lo tienes instalado. Y... ¡boom!

¡Saluda a la página de inicio de tu API! Como cada URL representa un recurso único, incluso esta página es un recurso: es... un recurso "Punto de entrada". Tiene los mismos@context, @id y @type, con una "propiedad" real llamada cheeseListing. Esa propiedad es el IRI del recurso de colección del listado de quesos.

Por cierto, ¡esto se describe en nuestro documento JSON-LD! La clase Entrypoint tiene una propiedad: cheeseListing con el tipo hydra:Link - eso es interesante. Y, es bastante feo, pero la parte rdfs:range es aparentemente una forma de describir que el recurso al que se refiere esta propiedad es una "colección" que tendrá una propiedadhydra:member, que será un array donde cada elemento es de tipoCheeseListing. ¡Woh!

Hola Hydra

Así que JSON-LD consiste en añadir más contexto a tus datos especificando que nuestros recursos contendrán claves especiales como @context, @id y @type. Sigue siendo JSON normal, pero si un cliente entiende JSON-LD, va a poder obtener mucha más información sobre tu API, de forma automática.

Pero en la Plataforma API, hay otra cosa que vas a ver todo el tiempo, ¡y ya la estamos viendo! La Hidra, que es algo más que un monstruo acuático de muchas cabezas de la mitología griega.

Vuelve a /api/docs.jsonld. De la misma manera que esto apunta al documento externoxmls para que podamos referenciar cosas como xmls:integer, también estamos apuntando a un documento externo llamado hydra que define más "tipos" o "vocabulario" que podemos utilizar.

Esta es la idea: JSON-LD nos proporcionó el sistema para decir que este dato es de este tipo y este otro tipo. Hydra es una extensión de JSON-LD que añade nuevos vocablos. Dice:

Espera un segundo. JSON-LD es genial y divertido y un excelente invitado a la cena. Pero para que un cliente y un servidor puedan realmente comunicarse, necesitamos más ¡> lenguaje compartido! Necesitamos una forma de definir "clases" dentro de mi API, las propiedades de esas clases y si cada una es legible y escribible. Ah, y también necesitamos también necesitamos poder comunicar las operaciones que admite un recurso: ¿puedo hacer una petición DELETE a este recurso para eliminarlo? ¿Puedo hacer una solicitud PUT para actualizarlo? ¿Qué formato de datos debo esperar de cada operación? ¿Y cuál es la verdadera identidad de Batman?

Hydra tomó el sistema JSON-LD y le añadió una nueva "terminología" -llamada "vocabulario"- que permite definir completamente cada aspecto de tu API.

Hydra frente a OpenAPI

Llegados a este punto, casi seguro que estás pensando:

Pero espera, esto suena en serio, es exactamente lo mismo que obtuvimos de nuestro documento JSON de OpenAPI.

Y... ¡sí! Si cambiamos la URL a /api/docs.json, se trata de la especificación OpenAPI. Y si la cambiamos a .jsonld, de repente tenemos la especificación JSON-LD con Hydra.

Entonces, ¿por qué tenemos ambos? En primer lugar, sí, estos dos documentos hacen básicamente lo mismo: describen tu API en un formato legible por la máquina. El formato JSON-LD e Hydra es un poco más potente que OpenAPI: es capaz de describir algunas cosas que OpenAPI no puede. Pero OpenAPI es más común y tiene más herramientas construidas a su alrededor. Así que, en algunos casos, tener una especificación OpenAPI será útil -como usar Swagger- y otras veces, el documento JSON-LD Hydra será útil. Con la Plataforma API, tienes ambas cosas.

¡Ufff! Bien, ¡basta de teoría! Volvamos a construir y personalizar nuestra API.

Leave a comment!

7
Login or Register to join the conversation
Authoritas Avatar
Authoritas Avatar Authoritas | posted hace 2 años

Wow, this is AMAZING! 🎉🥳Can't wait to play with it. I had wondered how some of our Java devs had setup Swagger so easily and now I know. Thanks! Great stuff, as per usual!

1 Reply

Hello,

Don't know why I have this error.

>curl -X GET 'https://127.0.0.1:8000/api' -H "accept: application/ld+json"

curl: (3) URL using bad/illegal format or missing URL
---------------------------------------------------------------------------------------------------------------------------------------------------------------
>php bin/console debug:router

Name Method Scheme Host Path
------------------------------------- -------- -------- ------ -------------------------------------
_twig_error_test ANY ANY ANY /_error/{code}.{_format}
api_entrypoint ANY ANY ANY /api/{index}.{_format}
api_doc ANY ANY ANY /api/docs.{_format}
api_jsonld_context ANY ANY ANY /api/contexts/{shortName}.{_format}
api_cheese_listings_get_collection GET ANY ANY /api/cheese_listings.{_format}
api_cheese_listings_post_collection POST ANY ANY /api/cheese_listings.{_format}
api_cheese_listings_get_item GET ANY ANY /api/cheese_listings/{id}.{_format}
api_cheese_listings_delete_item DELETE ANY ANY /api/cheese_listings/{id}.{_format}
api_cheese_listings_put_item PUT ANY ANY /api/cheese_listings/{id}.{_format}

Can someone do what should I do?

Thank you in advance

Reply

Hey zahariastefan462

That's very odd. Try using double quotes instead of single quotes for your host parameter

1 Reply
Bedoui A. Avatar
Bedoui A. Avatar Bedoui A. | posted hace 2 años

For Windows users who encountred issues with the curl command, you need to add --ssl-no-revoke at the end
So the full command is :
curl -X GET "https://localhost:8000/api" -H "accept: application/ld+json" --ssl-no-revoke

Reply
Tac-Tacelosky Avatar
Tac-Tacelosky Avatar Tac-Tacelosky | posted hace 2 años

Love API-Platform, using it as much as possible now.

I also use the Symfony proxy, to make my domains easier to work with (symfony proxy:domain:add my-project, then use https://my-project.wip). Can you suggest how to call fetch with a proxy (https://127.0.0.1:7080 is the default).

I keep thinking there must be a way to define the proxy, like in curl, but I can't find it. For now, I'm simply using localhost and the port, as you do in the tutorial, but then I have to always start the servers in the right order. Is there a way to set the proxy in the fetch call? Or somewhere else?

Reply

Hiya Tac-Tacelosky!

Always nice to hear from you :). Beyond what the docs talk about for this - https://symfony.com/doc/cur... - I am not sure, I don't personally use the proxy stuff. I would expect that setting the proxy in your OS and "Re-Applying it" if you're using Chrome (like the docs say) would be enough. Do those docs help at all, or no?

Cheers!

Reply
Cat in space

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

Este tutorial funciona muy bien para Symfony 5 y la Plataforma API 2.5/2.6.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "api-platform/core": "^2.1", // v2.4.3
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "doctrine/annotations": "^1.0", // 1.10.2
        "doctrine/doctrine-bundle": "^1.6", // 1.11.2
        "doctrine/doctrine-migrations-bundle": "^2.0", // v2.0.0
        "doctrine/orm": "^2.4.5", // v2.7.2
        "nelmio/cors-bundle": "^1.5", // 1.5.5
        "nesbot/carbon": "^2.17", // 2.19.2
        "phpdocumentor/reflection-docblock": "^3.0 || ^4.0", // 4.3.1
        "symfony/asset": "4.2.*|4.3.*|4.4.*", // v4.3.11
        "symfony/console": "4.2.*", // v4.2.12
        "symfony/dotenv": "4.2.*", // v4.2.12
        "symfony/expression-language": "4.2.*|4.3.*|4.4.*", // v4.3.11
        "symfony/flex": "^1.1", // v1.17.6
        "symfony/framework-bundle": "4.2.*", // v4.2.12
        "symfony/security-bundle": "4.2.*|4.3.*", // v4.3.3
        "symfony/twig-bundle": "4.2.*|4.3.*", // v4.2.12
        "symfony/validator": "4.2.*|4.3.*", // v4.3.11
        "symfony/yaml": "4.2.*" // v4.2.12
    },
    "require-dev": {
        "symfony/maker-bundle": "^1.11", // v1.11.6
        "symfony/stopwatch": "4.2.*|4.3.*", // v4.2.9
        "symfony/web-profiler-bundle": "4.2.*|4.3.*" // v4.2.9
    }
}
userVoice