<?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>Forem: Roman</title>
    <description>The latest articles on Forem by Roman (@romalyt).</description>
    <link>https://forem.com/romalyt</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%2F368978%2Fe4ad7b67-6e47-4c58-a7fe-2ca897bac7a3.jpg</url>
      <title>Forem: Roman</title>
      <link>https://forem.com/romalyt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/romalyt"/>
    <language>en</language>
    <item>
      <title>Scramble 0.11.0 – Laravel API docs generator update: Laravel Data support, enforcing schema types, inference improvements</title>
      <dc:creator>Roman</dc:creator>
      <pubDate>Thu, 04 Jul 2024 12:27:21 +0000</pubDate>
      <link>https://forem.com/romalyt/scramble-0110-laravel-api-docs-generator-update-laravel-data-support-enforcing-schema-types-inference-improvements-93b</link>
      <guid>https://forem.com/romalyt/scramble-0110-laravel-api-docs-generator-update-laravel-data-support-enforcing-schema-types-inference-improvements-93b</guid>
      <description>&lt;p&gt;Hey Laravel community!&lt;/p&gt;

&lt;p&gt;I’m happy to announce a new version of Scramble. Scramble is Laravel API docs generator that generates doc without requiring you to write PHPDoc annotations: &lt;a href="https://scramble.dedoc.co/introduction" rel="noopener noreferrer"&gt;https://scramble.dedoc.co/introduction&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Laravel Data support
&lt;/h2&gt;

&lt;p&gt;Finally, Scramble supports Spatie's Laravel Data package! Scramble will make a proper documentation when a data object is used as a form request. There are a lot of nuances to how data objects are actually behave in these contexts, and Scramble will handle all of them properly.&lt;/p&gt;

&lt;p&gt;Notice how there are no PHPDoc annotations used at all, and the documentation is complete.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Data\TodoData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Models\Todo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TodoController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&lt;/span&gt;
    &lt;span class="p"&gt;{&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;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Todo&lt;/span&gt; &lt;span class="nv"&gt;$todo&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="nc"&gt;TodoData&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$todo&lt;/span&gt;&lt;span class="p"&gt;);&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Spatie\LaravelData\Data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Spatie\LaravelData\Attributes\Validation\Min&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Spatie\LaravelData\Attributes\Validation\Max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TodoData&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Data&lt;/span&gt;
    &lt;span class="p"&gt;{&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;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="na"&gt;#[Min(3), Max(255)]&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;$title&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;$content&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;bool&lt;/span&gt; &lt;span class="nv"&gt;$completed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&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;&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%2Fuploads%2Farticles%2Fvsy2pwpq892u4h6wu3vn.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%2Fuploads%2Farticles%2Fvsy2pwpq892u4h6wu3vn.png" alt="Resulting documentation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Laravel Data package is supported as a part of Scramble PRO. To be able to maintain Scramble and introduce features, I'm looking for ways to monetize it. Scramble PRO is one way of doing it. The overall goal of Scramble PRO is to make sure the teams using it are successful with Scramble: the documentation generation is automatic (minimizing manual annotations and errors) and resulting documentation is as accurate as possible.&lt;/p&gt;

&lt;p&gt;Here is a &lt;a href="https://dev.to/usage/laravel-data"&gt;Laravel Data support documentation&lt;/a&gt;. There you'll find example project and example API documentation to check things out yourself!&lt;/p&gt;

&lt;h2&gt;
  
  
  Ability to ensure schema types
&lt;/h2&gt;

&lt;p&gt;Taking into account Scramble is inferring types across the codebase and then makes a documentation based on that, you may want to know when a type is not inferred and fix that case so your documentation is as accurate as it gets.&lt;/p&gt;

&lt;p&gt;Introducing the &lt;code&gt;Scramble::preventSchema&lt;/code&gt; method! It is used in an application service provider.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Dedoc\Scramble\Support\Generator\Types\UnknownType&lt;/span&gt;&lt;span class="p"&gt;;&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;register&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Scramble&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;preventSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UnknownType&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="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With this method Scramble will fail when generating documentation in case any of the provided schemas are met.&lt;/p&gt;

&lt;p&gt;In case you don't want to change anything in the code to fix a particular schema, but you don't want it to be reported (thrown), you can whitelist it (similar to baseline concept of PHPStan). To whitelist an error, simply add a string pattern that will match error's JSON Pointer (found at):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

&lt;span class="nc"&gt;Scramble&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;preventSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UnknownType&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="n"&gt;ignorePaths&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'*/PublisherImportStatusesCollection/type*'&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;In case you want the schemas to be reported by &lt;code&gt;analyze&lt;/code&gt; command, but you don't want it to throw an exception during the documentation generation, you can pass boolean &lt;code&gt;throw&lt;/code&gt; parameter:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

&lt;span class="nc"&gt;Scramble&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;preventSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UnknownType&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="k"&gt;throw&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can add some logic, like prevent throwing the exceptions in a non-production environment:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;

&lt;span class="nc"&gt;Scramble&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;preventSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UnknownType&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="k"&gt;throw&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isProduction&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This highlights any type that Scramble could not infer and this highlights the HUGE amount of work in the future!&lt;/p&gt;

&lt;h2&gt;
  
  
  Command to analyze documentation
&lt;/h2&gt;

&lt;p&gt;To see all the occurrences of prevented schemas in project, you can use &lt;code&gt;php artisan scramble:analyze&lt;/code&gt; command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;php artisan scramble:analyze
POST api/brand/&lt;span class="o"&gt;{&lt;/span&gt;brand&lt;span class="o"&gt;}&lt;/span&gt;/creators-import 1 error .. API&lt;span class="se"&gt;\B&lt;/span&gt;randPublishersImportController@store

1. Schema &lt;span class="o"&gt;[&lt;/span&gt;UnknownType] is not allowed.
Found at /components/schemas/PublisherImportStatusesCollection/type/properties/id
Inferred at App&lt;span class="se"&gt;\H&lt;/span&gt;ttp&lt;span class="se"&gt;\R&lt;/span&gt;esources&lt;span class="se"&gt;\P&lt;/span&gt;ublisherImportStatusesCollection:25
     21▕      &lt;span class="k"&gt;*&lt;/span&gt;/
     22▕     public &lt;span class="k"&gt;function &lt;/span&gt;toArray&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
     23▕     &lt;span class="o"&gt;{&lt;/span&gt;
     24▕         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
  ➜  25▕             &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;-&amp;gt;batchId,
     26▕             &lt;span class="s1"&gt;'progress'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;-&amp;gt;calculateProgress&lt;span class="o"&gt;()&lt;/span&gt;,
     27▕             &lt;span class="s1"&gt;'results'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;-&amp;gt;collection,
     28▕         &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     29▕     &lt;span class="o"&gt;}&lt;/span&gt;
....


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This command shows you all the occurrences of prevented schemas: the JSON pointer (Found at) of where the schema occurred in Open API document, and where possible the line of code which is responsible for this schema! So you can find and fix such things FAST.&lt;/p&gt;

&lt;p&gt;This command can be used as a part of your CI as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other
&lt;/h2&gt;

&lt;p&gt;Besides the larger features, this release if full of smaller goodies as well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Аdded the &lt;code&gt;response&lt;/code&gt; and &lt;code&gt;toResponse&lt;/code&gt; methods support on resource instances in &lt;a href="https://github.com/dedoc/scramble/pull/440" rel="noopener noreferrer"&gt;#440&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fixed data transform issue for manually annotated response bodies in &lt;a href="https://github.com/dedoc/scramble/pull/439" rel="noopener noreferrer"&gt;#493&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fix bug preventing validation rules from being documented when 3rd parameter was passing to validation methods in &lt;a href="https://github.com/dedoc/scramble/pull/410" rel="noopener noreferrer"&gt;#410&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fixed float literals transformation in &lt;a href="https://github.com/dedoc/scramble/pull/411" rel="noopener noreferrer"&gt;#411&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fix failing collection transformation when a resource is used in &lt;code&gt;additional&lt;/code&gt; in &lt;a href="https://github.com/dedoc/scramble/pull/422" rel="noopener noreferrer"&gt;#422&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fixed nullable being skipped when analyzing rules in &lt;a href="https://github.com/dedoc/scramble/pull/426" rel="noopener noreferrer"&gt;#426&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fixed return type annotation being ignored in &lt;a href="https://github.com/dedoc/scramble/pull/434" rel="noopener noreferrer"&gt;#434&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fixed non-needed usage of &lt;code&gt;AnyOf&lt;/code&gt; for responses documentation when the response code is the same in &lt;a href="https://github.com/dedoc/scramble/pull/427" rel="noopener noreferrer"&gt;#427&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Moved default value from parameter to schema in &lt;a href="https://github.com/dedoc/scramble/pull/438" rel="noopener noreferrer"&gt;#438&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Thanks!
&lt;/h2&gt;

&lt;p&gt;Thanks for checking this post out. If you have any questions, ideas, suggestions, feel free to drop me a line to &lt;a href="mailto:roman@dedoc.co"&gt;roman@dedoc.co&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Originally posted on Scramble's blog: &lt;a href="https://scramble.dedoc.co/blog/scrambledrop-scramble-0110" rel="noopener noreferrer"&gt;https://scramble.dedoc.co/blog/scrambledrop-scramble-0110&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>laravel</category>
      <category>api</category>
      <category>openapi</category>
      <category>documentation</category>
    </item>
    <item>
      <title>Scramble 0.8.0 - Update of Laravel API documentation generator</title>
      <dc:creator>Roman</dc:creator>
      <pubDate>Wed, 02 Aug 2023 07:17:14 +0000</pubDate>
      <link>https://forem.com/romalyt/scramble-080-update-of-laravel-api-documentation-generator-150b</link>
      <guid>https://forem.com/romalyt/scramble-080-update-of-laravel-api-documentation-generator-150b</guid>
      <description>&lt;p&gt;Improved performance, type inference across the codebase, operation ID generation, and sorted docs out of the box.&lt;/p&gt;

&lt;p&gt;Hey Laravel community!&lt;/p&gt;

&lt;p&gt;Super happy to announce the new version of Scramble. Scramble is API documentation generator for Laravel that works without requiring you to write PHPDoc annotations: &lt;a href="https://scramble.dedoc.co/introduction" rel="noopener noreferrer"&gt;https://scramble.dedoc.co/introduction&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;0.8.0 is finally out: &lt;a href="https://github.com/dedoc/scramble/releases/tag/v0.8.0" rel="noopener noreferrer"&gt;https://github.com/dedoc/scramble/releases/tag/v0.8.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This version requires PHP 8.1 now to work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance improvements
&lt;/h2&gt;

&lt;p&gt;This version took a lot of time to build, but as the result Scramble now can analyze entire codebase to infer types. &lt;/p&gt;

&lt;p&gt;And despite analyzing the entire codebase, this release makes Scramble around 40% faster!&lt;/p&gt;

&lt;p&gt;~40% speed improvement was measured on a big codebase with 250+ API endpoints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type inference across the codebase
&lt;/h2&gt;

&lt;p&gt;Type inference is a process of determining types of variables based on the source code analysis.&lt;/p&gt;

&lt;p&gt;Scramble uses type inference to understand responses of endpoints. PhpDoc usually either not accurate or outdated, and just type hints don’t contain enough information. Consider this example.&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Post&lt;/span&gt; &lt;span class="nv"&gt;$post&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$post&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;While type hint clearly states the response is &lt;code&gt;JsonResponse&lt;/code&gt;, only this information won’t be useful for documentation. We’d want to know the specifics of the response.&lt;/p&gt;

&lt;p&gt;So thanks to type inference, Scramble deducts the return type of this method to something like &lt;code&gt;JsonResponse&amp;lt;Post, 200, []&amp;gt;&lt;/code&gt;. And now we actually have useful information here — response body, response status, headers.&lt;/p&gt;

&lt;p&gt;Prior to 0.8.0 Scramble was pretty limited in what types it can infer. It could understand types based on info that is available in the file being analyzed, but it didn’t analyze other files. &lt;/p&gt;

&lt;p&gt;So let’s take this example:&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="c1"&gt;// Controllers/PostsController.php&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;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;PostRepository&lt;/span&gt; &lt;span class="nv"&gt;$postRepository&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="nv"&gt;$postRepository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$post&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Repositories/PostsRepository.php&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;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$postId&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Post&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prior to 0.8.0 Scramble would analyze just the controller source code, and won’t deep dive into &lt;code&gt;PostRepository&lt;/code&gt; class to see what is going on there. &lt;/p&gt;

&lt;p&gt;But in 0.8.0 Scramble does that! To infer the type returned from &lt;code&gt;show&lt;/code&gt;, Scramble now will analyze &lt;code&gt;PostRepository&lt;/code&gt;’s &lt;code&gt;find&lt;/code&gt; method. This way it will know that controller’s &lt;code&gt;show&lt;/code&gt; method returns &lt;code&gt;Post&lt;/code&gt; instance, hence it can document the response correctly.&lt;/p&gt;

&lt;p&gt;And even with deep diving into the codebase, this version is shipped with performance improvements (40% faster docs generation) 🤯&lt;/p&gt;

&lt;p&gt;So improved type inference will cover more cases out of the box, and will allow you to have more accurate responses documentation without manual type hinting.&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%2Fuploads%2Farticles%2Fm0qk6yvklqc2o6ozk7cz.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%2Fuploads%2Farticles%2Fm0qk6yvklqc2o6ozk7cz.png" alt="Notice how success method is defined in trait, and Scramble is able to deduct the final response type from it."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how success method is defined in trait, and Scramble is able to deduct the final response type from it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operations ID support
&lt;/h2&gt;

&lt;p&gt;In OpenAPI standard, operation ID is a unique identifier for an operation (endpoint). It is primarily used as link anchors in docs websites, or by code generators to generate methods names. You get the point.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/HelgeSverre" rel="noopener noreferrer"&gt;Helge Sverre&lt;/a&gt; pointed out that operation IDs are also required by Chat GPT plugins to consume your APIs and even provided an implementation for manual &lt;code&gt;operationId&lt;/code&gt; support &lt;a href="https://helgesver.re/articles/operationid-support-scramble-openapi" rel="noopener noreferrer"&gt;in his blog&lt;/a&gt;! Thank you Helge! &lt;/p&gt;

&lt;p&gt;In 0.8.0 Scramble will automatically generate unique &lt;code&gt;operationId&lt;/code&gt; for every endpoint, and also it will allow you to have specify it yourself using &lt;code&gt;@operationId&lt;/code&gt; PhpDoc annotation.&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%2Fuploads%2Farticles%2Fbfae1gyo2tft5isgzvzr.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%2Fuploads%2Farticles%2Fbfae1gyo2tft5isgzvzr.png" alt="Operation ID is used as link anchors in current Scramble’s UI."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Operation ID is used as link anchors in current Scramble’s UI.&lt;/p&gt;

&lt;p&gt;Read more about it in documentation: &lt;a href="https://scramble.dedoc.co/usage/request#documenting-operation-id" rel="noopener noreferrer"&gt;https://scramble.dedoc.co/usage/request#documenting-operation-id&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sorting pages in documentation automatically
&lt;/h2&gt;

&lt;p&gt;Starting from 0.8.0 all operations (endpoints) and schemas (resources) are sorted alphabetically in the resulting documentation.&lt;/p&gt;

&lt;p&gt;It will make reading docs more convenient and will allow to find information faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other changes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;confirmed&lt;/code&gt; validation rule support&lt;/li&gt;
&lt;li&gt;Added support of UUID model keys&lt;/li&gt;
&lt;li&gt;Fixed spread operator not being properly analyzed when inferring a type for an array&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Thanks!
&lt;/h2&gt;

&lt;p&gt;Hope you like it! If so, please share this update on Twitter (share button is on the right) and leave some stars &lt;a href="https://github.com/dedoc/scramble" rel="noopener noreferrer"&gt;in Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Originally posted on Scramble's Blog: &lt;a href="https://blog.dedoc.co/scrambledrop-scramble-080" rel="noopener noreferrer"&gt;https://blog.dedoc.co/scrambledrop-scramble-080&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>api</category>
      <category>openapi</category>
    </item>
    <item>
      <title>How to create robust HTTP clients with Guzzle </title>
      <dc:creator>Roman</dc:creator>
      <pubDate>Tue, 25 May 2021 19:00:37 +0000</pubDate>
      <link>https://forem.com/romalyt/how-to-create-robust-http-clients-with-guzzle-34p6</link>
      <guid>https://forem.com/romalyt/how-to-create-robust-http-clients-with-guzzle-34p6</guid>
      <description>&lt;p&gt;I never was a big fan of Guzzle until recently when I finally learned about Guzzle middleware and some basic config.&lt;/p&gt;

&lt;p&gt;Here is how you can step up your Guzzle game and build robust HTTP clients.&lt;/p&gt;

&lt;p&gt;First of all, start from setting timeouts. Timeouts are not limited by default, and this can cause headaches when debugging issues it can cause.&lt;/p&gt;

&lt;p&gt;I remember spending 2 days trying to understand why some jobs randomly time-outed. It wasn't fun when I noticed some requests stuck!&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="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;GuzzleHttp\Client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'timeout'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'connect_timeout'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;15&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;So Guzzle's middleware stack. Guzzle passes any request through the middleware stack. It allows you to add your middleware and do something for every request (or every response): add the API key to headers, handle errors, and even retry failed requests.&lt;/p&gt;

&lt;p&gt;To start you need to create &lt;code&gt;HandlerStack&lt;/code&gt;. The simplest way to do it is to call the static method &lt;code&gt;create&lt;/code&gt; on &lt;code&gt;HandlerStack&lt;/code&gt; class. You will add middleware to the stack.&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="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;GuzzleHttp\Client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;GuzzleHttp\HandlerStack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HandlerStack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'base_uri'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'https://api.some.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'timeout'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'connect_timeout'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'handler'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$stack&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;Guzzle's middleware on its own is pretty tricky: a function that returns a function. But thankfully, they've added sugar for it, so it looks readable.&lt;/p&gt;

&lt;p&gt;Let's start from &lt;code&gt;Middleware::mapRequest&lt;/code&gt; middleware. It allows you to modify a request. I use this middleware to add the API key to every request, either in headers or in the query string. It helps to reduce the amount of boilerplate code I write when making requests.&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="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;GuzzleHttp\Middleware&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;GuzzleHttp\HandlerStack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\RequestInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;RequestInterface&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'services.some.api_token'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&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;withHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Authorization'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Basic &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&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;&lt;code&gt;Middleware::mapResponse&lt;/code&gt; allows you to do something with the response. I use it to do basic error handling. This way, I can avoid excessive try/catch usage or wrapping my entire client in a separate method.&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="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;GuzzleHttp\Middleware&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ResponseInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Middleware&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;mapResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ResponseInterface&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;)&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="nb"&gt;in_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getStatusCode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Some logic to hanle the error. For example, save it into DB.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$response&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;And my favorite &lt;code&gt;Middleware::retry&lt;/code&gt;. It allows you to specify when and how to retry failed requests. For example, when you get 50x errors, connection timeouts, etc you would probably want to try again before giving up.&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="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;GuzzleHttp\Middleware&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\RequestInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ResponseInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;GuzzleHttp\Exception\ConnectException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;$retryDecider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;$retries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="kt"&gt;RequestInterface&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;ResponseInterface&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="kt"&gt;Exception&lt;/span&gt; &lt;span class="nv"&gt;$exception&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;)&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;$retries&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&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;$exception&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;ConnectException&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&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;$response&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getStatusCode&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;500&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="kc"&gt;true&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nv"&gt;$retryDelay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$numberOfRetries&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="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;$numberOfRetries&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Middleware&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$retryDecider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$retryDelay&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retry middleware also allows you to set the delay between requests so you can configure something like exponential back-off pretty easily. On the screenshot in the previous tweet delay between requests will be a bit bigger between every failed request.&lt;/p&gt;

&lt;p&gt;At this point, you have a robust Guzzle HTTP client that is enjoyable to use. It will automatically retry failed requests, add authorization to the request, or do whatever you need!&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
    </item>
  </channel>
</rss>
