Core: Content type

Created on 18 Sep 2019  路  17Comments  路  Source: api-platform/core

Updated to 2.5.0 core

The content-type \"application/json\" is not supported. Supported MIME types are \"\".

how to fix?

bug invalid question

Most helpful comment

i found the same problem, it's fixed only by adding the input_formats attribute to the entity

@ApiResource( attributes={ "input_formats"={"json"={"application/ld+json"}}, "output_formats"={"json"={"application/ld+json"}} },

All 17 comments

Do you have a formats configuration in your api_platform.yaml config?
You can check with bin/console debug:config api_platform

default config when left empty :
```
api_platform:
formats:
jsonld:
mime_types:
- application/ld+json
json:
mime_types:
- application/json
html:
mime_types:
- text/html

```

Same here, updating from v2.4.7 to v2.5.0 triggers this error in custom actions.

Reverting to v2.4.7 in composer.lock without any changes in my codebase fixes the error.


Configuration is default symfony console debug:config api_platform:

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

It has errors only in custom actions (for me) that are defined like that:

<?php

namespace App\Controller;

use App\Entity\FooEntity;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

final class FooAction
{
    /**
     * @Route(
     *     name="api_foos_bars",
     *     path="/api/foos/{id}/bar_action",
     *     methods={"POST"},
     *     defaults={
     *         "_api_resource_class"=FooEntity::class,
     *         "_api_item_operation_name"="api_foos_bars"
     *     }
     * )
     *
     * @param FooEntity $foo
     * @param Request   $request
     *
     * @return Response
     */
    public function __invoke(FooEntity $foo, Request $request): Response
    {
        // ... nevermind ...
    }
}

Request looks like this:

POST /api/foos/42/bar_action HTTP/1.1
Accept: application/json+ld, */*
Accept-Encoding: gzip, deflate
Authorization: Bearer AUTH_JWT_TOKEN
Connection: keep-alive
Content-Length: 14
Content-Type: application/json
Host: example.com

{
    "some":"data"
}

Stacktrace:

Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException:
The content-type "application/json" is not supported. Supported MIME types are "".

  at vendor/api-platform/core/src/EventListener/DeserializeListener.php:135
  at ApiPlatform\Core\EventListener\DeserializeListener->getFormat(object(Request), array())
     (vendor/api-platform/core/src/EventListener/DeserializeListener.php:98)
  at ApiPlatform\Core\EventListener\DeserializeListener->onKernelRequest(object(RequestEvent), 'kernel.request', object(TraceableEventDispatcher))
     (vendor/symfony/event-dispatcher/Debug/WrappedListener.php:126)
  at Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke(object(RequestEvent), 'kernel.request', object(TraceableEventDispatcher))
     (vendor/symfony/event-dispatcher/EventDispatcher.php:260)
  at Symfony\Component\EventDispatcher\EventDispatcher->doDispatch(array(object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener)), 'kernel.request', object(RequestEvent))
     (vendor/symfony/event-dispatcher/EventDispatcher.php:235)
  at Symfony\Component\EventDispatcher\EventDispatcher->callListeners(array(object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener)), 'kernel.request', object(RequestEvent))
     (vendor/symfony/event-dispatcher/EventDispatcher.php:73)
  at Symfony\Component\EventDispatcher\EventDispatcher->dispatch(object(RequestEvent), 'kernel.request')
     (vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:168)
  at Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch(object(RequestEvent), 'kernel.request')
     (vendor/symfony/http-kernel/HttpKernel.php:127)
  at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
     (vendor/symfony/http-kernel/HttpKernel.php:68)
  at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
     (vendor/symfony/http-kernel/Kernel.php:198)
  at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
     (public/index.php:25)

Would you like to work on a Pull Request? A failing Behat test would already be awesome! There is probably a bug in DeserializerListener related to the formats refactoring I've done to introduce PATCH support.

I just checked, and now we assume that the format is accessible through resource metadata. It looks like it is not in your case. Could you please post the code of your class marked with @ApiResource?

Would you like to work on a Pull Request? A failing Behat test would already be awesome! There is probably a bug in DeserializerListener related to the formats refactoring I've done to introduce PATCH support.

I can try to make a PR in a few days.. like in Friday this week only. If no one will be faster or more familiar with codebase and Behat (using PHPUnit) :-)

I just checked, and now we assume that the format is accessible through resource metadata. It looks like it is not in your case. Could you please post the code of your class marked with @ApiResource?

You mean FooEntity in my example?

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ORM\Entity(repositoryClass="App\Repository\FooRepository")
 * @ApiResource(
 *     normalizationContext={"groups"={"user:read", "foo:read"}},
 *     itemOperations={"get", "put"},
 *     collectionOperations={"get"},
 * )
 */
class Foo implements UserInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @Groups({"user:read", "foo:read"})
     */
    protected $id;

    /** ... simple properties and some relations to other entities ... **/

    /**
     * @ORM\OneToMany(targetEntity="Bar", mappedBy="foos", cascade={"all"}, fetch="EXTRA_LAZY")
     * @Groups({"user:read"})
     */
    protected $bars;

    public function __construct()
    {
        parent::__construct();

        $this->bars = new ArrayCollection();
    }

    public function getId(): int { return $this->id; }

    /** @return Collection|Bar[] */
    public function getBars(): Collection { return $this->bars; }

    /**
     * @ApiProperty()
     * @Groups({"user:read"})
     */
    public function getBarsCount(): int { return $this->getBars()->count(); }
}

I don't get how it can work. The post operation isn't defined in your FooEntity. It's probably the problem.

I mean api_foos_bars is referenced but not defined. Defining it should fix your issue. Also, I strongly recommend you to use the recommended way to register custom controllers: https://api-platform.com/docs/core/controllers/

Oh, i need to define same route in annotation AND in controller? Or only in entity but NOT in controller? That wasn't clear from docs. Thanks.

Here is working example of configuration with v.2.5.0.

Entity annotation:

/**
 * @ORM\Entity(repositoryClass="App\Repository\FooRepository")
 * @ApiResource(
 *     normalizationContext={"groups"={"user:read", "foo:read"}},
 *     itemOperations={
 *         "get",
 *         "put",
 *         "foos_bars"={
 *             "controller"=FooAction::class,
 *             "method"="POST",
 *             "path"="/foos/{id}/bar_action"
 *         }
 *     },
 *     collectionOperations={"get"},
 * )
 */

And controller annotation 鈥撀爊one (0.o)

Now, second question related.

Imagine entity that has 3 custom operations with config/swagger context and so on.. annotations are bigger that actual entity code. Moreover, most entity code now contains controller layer information and is disconnected from actual route handler.

My general idea is to keep routing configuration as close to handlers as possible. Can i only link routes in entities? Something like that?

/**
 * @ApiResource(
 *     itemOperations={
 *         "api_foos_one"=OneAction::class,
 *         "api_foos_two"=TwoAction::class,
 *     }
 * )
 */

And then configure everything related in controller annotations?

Or only in entity but NOT in controller?

Only on the entity and not in controllers!

About your second question, you can switch to XML or YAML is annotations become too verbose.
Your proposal is nice but not supported yet. PR welcome!

Ok, all info now is clear! Yaml is more away from handlers.

I don鈥檛 know about topic starter but for me everything works with new version. 馃憣 Thanks for fast answers :-)

i found the same problem, it's fixed only by adding the input_formats attribute to the entity

@ApiResource( attributes={ "input_formats"={"json"={"application/ld+json"}}, "output_formats"={"json"={"application/ld+json"}} },

I wonder why global config isn't used as a default instead?

Sorry for reply on this old issues, but I have the same problem.
My anotate in Entity :

/**
* @ApiResource(
*     shortName="Demande de squelette",
*     description="Gestion des demandes de squelette.",
*     formats={"json", "xml"},
*     itemOperations={
*     },
*     collectionOperations={
*          "force_demande_squelette"={
*              "input" = DemandeSqueletteSimplifie::class,
*              "output" = ResultatDemande::class,
*              "route_name" = "force_demande_squelette",
*              "method" = "POST",
*              "openapi_context" = {
*                  "summary" = "Soumet une demande de squelette.",
*                  "description" = "Soumet une demande de squelette et notifie le demandeur.",
*              },
*         }
*      }
* )

My methode in the controler :

/**
 * Methode permettant de formuler une demande de squelette.
 *
 * @Route(
 *     name = "force_demande_squelette",
 *     path = "/api/demande_squelette.{_formats}",
 *     methods="POST",
 *     defaults = {
 *          "_formats" = "json",
 *          "_api_resource_class" = DemandeSqueletteSimplifie::class,
 *          "_api_collection_operation_name" = "post",
 *     }
 *  )
 * @ParamConverter("demandeSqueletteSimplifie", converter="fos_rest.request_body")
 *
 * @return ResultatDemande
 */
public function addDemandeSquelette(DemandeSqueletteSimplifie $demandeSqueletteSimplifie): ResultatDemande

A sample of call :
curl -X POST "http://..../api/demande_squelette.{_formats}" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"application\":263756,\"collecteur\":\"TOOT\",\"hostnames\":null,\"destination\":4,\"destinationServeur\":\"taratata\",\"utilisateur\":\"Thomas\"}"

Response :
...
"title": "An error occurred",
"detail": "The content-type \"application/json\" is not supported. Supported MIME types are \"\".",
...

My plateform :
api-platform/core v2.5.4 Build a fully-featured hypermedia or GraphQL API in minutes
PHP 7.2.10

Thanks
Thomas

Like @amine0902 mentioned, you need the additional attributes and this fixed it for me:

 *     attributes={
 *      "input_formats"={"json"={"application/ld+json", "application/json"}},
 *      "output_formats"={"json"={"application/ld+json", "application/json"}}
 *     }

This is added inside the @ApiResource annotation, not in the controller.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mahmoodbazdar picture mahmoodbazdar  路  3Comments

dematerializer picture dematerializer  路  3Comments

stipic picture stipic  路  3Comments

theshaunwalker picture theshaunwalker  路  3Comments

gustawdaniel picture gustawdaniel  路  3Comments