<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Guillaume MOREL</title>
    <description>The latest articles on DEV Community by Guillaume MOREL (@gmorel).</description>
    <link>https://dev.to/gmorel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F418694%2Fe2bc0070-544c-49ff-8775-0d1b37aba763.jpeg</url>
      <title>DEV Community: Guillaume MOREL</title>
      <link>https://dev.to/gmorel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gmorel"/>
    <language>en</language>
    <item>
      <title>Cooking safety nests</title>
      <dc:creator>Guillaume MOREL</dc:creator>
      <pubDate>Tue, 16 Feb 2021 14:09:43 +0000</pubDate>
      <link>https://dev.to/gmorel/cooking-safety-nests-155n</link>
      <guid>https://dev.to/gmorel/cooking-safety-nests-155n</guid>
      <description>&lt;p&gt;Something still occurs too often: &lt;br&gt;
Developers trying to conceal their mistakes 💣.&lt;/p&gt;

&lt;p&gt;Most of the time it creates no particular issue. But sometimes it can lead to incident and even service outage.&lt;/p&gt;

&lt;p&gt;This is a fact: developers often make mistakes. This is normal since nowadays technologies are highly complex.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In order to promote Teamplay we should embrace developer’s mistakes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because it is clearly unavoidable and this is the best way to learn.&lt;/p&gt;

&lt;p&gt;Our responsibility however is &lt;strong&gt;to reduce any negative outcome&lt;/strong&gt;. And to detect them ASAP when they are &lt;strong&gt;costless&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Nearly all mistakes will be noticed one way or another.&lt;br&gt;
When they are noticed:&lt;/p&gt;

&lt;h2&gt;
  
  
  🎉 Ask for a homemade cookie !
&lt;/h2&gt;

&lt;p&gt;Homemade 🍪 are a humorous way to de-escalate the way mistakes are perceived. Since developers no more fear being caught doing a mistake. It leads them to be way more transparent. Therefore it produces trust.&lt;/p&gt;

&lt;p&gt;As soon as developers embrace mistakes. And as long as you provide them the tools/methodologies to reduce any negative outcome. You will create a safety nest. When your team members no more feel in danger, this reduces their cognitive load.&lt;/p&gt;

&lt;p&gt;Another positive outcome is that developers will then openly share their mistakes. Allowing to transfer experience to other teammates. Hence mistakes won’t be done twice.&lt;/p&gt;

&lt;p&gt;The last positive outcome is that now your developers will dare to take more initiatives. They will be less stunned by fear.&lt;/p&gt;

&lt;p&gt;🍪 will ultimately increase your team productivity.&lt;/p&gt;




&lt;p&gt;Working remotely ? Ask them to share the picture of their work. Or find a cheap alternative.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DrC-MIO---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gsdannuokpkzs6eqjvvs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DrC-MIO---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gsdannuokpkzs6eqjvvs.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>management</category>
      <category>productivity</category>
      <category>teamplay</category>
      <category>leadership</category>
    </item>
    <item>
      <title>Another way for a Symfony API to ingest POST requests - No Bundle</title>
      <dc:creator>Guillaume MOREL</dc:creator>
      <pubDate>Sun, 19 Jul 2020 15:34:18 +0000</pubDate>
      <link>https://dev.to/gmorel/another-way-for-a-symfony-api-to-ingest-post-requests-no-bundle-5h15</link>
      <guid>https://dev.to/gmorel/another-way-for-a-symfony-api-to-ingest-post-requests-no-bundle-5h15</guid>
      <description>&lt;p&gt;Let's begin with some &lt;a href="https://docs.behat.org/en/latest/quick_start.html" rel="noopener noreferrer"&gt;Behat&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; It creates a Product
  &lt;span class="err"&gt;When I send a POST request to "/v1/products.json" with body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;"""
  {
    "id": "fabd5e92-02e7-43f7-a962-adab8ec88e94",
    "name": "Product1",
    "price": {
      "amount": 600,
      "currency": "EUR"
    }
  }
  """&lt;/span&gt;
  &lt;span class="nf"&gt;Then &lt;/span&gt;the response status code should be 201
  &lt;span class="nf"&gt;And &lt;/span&gt;the header &lt;span class="s"&gt;"Location"&lt;/span&gt; should contain &lt;span class="s"&gt;"/v1/products/fabd5e92-02e7-43f7-a962-adab8ec88e94.json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;There are several ways of  building a RESTfull API in Symfony:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://symfony.com/doc/master/bundles/FOSRestBundle/index.html" rel="noopener noreferrer"&gt;FOSRestBundle&lt;/a&gt; or &lt;a href="https://api-platform.com/" rel="noopener noreferrer"&gt;API Platform&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Custom by using the &lt;a href="https://medium.com/@ideneal/how-to-handle-json-requests-using-forms-on-symfony-4-and-getting-a-clean-code-67dd796f3d2f" rel="noopener noreferrer"&gt;Form Component&lt;/a&gt; or using &lt;a href="https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html" rel="noopener noreferrer"&gt;@ParamConverter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Or simply custom by extracting manually params one by one from a Request array&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are already proven to work great. But sometimes you just need a very simple way &lt;strong&gt;with minimum dependencies&lt;/strong&gt; to ingest data from a Single Page Application or a Micro Service. Something pretty straight forward that will allow any intern/junior 🌱 to quickly be up to speed and autonomous in your project.&lt;/p&gt;


&lt;h2&gt;
  
  
  🎉 Meet the Serializer
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;SerializerInterface&lt;/span&gt; &lt;span class="nv"&gt;$serializer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="cd"&gt;/**
 * @Route("products.json", methods={"POST"})
 */&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;JsonResponse&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/** @var CreateProductRequestPayload $requestPayload */&lt;/span&gt;
    &lt;span class="nv"&gt;$requestPayload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;deserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getContent&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="nc"&gt;CreateProductRequestPayload&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Your Logic&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Having a DTO request like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * DTO representing how API ingest JSON
 */&lt;/span&gt;
&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateProductRequestPayload&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It uses the Symfony &lt;a href="https://symfony.com/doc/current/components/serializer.html#deserializing-an-object" rel="noopener noreferrer"&gt;Serializer Component&lt;/a&gt; to deserialize  a JSON into an Object. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy80hh4gav9a0720c1kw0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy80hh4gav9a0720c1kw0.png" alt="Deserialize" width="487" height="381"&gt;&lt;/a&gt;&lt;br&gt;
Sorry to disappoint you ... but nothing new here: FOSRestBundle and API Platform are using it internally.&lt;/p&gt;

&lt;p&gt;The good news is you have good chances to already have this component as a part of your project dependency. &lt;/p&gt;

&lt;p&gt;If it is not already present:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require symfony/serializer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/gmorel" rel="noopener noreferrer"&gt;
        gmorel
      &lt;/a&gt; / &lt;a href="https://github.com/gmorel/very-light-symfony-api-example" rel="noopener noreferrer"&gt;
        very-light-symfony-api-example
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Yet another Symfony API without Bundle
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7aeiynmf6hr8z8lbn7nn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7aeiynmf6hr8z8lbn7nn.png" alt="GitHub" width="64" height="64"&gt;&lt;/a&gt; Full example here: &lt;a href="https://github.com/gmorel/very-light-symfony-api-example/blob/master/src/Product/UI/Controller/ProductController.php#L38-L67" rel="noopener noreferrer"&gt;https://github.com/gmorel/very-light-symfony-api-example/blob/master/src/Product/UI/Controller/ProductController.php#L38-L67&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Validation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateProductRequestPayload&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @Assert\NotNull
     * @Assert\Uuid
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * @Assert\NotNull
     * @Assert\NotBlank()
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exactly like you would do with Forms. You can now validate your &lt;code&gt;$requestPayload&lt;/code&gt; against the Symfony &lt;a href="https://symfony.com/doc/current/components/validator.html" rel="noopener noreferrer"&gt;Validator Component&lt;/a&gt; in the &lt;a href="https://github.com/gmorel/very-light-symfony-api-example/blob/master/src/Product/UI/Controller/ProductController.php#L51-L57" rel="noopener noreferrer"&gt;Controller&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$requestPayload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$errors&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JsonResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createErrorFromValidation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$errors&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTTP_BAD_REQUEST&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h5&gt;
  
  
  Deep validation
&lt;/h5&gt;

&lt;p&gt;You can of course perform deep validation if your are using Value Objects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;It fails to create a Product with bad amount and bad currency - Deep inspection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="err"&gt;When I send a POST request to "/v1/en/products.json" with body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;"""
  {
    "id": "fabd5e92-02e7-43f7-a962-adab8ec88e94",
    "name": "Product 1",
    "price": {
      "amount": 0,
      "currency": "EU"
    }
  }
  """&lt;/span&gt;
  &lt;span class="nf"&gt;Then &lt;/span&gt;the response status code should be 400
  &lt;span class="nf"&gt;And &lt;/span&gt;the JSON node &lt;span class="s"&gt;"type"&lt;/span&gt; should be equal to &lt;span class="s"&gt;"UI Validation"&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the JSON node &lt;span class="s"&gt;"title"&lt;/span&gt; should be equal to &lt;span class="s"&gt;"Bad Request"&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the JSON node &lt;span class="s"&gt;"violations"&lt;/span&gt; should have 2 elements
  &lt;span class="nf"&gt;And &lt;/span&gt;the JSON node &lt;span class="s"&gt;"violations[0].propertyPath"&lt;/span&gt; should be equal to &lt;span class="s"&gt;"price.amount"&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the JSON node &lt;span class="s"&gt;"violations[0].message"&lt;/span&gt; should be equal to &lt;span class="s"&gt;"This value should be positive."&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the JSON node &lt;span class="s"&gt;"violations[1].propertyPath"&lt;/span&gt; should be equal to &lt;span class="s"&gt;"price.currency"&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the JSON node &lt;span class="s"&gt;"violations[1].message"&lt;/span&gt; should be equal to &lt;span class="s"&gt;"This value is not a valid currency."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ Don't forget the &lt;code&gt;@Assert\Valid&lt;/code&gt; annotation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @Assert\Valid
 */&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;PriceDTO&lt;/span&gt; &lt;span class="nv"&gt;$price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Otherwise no deep validation will be performed. And without proper test suite you have good chance to notice it too late.&lt;/p&gt;




&lt;h5&gt;
  
  
  Bonus: i18n validation
&lt;/h5&gt;

&lt;p&gt;You can have your JS/Mobile to directly show some already translated validation errors for free.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; It fails to create a Product in French
  &lt;span class="err"&gt;When I send a POST request to "/v1/fr/products.json" with body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
  &lt;span class="nf"&gt;And &lt;/span&gt;the JSON node &lt;span class="s"&gt;"violations[0].message"&lt;/span&gt; should be equal to &lt;span class="s"&gt;"Cette valeur ne doit pas être vide."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;For the simplicity of the example locale is set in the URL. But I would advise to have the locale extracted from HTTP Headers. So user Browser/Phone could take care of the locale by itself.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="nf"&gt;Given &lt;/span&gt;I add &lt;span class="s"&gt;"Accept-Language"&lt;/span&gt; header equal to &lt;span class="s"&gt;"fr"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h5&gt;
  
  
  Mixing ParamConverter + Serializer
&lt;/h5&gt;

&lt;p&gt;You could also mix &lt;a href="https://github.com/TBoileau/api_social_network/blob/master/src/Request/ParamConverter/PostConverter.php#L36-L45" rel="noopener noreferrer"&gt;ParamConverter + Serializer&lt;/a&gt; 🚀. This is clever. However Listeners tend to confuse new comers and juniors. Use them wisely as they bring their own &lt;a href="https://github.com/TBoileau/api_social_network/blob/master/config/services.yaml#L34-L36" rel="noopener noreferrer"&gt;complexity&lt;/a&gt;.&lt;/p&gt;




&lt;h5&gt;
  
  
  OpenAPI documentation - Swagger
&lt;/h5&gt;

&lt;p&gt;You can still generate an OpenAPI documentation by adding the relevant annotations to your RequestPayload using &lt;a href="https://zircote.github.io/swagger-php/Getting-started.html#detects-values-based-on-context" rel="noopener noreferrer"&gt;SwaggerPHP&lt;/a&gt; or via &lt;a href="https://symfony.com/doc/current/bundles/NelmioApiDocBundle/index.html" rel="noopener noreferrer"&gt;NelmioApiDocBundle v4&lt;/a&gt;.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Wait a little: CreateProductRequestPayload has only public properties. Where is our user intention's &lt;code&gt;immutability&lt;/code&gt; here ?&lt;br&gt;
I let you read &lt;a href="https://jimmybogard.com/immutability-in-dtos/" rel="noopener noreferrer"&gt;this&lt;/a&gt; and then decide by yourself. You might also want to try &lt;a href="https://psalm.dev/articles/immutability-and-beyond" rel="noopener noreferrer"&gt;Psalm&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>symfony</category>
      <category>api</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
