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

Más formatos: HAL Y CSV

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

La Plataforma API admite múltiples formatos de entrada y salida. Puedes comprobarlo entrando en /api/cheeses.json para obtener JSON "en bruto" o .jsonld o incluso .html, que carga la documentación HTML. Pero añadir la extensión de esta manera es una especie de "truco" que la Plataforma API ha añadido sólo para facilitar el juego.

En su lugar, se supone que debes elegir qué "formato" o "representación" quieres para un recurso mediante la negociación del contenido. La documentación ya lo hace y lo muestra en los ejemplos: envía una cabecera Accept, que la Plataforma API utiliza para averiguar qué formato debe utilizar el serializador.

Añadir un nuevo formato: HAL

Por defecto, la Plataforma API utiliza 3 formatos... pero en realidad admite un montón más: JSON-API, HAL JSON, XML, YAML y CSV. Busca tu terminal y ejecuta:

php bin/console debug:config api_platform

Esta es nuestra configuración actual de la Plataforma API, incluyendo los valores por defecto. Echa un vistazo a formats. Muestra los 3 formatos que hemos visto hasta ahora y los tipos mime de cada uno, que es el valor que debe enviarse en la cabecera Accept para activarlos.

Vamos a añadir otro formato. Para ello, copia toda esta sección de formatos. Luego abre config/packages/api_platform.yaml y pégalo aquí

api_platform:
... lines 2 - 3
formats:
jsonld:
mime_types:
- application/ld+json
json:
mime_types:
- application/json
html:
mime_types:
- text/html

Así nos aseguraremos de mantener estos tres formatos. Ahora, vamos a añadir uno nuevo: jsonhal. Este es uno de los otros formatos que la Plataforma API admite de forma inmediata. A continuación, añademime_types: y luego el tipo de contenido estándar para este formato: application/hal+json.

api_platform:
... lines 2 - 13
jsonhal:
mime_types:
- application/hal+json

¡Genial! Y así de fácil... ¡toda nuestra API soporta un nuevo formato! Actualiza los documentos y abre la operación GET para ver el listado de quesos 1. Antes de pulsar ejecutar, abre el desplegable de formato y... ¡eh! Selecciona application/hal+json. ¡Ejecuta!

Saluda al formato JSON HAL: una especie de formato "competidor" de JSON-LD o JSON-API, que pretenden estandarizar cómo debes estructurar tu JSON: dónde deben vivir tus datos, dónde deben vivir los enlaces, etc.

En HAL, tienes una propiedad _links. Ahora sólo tiene un enlace a self, pero éste suele contener enlaces a otros recursos.

Esto es más divertido si probamos la operación de recolección GET: seleccionaapplication/hal+json y pulsa Ejecutar. Es bastante chulo ver cómo los distintos formatos "anuncian" la paginación. HAL utiliza _links con las claves first, last y next. Si estuviéramos en la página 2, también habría un campo prev.

Disponer de este formato puede ser útil o no para ti; lo increíble es que puedes elegir lo que quieras. Además, entender los formatos desbloquea otras posibilidades interesantes.

Formato CSV

Por ejemplo, ¿qué pasa si, por alguna razón, tú o alguien que utilice tu API quiere poder obtener los recursos del listado de quesos como CSV? Sí, ¡es totalmente posible! Pero en lugar de hacer que ese formato esté disponible globalmente para todos los recursos, vamos a activarlo sólo para nuestro CheeseListing.

De nuevo dentro de esa clase, bajo esta clave especial attributes, añade"formats". Si quieres mantener todos los formatos existentes, tendrás que enumerarlos aquí: jsonld json , luego... veamos, ah sí, html y jsonhal. Para añadir un nuevo formato, digamos csv, pero ponlo en una nueva matriz con text/csvdentro.

... lines 1 - 15
/**
* @ApiResource(
... lines 18 - 25
* attributes={
... line 27
* "formats"={"jsonld", "json", "html", "jsonhal", "csv"={"text/csv"}}
* }
* )
... lines 31 - 35
*/
class CheeseListing
... lines 38 - 168

Este es el tipo mime para el formato. No necesitamos añadir tipos mime para los otros formatos porque ya están configurados en nuestro archivo de configuración.

¡Vamos a probarlo! Ve a actualizar los documentos. De repente, sólo para este recurso... que, vale, ahora sólo tenemos un recurso... pero CheeseListing tiene ahora un formato CSV. Selecciónalo y ejecútalo.

¡Ya está! Y podemos probarlo directamente en el navegador añadiendo .csv al final. Mi navegador lo ha descargado... así que vamos a dar la vuelta y a cat ese archivo para ver qué aspecto tiene. Los saltos de línea parecen un poco extraños, pero es un CSV válido.

Un ejemplo mejor es obtener la lista completa: /api/cheeses.csv. Veamos también qué aspecto tiene en el terminal. ¡Esto es increíble! La función de descarga de CSV más rápida que he construido nunca.

Y... ¡sí! También puedes crear tu propio formato y activarlo de esta misma manera. Es una idea poderosa: nuestro único recurso de la API puede representarse de muchas maneras diferentes, incluyendo formatos -como el CSV- que no necesitas... hasta esa situación aleatoria en la que de repente los necesitas de verdad.

A continuación, es hora de dejar que los usuarios creen listados de queso con los datos que quieran. ¡Es hora de añadir la validación!

Leave a comment!

14
Login or Register to join the conversation
Igor Avatar

Hi ,

how do I add format application/x-www-form-urlencode ?
why the default formats aren't supported?

Reply

Hey,

That's output format, why do you need to output in application/x-www-form-urlencode format? It's not very useful as I know.

Cheers!

Reply
Benoit-L Avatar
Benoit-L Avatar Benoit-L | posted hace 1 año

Hi,

When I add this :

api_platform:
formats:
jsonld:
mime_types:
- application/ld+json
json:
mime_types:
- application/json
html:
mime_types:
- text/html

in the yaml file, I have the following error that is displayed : The routing file "C:\wamp64\www\bookshop-api\config/routes/api_platform.yaml" contains unsupported keys for "api_platform": "formats". Expected one of: "resource", "type", "prefix", "path", "host", "schemes", "methods", "defaults", "requirements", "options", "condition", "controller", "name_prefix", "trailing_slash_on_root", "locale", "format", "utf8", "exclude", "stateless" in C:\wamp64\www\bookshop-api\config/routes/api_platform.yaml (which is being imported from "C:\wamp64\www\bookshop-api\src\Kernel.php").

Reply
David-G Avatar
David-G Avatar David-G | Benoit-L | posted hace 10 meses | edited

I reply very late, but maybe that can be useful for other members.

This error is because you modify the wrong files. the right file is in the folder config/packages/api_platform.yaml (not config/routes/...)

1 Reply

Hey David-G,

Thank you for this tip! I bet it might be useful to someone.

Cheers!

Reply

Hey Benoit L.

This is odd, I just checked our course code, and also ApiPlatform source and this key should be named formats:. Have you updated course code? or not? Can you try to reinstall vendors and manually clear the caches.

Cheers

Reply
Benoit-L Avatar

I had to create the project using this command : composer create-project symfony/skeleton bookshop-api because the server was not running without that.

Reply

Hey Benoit L.

and which version on ApiPlatform do you have installed? Do you still have this error?

Cheers!

Reply

Hey guys,
1) what about exporting word docx formats. What we should exactlly do ? Do we need to create a normolizer like this https://api-platform.com/do... and what we should put there?
2) Does there a way to acess to _format inside my controller, In fact apiplatform they force remove the _format from the open api document.
https://github.com/api-plat...

Cheers

Reply

Hey ahmedbhs!

1) Hmm, I'm not sure! I guess docx is just a special XML format that you can generate? In the case, you would create a custom encoder for it I believe - I don't think you would need a normalizer (but I could be wrong). The normalizer takes the Object and converts it to an array structure.Then, the encoder takes that array structure and converts it into the final format - like xml, json, etc. Hence, I think (?) you might only need a custom encoder, but it's possible you might also need a custom normalizer. In general, this is more of a "Symfony serializer" question than an API Platform question: if you're able to teach the serializer how to export to docx, then API Platform should do it. Here are some details about that: https://symfony.com/doc/current/serializer.html#adding-normalizers-and-encoders

2) You should be able to access it either via $request->getRequestFormat() or via $request->attributes->get('_format').

Let me know how it goes :)

Cheers!

Reply
Jean-tilapin Avatar
Jean-tilapin Avatar Jean-tilapin | posted hace 2 años

Hi,
I need to display dots on a map (using mapbox), with some other informations (address, name, etc.). It works best if I can provide to my map GeoJson data...What is the best way to do that?

Of course, I can make my user's device process the regular collection it gets from the "GET" method, but API Platform should be able to do that more efficiently, right? Through a controller with a specific route, generating my GeoJson "manually"? Through Content Negotiation? Or any other way? What would you recommend? (I don't *always* need to get that GeoJson format for my list, only for that map)

Reply

Hey @Xav!

Hmm, I’m not sure. Do you already have an api endpoint of “locations” (or something)? And now you want to be able to sometimes turn that same collection, but formatted in GeoJson? If so, a custom format might indeed make sense.

I’ve never done that myself (we use formats in this video that are already supported in core). They do have Docs on this - https://api-platform.com/do... - but I’ve never tried that before. You basically want a custom normalizer for this situation that builds your data... and then you want to use the standard json encoder.

Let me know if this solution seems to fit you’re use case or not :).

Cheers!

Reply

The CSV format is a feature desired in most enterprise applications. It allows users to export static and other data like trial balances to spread sheets for further processing., Is there a export to PDF available or being planning or is there a way to incorporate an existing symfony or PHP library ? This is something that I would like to see in future versions atleast it helps us generate reports using the server resources and a cron job without having any user intervention sample use cases : credit card statements, invoices, regulatory reports etc. Wouldn't want to generate at the browser end.

Reply

Hey Sridhar,

I'm not 100% sure if it is going to be implemented in future versions, most probably not, but I can't quickly find any info about it. So feel free to open an issue in the ApiPlatform project repository to be more sure or get feedback from maintainers directly why it won't be implemented.

For now, you probably need only custom solution for this, I can recommend you to take a look at KnpSnappyBundle that allow you to generate PDF files on server side thanks to Wkhtmltopdf that you also need to install on your server.

I hope this helps!

Cheers!

1 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