<?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: Timo Schinkel</title>
    <description>The latest articles on Forem by Timo Schinkel (@timoschinkel).</description>
    <link>https://forem.com/timoschinkel</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%2F256262%2F011c4493-a9e8-4b6e-931c-ea9d19312c27.jpg</url>
      <title>Forem: Timo Schinkel</title>
      <link>https://forem.com/timoschinkel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/timoschinkel"/>
    <language>en</language>
    <item>
      <title>Native TypeScript with Node</title>
      <dc:creator>Timo Schinkel</dc:creator>
      <pubDate>Mon, 09 Mar 2026 07:40:18 +0000</pubDate>
      <link>https://forem.com/timoschinkel/native-typescript-with-node-4d93</link>
      <guid>https://forem.com/timoschinkel/native-typescript-with-node-4d93</guid>
      <description>&lt;p&gt;Starting with Node 22.18.0 it is possible to run &lt;a href="https://nodejs.org/en/learn/typescript/run-natively" rel="noopener noreferrer"&gt;TypeScript natively&lt;/a&gt; from the Node interpreter. This feels like the best of both worlds - the benefits of type inference in your IDE without need to first transpile. I have been using this feature for the small scripts that I use during development and during inspections. Think of scripts to generate or validate a keypair, or a script to build a configuration file for local development. Needing to run &lt;code&gt;tsc&lt;/code&gt; is a bit of a nuisance for these scripts, and therefore solutions like &lt;code&gt;ts-node&lt;/code&gt; and &lt;code&gt;tsx&lt;/code&gt; were introduced. But now this is built-in in Node, and that means that we have one dependency less in our &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But before you start using this in your codebases there are a few caveats that you should probably be aware of.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type safety
&lt;/h2&gt;

&lt;p&gt;First a word of caution; Node does not actually perform the type checks that TypeScript performs. It merely &lt;em&gt;strips&lt;/em&gt; the type information from the TypeScript code. This does mean an added, although barely noticable, latency to the execution of your scripts. More importantly it means that the type safety is &lt;strong&gt;not guaranteed&lt;/strong&gt;. This is actually the same thing that happens with bundlers like &lt;code&gt;esbuild&lt;/code&gt;. That's why  you should always also run &lt;code&gt;tsc --noEmit&lt;/code&gt; on your TypeScript code when you use a bundler or when running it natively with Node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Restricted syntax
&lt;/h2&gt;

&lt;p&gt;But more importantly it means that you cannot use any syntax that is TypeScript only. Two example of this that I personally ran into were enums and parameter properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;MyEnum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;OptionA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;option-a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;OptionB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;option-b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;constructor&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;readonly&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a way to let TypeScript block this via the &lt;code&gt;tsconfig.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"erasableSyntaxOnly"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind that - unlike &lt;code&gt;package.json&lt;/code&gt; - &lt;code&gt;tsconfig.json&lt;/code&gt; files are &lt;strong&gt;not&lt;/strong&gt; hierarchical read by &lt;code&gt;tsc&lt;/code&gt;. I personally tend to use the native TypeScript feature for specific scripts, which are located outside the TypeScript files meant for production. Contrary to linters like &lt;code&gt;eslint&lt;/code&gt;, &lt;code&gt;oxlint&lt;/code&gt; and &lt;code&gt;biome&lt;/code&gt; TypeScript does not have a way to specify compiler options per folder. So you have three options if you want to use this option:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable this flag in your root &lt;code&gt;tsconfig.json&lt;/code&gt;, with the side effect that you are limited in your TypeScript syntax. But this approach will give you the option to validate the typing of your scripts.&lt;/li&gt;
&lt;li&gt;Create a separate &lt;code&gt;tsconfig.json&lt;/code&gt; inside the folder where the scripts are located and run a second &lt;code&gt;tsc --project scripts/tsconfig.json --noEmit&lt;/code&gt;. By using the &lt;a href="https://www.typescriptlang.org/tsconfig/#extends" rel="noopener noreferrer"&gt;&lt;code&gt;$extends&lt;/code&gt;&lt;/a&gt; option from TypeScript you can still keep most of your configuration centralized.&lt;/li&gt;
&lt;li&gt;Don't explicitly check for erasable syntax. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  CommonJS vs ESM
&lt;/h2&gt;

&lt;p&gt;Already since version 12 NodeJS has had support for &lt;a href="https://nodejs.org/api/esm.html" rel="noopener noreferrer"&gt;ESM&lt;/a&gt; - ECMAScript modules -, while also keeping support for CommonJS modules. We are now at version 25 of NodeJS and still there are libraries that are only available as CommonJS modules, and some libraries have made the step towards ESM. But if you want to use native TypeScript this becomes an even more concious decision, because we cannot rely on &lt;code&gt;tsc&lt;/code&gt; to convert ESM syntax to CommonJS syntax - or vise versa - based on the compiler options in &lt;code&gt;tsconfig.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// CommonJS way of including files and modules&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./method&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ESM way of including files and modules&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./method.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ESM has some advantages over CommonJS, such as a better capability of &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking" rel="noopener noreferrer"&gt;tree shaking&lt;/a&gt;, but it also has a downside; you will need to specify the extension of the file for relative imports. If you're using &lt;code&gt;tsc&lt;/code&gt; to build your production code you will end up with multiple &lt;code&gt;.js&lt;/code&gt; files, and therefore you will need to explicitly use the &lt;code&gt;.js&lt;/code&gt; extension in your relative imports. Even in your TypeScript code, because &lt;code&gt;tsc&lt;/code&gt; does not rewrite those imports (&lt;a href="https://github.com/microsoft/TypeScript/issues/61021" rel="noopener noreferrer"&gt;yet&lt;/a&gt;?). &lt;/p&gt;

&lt;p&gt;How NodeJS decides if a file is to be interpreted as ESM or as CommonJS is &lt;a href="https://nodejs.org/api/packages.html#determining-module-system" rel="noopener noreferrer"&gt;well-documented&lt;/a&gt;. In a nutshell; It checks the extension, then the nearest &lt;code&gt;package.json&lt;/code&gt; with a &lt;code&gt;type&lt;/code&gt; property, then the &lt;code&gt;--input-type&lt;/code&gt; flag, and finally it guesses. &lt;/p&gt;

&lt;p&gt;If you use a bundler then this usually is corrected by the bundler, but this is not the case for native TypeScript. So, you better make an explicit choice and go for one or the other. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt; This really only is an issue if you want to use code from another file in your codebase. If you only use modules from NodeJS itself then this is simple choice of syntax, and I would recommend to steer the module resolution by using either the extension &lt;code&gt;.mts&lt;/code&gt; or &lt;code&gt;.cts&lt;/code&gt;. When importing from an (P)NPM package you are dependent of the package maintainers as they how they offer their library; as ESM, as CJS or as both.&lt;/p&gt;

&lt;h3&gt;
  
  
  ESM
&lt;/h3&gt;

&lt;p&gt;The moment you want to introduce relative imports into your script I would recommend using ESM. Not only is it more future-proof, and the syntax is used in the code examples on the TypeScript website, but I have yet to find a nice way to make relative imports work using CommonJS. Since the files that are used via native TypeScript in my repositories are typically grouped in a single folder I tend to add a minimal &lt;code&gt;package.json&lt;/code&gt; to that folder to indicate ESM. Of course, this is only relevant if your root &lt;code&gt;package.json&lt;/code&gt; explicitly indicates CommonJS usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I can split my code in file - just like I would do for production code -, and for relative imports I add the explicit extension &lt;code&gt;.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./method.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is one small extra step to take for this to work properly; we need to tell TypeScript that we're going to use these extensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowImportingTsExtensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using a linter like &lt;code&gt;eslint&lt;/code&gt;, &lt;code&gt;oxlint&lt;/code&gt; or &lt;code&gt;biome&lt;/code&gt; you can enforce usage of extensions in imports, or not, per folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  CommonJS
&lt;/h3&gt;

&lt;p&gt;If you decide to use CommonJS as module resolution you can do so via &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"commonjs"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a big caveat for this however; you will still need to include relative paths with an extension when using native TypeScript. Where this will work in plain JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./sum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will not work when using native TypeScript. In that situation you are forced to specify the extension:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./sum.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mixing "script" files and "production" files
&lt;/h3&gt;

&lt;p&gt;So you've built a nice script, and you really want to use a class, method or type definition that is also used in the code that is used in your "production" code. This &lt;em&gt;could&lt;/em&gt; become problematic if you don't use a bundler or postprocessor. Since you need to specify the &lt;code&gt;.ts&lt;/code&gt; - or &lt;code&gt;.mts&lt;/code&gt; or &lt;code&gt;.cts&lt;/code&gt; - extension on your imports, you will also need to do this on your "production" code. This can become a problem, because TypeScript will not rewrite the extension for you. And that means that the transpiled code will have the extension &lt;code&gt;.js&lt;/code&gt;, but files will try to include it using the extension &lt;code&gt;.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are three workarounds for this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use a bundler to build your production artifact as the bundler will take care of this translation.&lt;/li&gt;
&lt;li&gt;Do not mix production code and native TypeScript code.&lt;/li&gt;
&lt;li&gt;Use a postprocessor to correct the imports after TypeScript transpilation.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  My setup
&lt;/h2&gt;

&lt;p&gt;This may sound like a lot of caveats and a lot of stuff to deal with, just so you don't have to introduce a dependency on &lt;code&gt;ts-node&lt;/code&gt;/&lt;code&gt;tsx&lt;/code&gt; or add a &lt;code&gt;tsc&lt;/code&gt; step to your workflow. And you might be right. But I have found that with a "modern" codebase it is just a handful of configurations to make native TypeScript possible.&lt;/p&gt;

&lt;p&gt;It is 2026, so I opt for ESM for module resolution. I think it is the way forward. This means that my &lt;code&gt;./package.json&lt;/code&gt; configures this for the entire codebase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows me to use the &lt;code&gt;import from&lt;/code&gt; and &lt;code&gt;export&lt;/code&gt; syntax, and to use &lt;code&gt;.ts&lt;/code&gt; extensions on all my TypeScript files. I try to avoid mixing native TypeScript code and production code by separating them in my filesystem. Typically, the native TypeScript code is for development and/or CI/CD only, and therefore I tend to keep it in a separate &lt;code&gt;scripts&lt;/code&gt; folder. &lt;/p&gt;

&lt;p&gt;Because size always matters I use a bundler like &lt;code&gt;esbuild&lt;/code&gt; to bundle, minify and tree shake my code. This will minimize my code artifact, and that &lt;em&gt;can&lt;/em&gt; mean better performance. Especially on serverless architectures a smaller artifact can lead to much lower cold start times. This also makes that I can configure my linter to always require relative imports to have a &lt;code&gt;.ts&lt;/code&gt; extension. I am currently using Biome for linting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"linter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"correctness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"useImportExtensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly I configure TypeScript to allow &lt;code&gt;.ts&lt;/code&gt; extensions in my imports and - because I use a bundler - I explicitly disable emitting of transpiled code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"noEmit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allowImportingTsExtensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I don't have any additional safeguards in place to prevent TypeScript-only syntax in the code that is run via native TypeScript. These scripts are either used for local development or as an inspection step in a CI pipeline, so if they fail the fallout is not noticable for my production environment. &lt;/p&gt;

&lt;h2&gt;
  
  
  tl/dr;
&lt;/h2&gt;

&lt;p&gt;Since NodeJS version 22 it is possible to have NodeJS run TypeScript code without the need to transpile. This feature is called &lt;em&gt;native TypeScript&lt;/em&gt;. It adds a minimal latency and should therefore probably not be used for production purposes, but it allows typing and typesafety in your scripts. When you create larger scripts, and you want to perform relative imports then you are best off switching your entire codebase to ESM due to the requirement of extensions in your relative imports.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>esm</category>
    </item>
    <item>
      <title>Peer dependencies in (P)NPM</title>
      <dc:creator>Timo Schinkel</dc:creator>
      <pubDate>Mon, 24 Nov 2025 15:52:12 +0000</pubDate>
      <link>https://forem.com/timoschinkel/peer-dependencies-in-pnpm-4mo6</link>
      <guid>https://forem.com/timoschinkel/peer-dependencies-in-pnpm-4mo6</guid>
      <description>&lt;p&gt;If you dive into &lt;a href="https://docs.npmjs.com/cli/v9/configuring-npm/package-json" rel="noopener noreferrer"&gt;the specification of &lt;code&gt;package.json&lt;/code&gt;&lt;/a&gt; you might be surprised to learn that next to the options &lt;code&gt;dependencies&lt;/code&gt; and &lt;code&gt;devDependencies&lt;/code&gt; there are also the options &lt;code&gt;bundleDependencies&lt;/code&gt;, &lt;code&gt;optionalDependencies&lt;/code&gt; and &lt;code&gt;peerDependencies&lt;/code&gt;. Recently we have been migrating our main application to an architecture with multiple frontends based on NextJS. Since we have shared components and logic we expose these as packages with peer dependencies. And I found that a good number of my colleagues are unfamiliar with peer dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are peer dependencies
&lt;/h2&gt;

&lt;p&gt;In order to explain peer dependencies, it is beneficial to first look at how &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;NPM&lt;/a&gt; and &lt;a href="https://pnpm.io/" rel="noopener noreferrer"&gt;PNPM&lt;/a&gt; work. Whenever you install a dependency in your project, this dependency can have other dependencies (these are typically referred to as non-root dependencies or &lt;a href="https://en.wikipedia.org/wiki/Transitive_dependency" rel="noopener noreferrer"&gt;transitive dependencies&lt;/a&gt;). Within the scoping model of (P)NPM these dependencies are tied to this specific dependency. The big benefit of this is that you hardly ever have version conflicts in your project, but a big downside of this is that you cannot guarantee that the dependency and your project will have the same version of a dependency, and you might get a good amount of duplicate dependencies in your &lt;code&gt;node_modules&lt;/code&gt; folder. Let's look at an example.&lt;/p&gt;

&lt;p&gt;NB. For the example I am using existing dependencies that I found in one of the projects of my employer. These dependencies are deliberately outdated, this will allow you to reproduce this yourself. The examples use NPM 10.9.4 and PNPM 10.20.0.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;chalk@4.1.2 wrap-ansi@8.1.0 ansi-styles@2.2.1 &lt;span class="nt"&gt;--save-dev&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now use &lt;code&gt;npm ls ansi-styles&lt;/code&gt; to get a list of usages of this package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── ansi-styles@2.2.1
├─┬ chalk@4.1.2
│ └── ansi-styles@4.3.0
└─┬ wrap-ansi@8.1.0
  └── ansi-styles@6.2.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have installed three different versions of the &lt;code&gt;ansi-styles&lt;/code&gt; package. How NPM stores this is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;└─┬ node_modules
  ├── ansi-styles       // version 2.2.1
  ├─┬ chalk
  │ └─┬ node_modules
  │   └── ansi-styles   // version 4.3.0
  └─┬ wrap-ansi
    └─┬ node_modules
      └── ansi-styles   // version 6.2.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can do the same in PNPM - &lt;code&gt;pnpm install chalk@4.1.2 wrap-ansi@8.1.0 ansi-styles@2.2.1 --save-dev&lt;/code&gt; - with a similar result for &lt;code&gt;pnpm why ansi-styles&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ansi-styles 2.2.1
chalk 4.1.2
└── ansi-styles 4.3.0
wrap-ansi 8.1.0
└── ansi-styles 6.2.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the folder structure we see that we still actually have three versions of &lt;code&gt;ansy-styles&lt;/code&gt; installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;└─┬ node_modules
  ├─┬ .pnpm
  │ ├── ansi-styles@2.2.1
  │ ├── ansi-styles@4.3.0
  │ ├── ansi-styles@6.0.1
  │ ├─┬ chalk@4.1.2
  │ │ └─┬ node_modules
  │ │   └── ansi-styles -&amp;gt; ../../ansi-styles@4.3.0/node_modules/ansi-styles
  │ └─┬ wrap-ansi@8.1.0
  │   └─┬ node_modules
  │     └── ansi-styles -&amp;gt; ../../ansi-styles@6.0.1/node_modules/ansi-styles
  └── ansi-styles -&amp;gt; .pnpm/ansi-styles@2.2.1/node_modules/ansi-styles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although PNPM makes heavily use of symlinks to save disk space, but we still have three copies of the &lt;code&gt;ansi-styles&lt;/code&gt; package. Even the &lt;a href="https://pnpm.io/next/cli/dedupe" rel="noopener noreferrer"&gt;&lt;code&gt;pnpm dedupe&lt;/code&gt;&lt;/a&gt; won't change this.&lt;/p&gt;

&lt;p&gt;Now we need to get a little bit hypothetical. Let's say that &lt;code&gt;wrap-ansi&lt;/code&gt; expects an object that is defined in &lt;code&gt;ansi-styles&lt;/code&gt; as argument to a function. This means that we need to instantiate this object in our application and pass this to &lt;code&gt;wrap-ansi&lt;/code&gt;. And let's say that between version &lt;code&gt;2.2.1&lt;/code&gt; of &lt;code&gt;ansi-styles&lt;/code&gt; - which we have defined in our project - and version &lt;code&gt;4.3.0&lt;/code&gt; of &lt;code&gt;ansi-styles&lt;/code&gt; - which is required by &lt;code&gt;chalk&lt;/code&gt; - the type definition  of this object has changed. There's a difference of two major versions, so backwards incompatibility is expected. What will happen? Our application will probably break at runtime.  &lt;/p&gt;

&lt;p&gt;This is where &lt;em&gt;peer dependencies&lt;/em&gt; come into play; a dependency that is marked as a peer dependency is required to be installed &lt;em&gt;next to&lt;/em&gt; the dependency, as a &lt;em&gt;peer&lt;/em&gt;. What if in this example &lt;code&gt;chalk&lt;/code&gt; marks &lt;code&gt;ansi-styles@^4.0.0&lt;/code&gt; as peer dependency. Then NPM would have thrown an error when we would try to install &lt;code&gt;ansi-styles@2.2.1&lt;/code&gt; as &lt;code&gt;2.2.1&lt;/code&gt; does not match the version range &lt;code&gt;^4.0.0&lt;/code&gt;. So, peer dependencies allow you to &lt;em&gt;guarantee&lt;/em&gt; that a transitive dependency is the same version range as the non-transitive dependency of the application.&lt;/p&gt;

&lt;p&gt;A concrete example of this is NextJS. NextJS is a framework that uses React, and as such the package &lt;code&gt;next&lt;/code&gt; has a peer dependency on &lt;code&gt;react&lt;/code&gt;, so when we want to install NextJS we als need to install React - and a number of additional packages. &lt;strong&gt;Be aware!&lt;/strong&gt; NPM and PNPM do &lt;strong&gt;not&lt;/strong&gt; automatically install peer dependencies. They will happily let you add &lt;code&gt;next&lt;/code&gt; as a dependency without adding &lt;code&gt;react&lt;/code&gt; as dependency, and without giving an error message. So, this is something you will need to do yourself. Installing &lt;code&gt;NextJS&lt;/code&gt; is done as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;next@^15 react@^19 react-dom@^19 @opentelemetry/api@^1.1 @playwright/test@^1.51.1 babel-plugin-react-compiler sass@^1.3  &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(P)NPM is an outlier in this behavior compared to package managers of other languages. With package managers like &lt;a href="https://getcomposer.org/" rel="noopener noreferrer"&gt;Composer&lt;/a&gt; (PHP), &lt;a href="https://pypi.org/project/pip/" rel="noopener noreferrer"&gt;pip&lt;/a&gt; (Python) and &lt;a href="https://www.nuget.org/" rel="noopener noreferrer"&gt;NuGet&lt;/a&gt; (.NET) dependencies are by default peer dependencies. That means that in those package managers it is not possible to have multiple versions of the same dependency in your application&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  When to use peer dependencies
&lt;/h2&gt;

&lt;p&gt;Peer dependencies are used when your application and one or more dependencies will be relying on the same definitions of methods or objects. A good rule of thumb is: when instantiation and usage are in two separate parts of the code then you might want to consider using peer dependencies. Let's highlight three concrete examples to illustrate this.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shared type definitions
&lt;/h3&gt;

&lt;p&gt;We currently operate in three countries, but in some countries we have multiple activities. Within our application landscape these activities are indicated as &lt;em&gt;subsidiaries&lt;/em&gt;. For the majority of code it is completely irrelevant how these subsidiaries are represented, but they &lt;em&gt;do&lt;/em&gt; need to have knowledge about subsidiaries, for example when we want to make an API call to retrieve information for the current subsidiary. We need to make sure that the subsidiary in the application is defined in the same way as it is in the package that makes the API call - let's call this package &lt;code&gt;product-information&lt;/code&gt; with a single method with the following signature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;GetProduct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subsidiary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Subsidiary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where should the type &lt;code&gt;Subsidiary&lt;/code&gt; be defined? And what if we also had another package to retrieve contact information - let's calls this package &lt;code&gt;contact-information&lt;/code&gt;? That is also localized per subsidiary. It is not desirable to have separate definitions for the same entity. For this we introduced an internal package called &lt;code&gt;constants&lt;/code&gt;. That package contains the definition of Subsidiary, and by making this package a &lt;em&gt;peer dependency&lt;/em&gt; of &lt;code&gt;product-information&lt;/code&gt; and or &lt;code&gt;contact-information&lt;/code&gt; we guarantee that the definition of &lt;code&gt;Subsidiary&lt;/code&gt; is the same in all the placed we need it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plugins
&lt;/h3&gt;

&lt;p&gt;We are using &lt;a href="https://www.npmjs.com/package/axios" rel="noopener noreferrer"&gt;Axios&lt;/a&gt; for HTTP requests, and &lt;a href="https://www.npmjs.com/package/apollo-client" rel="noopener noreferrer"&gt;Apollo Client&lt;/a&gt; for GraphQL requests. For both of these clients we have built extensions/plugins, for example to send correlation headers&lt;sup id="fnref2"&gt;2&lt;/sup&gt;. For such an extension you are dependent on the version of the client. As such we mark &lt;code&gt;axios&lt;/code&gt; a peer dependency of the extensions for Axios, and &lt;code&gt;apollo-client&lt;/code&gt; of the extensions for Apollo Client. That way we can guarantee that the plugin will be compatible with the version of the client.&lt;/p&gt;

&lt;p&gt;Sending these headers is not enough, they need to be added to the logs as well. That's why we also have an extension for our logger that automatically adds any correlation values to all logs. This extension therefore also has a peer dependency on the package that contains the logger.&lt;/p&gt;

&lt;p&gt;NB. These extensions &lt;em&gt;also&lt;/em&gt; have a peer dependency on a package that contains a type definition for &lt;code&gt;CorrelationContext&lt;/code&gt;, which is another example of the previous use case.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frameworks
&lt;/h3&gt;

&lt;p&gt;We have recently migrated away from our monolithic approach for our main application in favor of a decentralized approach, where separated parts of our application are handled by separate frontends. We have adopted &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;NextJS&lt;/a&gt; as our framework of choice for these frontends. Now, just because &lt;em&gt;we&lt;/em&gt; know that our application exists of multiple smaller frontends does not mean that our customers need to have this knowledge as well. In fact, for our customers we want to present our application as exactly that: a unified application. &lt;/p&gt;

&lt;p&gt;To achieve this idea of a single application we have introduced a slew of packages that build parts of the application; there's a package for the shared layout items - header, footer -, there's a package with all design elements (our design system), and there are packages for things like product cards. All these packages use features defined in both NextJS, but also in React - which is the foundation for NextJS. All these packages can only be guaranteed to work when they know what version of NextJS and React is being used. That is why for all these packages &lt;code&gt;next&lt;/code&gt; and &lt;code&gt;react&lt;/code&gt; are peer dependencies. &lt;/p&gt;

&lt;p&gt;For the latter example we can see how NPM responds to a deliberate violation of the peer dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; npm i next@^15.0 react@^15.0 &lt;span class="nt"&gt;--save&lt;/span&gt;
npm error code ERESOLVE
npm error ERESOLVE unable to resolve dependency tree
npm error
npm error While resolving: npm-peer-dependencies@1.0.0
npm error Found: react@15.7.0
npm error node_modules/react
npm error   react@&lt;span class="s2"&gt;"^15.0"&lt;/span&gt; from the root project
npm error
npm error Could not resolve dependency:
npm error peer react@&lt;span class="s2"&gt;"^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0"&lt;/span&gt; from next@15.5.6
npm error node_modules/next
npm error   next@&lt;span class="s2"&gt;"^15.0"&lt;/span&gt; from the root project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But let's have a look at the folder structure when we use the correct versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i next@^15 react@^19 next-auth@^4 &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have added &lt;code&gt;next-auth&lt;/code&gt; for illustration purposes, because &lt;code&gt;next-auth&lt;/code&gt; also has a peer dependency on &lt;code&gt;next&lt;/code&gt;, and this way we can illustrate that only one version of &lt;code&gt;next&lt;/code&gt; is installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;└─┬ node_modules
  ├── next
  ├── next-auth
  └── react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, instead of having potentially multiple version of the same package, we force NPM - and PNPM - to have a single version of the same package. &lt;/p&gt;

&lt;h2&gt;
  
  
  A note on PNPM
&lt;/h2&gt;

&lt;p&gt;PNPM by default emits a warning when there's an issue with peer dependencies, but it does not actually exit with a non-success exit code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; pnpm add next@^15.0 react@^15.0 &lt;span class="nt"&gt;--save&lt;/span&gt;

Progress: resolved 70, reused 33, downloaded 8, added 23, &lt;span class="k"&gt;done&lt;/span&gt;
 WARN  Issues with peer dependencies found
&lt;span class="nb"&gt;.&lt;/span&gt;
├─┬ react-dom 19.2.0
│ └── ✕ unmet peer react@^19.2.0: found 15.7.0
└─┬ next 15.5.6
  ├── ✕ unmet peer react@&lt;span class="s2"&gt;"^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0"&lt;/span&gt;: found 15.7.0
  └─┬ styled-jsx 5.1.6
    └── ✕ unmet peer react@&lt;span class="s2"&gt;"&amp;gt;= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"&lt;/span&gt;: found 15.7.0

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;
0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And also when installing the dependencies we PNPM will respond with a non-error exit code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; pnpm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--frozen-lockfile&lt;/span&gt;

Lockfile is up to &lt;span class="nb"&gt;date&lt;/span&gt;, resolution step is skipped
Already up to &lt;span class="nb"&gt;date&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;
0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The consequence of this is that automated pull requests from Dependabot or Renovate might pass inspections with invalid peer dependencies&lt;sup id="fnref3"&gt;3&lt;/sup&gt;. Looking at some issues on the PNPM repository - e.g. &lt;a href="https://github.com/pnpm/pnpm/issues/6893" rel="noopener noreferrer"&gt;#6893&lt;/a&gt; and &lt;a href="https://github.com/pnpm/pnpm/issues/7087" rel="noopener noreferrer"&gt;#7087&lt;/a&gt; - this is a deliberate choice, and not a high priority issue. There is a setting called &lt;a href="https://pnpm.io/next/settings#strictpeerdependencies" rel="noopener noreferrer"&gt;&lt;code&gt;strictPeerDependencies&lt;/code&gt;&lt;/a&gt; for this that you can enable for your repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'strict-peer-dependencies=true'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .npmrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem is that this setting does not work very consistently; it will not work when running &lt;code&gt;pnpm add&lt;/code&gt; nor when running &lt;code&gt;pnpm install&lt;/code&gt; with the &lt;code&gt;--frozen-lockfile&lt;/code&gt; flag - which should be the default in your CI/CD pipelines. For that to work you need to run an additional command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; pnpm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--resolution-only&lt;/span&gt; &lt;span class="nt"&gt;--prefer-frozen-lockfile&lt;/span&gt;

 ERR_PNPM_PEER_DEP_ISSUES  Unmet peer dependencies

&lt;span class="nb"&gt;.&lt;/span&gt;
├─┬ react-dom 19.2.0
│ └── ✕ unmet peer react@^19.2.0: found 15.7.0
└─┬ next 15.5.6
  ├── ✕ unmet peer react@&lt;span class="s2"&gt;"^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0"&lt;/span&gt;: found 15.7.0
  └─┬ styled-jsx 5.1.6
    └── ✕ unmet peer react@&lt;span class="s2"&gt;"&amp;gt;= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"&lt;/span&gt;: found 15.7.0

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;
1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NB. You might notice the missing &lt;code&gt;--frozen-lockfile&lt;/code&gt; flag and the presence of the &lt;code&gt;--prefer-frozen-lockfile&lt;/code&gt; flag. There's an issue open on the PNPM repository about this: &lt;a href="https://github.com/pnpm/pnpm/issues/8433" rel="noopener noreferrer"&gt;#8433&lt;/a&gt;. What my experiments have shown is that this command will correctly use the lockfile for resolution.&lt;/p&gt;

&lt;p&gt;Keep in mind that this does not actually install the dependencies! This will only perform a resolution step. You will still need to run &lt;code&gt;pnpm install --frozen-lockfile&lt;/code&gt; after running this command, but it will exit with a non-success exit code, and thus any code inspections should fail accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Looking at dependency managers for similar (web focused) languages the JavaScript ecosystem stands out; where Composer, Nuget and Pip install a package only once, NPM, PNPM and Yarn &lt;em&gt;scope&lt;/em&gt; a package to their direct dependency. This can become an issue in the scenarios where you reuse definitions between one of multiple packages. For these scenarios you can use the concept of &lt;em&gt;peer dependencies&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Proper handling of peer dependencies will give you &lt;em&gt;guarantees&lt;/em&gt; about versions of packages being used within your application, but also guarantees for the maintainer of packages that their package works as expected. Neither NPM and PNPM automatically install peer dependencies, nor do they notify you of &lt;em&gt;missing&lt;/em&gt; peer dependencies. NPM does give you the guarantee that the versions of peer dependencies are valid by default, but for PNPM some extra steps are required.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Of course, with enough trickery you might be able to install two versions of the same package, but it is far from trivial. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Correlation headers are headers that are sent with (internal) interactions. When added to logs it allows for correlating all the logs/operations across applications for a single request. The W3C has a recommendation in &lt;a href="https://www.w3.org/TR/trace-context/" rel="noopener noreferrer"&gt;Trace Context&lt;/a&gt; that has a similar purpose. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Of course every codebase has proper test coverage, so the inspections would fail in case invalid peer dependencies were to cause problems, right?! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>npm</category>
      <category>pnpm</category>
    </item>
    <item>
      <title>Friday Thoughts on email validation</title>
      <dc:creator>Timo Schinkel</dc:creator>
      <pubDate>Fri, 14 Jun 2024 08:10:57 +0000</pubDate>
      <link>https://forem.com/timoschinkel/friday-thoughts-on-email-validation-4fha</link>
      <guid>https://forem.com/timoschinkel/friday-thoughts-on-email-validation-4fha</guid>
      <description>&lt;p&gt;While working on a new authentication system I was getting alerts that account creation was failing. After diving into the logs I learned that the accounts were rejected because the email addresses were not deemed valid. But I made sure standardized email validation was in place. What's going on here?&lt;/p&gt;

&lt;h2&gt;
  
  
  So many systems and so many specifications
&lt;/h2&gt;

&lt;p&gt;The authentication system is web based and thus uses HTML&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. There is a backend written in JavaScript (actually TypeScript), which in turn - for some operations - talks to a service written in .NET that stores data in &lt;a href="https://aws.amazon.com/cognito/"&gt;AWS Cognito&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Because the front-end is web based we use &lt;code&gt;&amp;lt;input type="email"&amp;gt;&lt;/code&gt;. This has a number of benefits from the perspective of usability; we get out-of-the-box validation on the format of the input, for some devices a customized keyboard is shown, and password managers are inclined to prefill the field. The validation rules of this input type are well-defined in the &lt;a href="https://html.spec.whatwg.org/multipage/input.html#email-state-(type=email)"&gt;HTML specification&lt;/a&gt;. There's even a handy regular expression for you to use, which is nice as JavaScript does not have out-of-the-box email validation.&lt;/p&gt;

&lt;p&gt;The backend of our system is dotnet and uses a feature called &lt;a href="https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/mvc-music-store/mvc-music-store-part-6"&gt;Data Annotations for Model Validation&lt;/a&gt; that can be used to validate incoming models, including a validation for email addresses. Microsoft is nice enough to share the code for this validation with us: &lt;a href="https://github.com/microsoft/referencesource/blob/master/System.ComponentModel.DataAnnotations/DataAnnotations/EmailAddressAttribute.cs#L48"&gt;https://github.com/microsoft/referencesource/blob/master/System.ComponentModel.DataAnnotations/DataAnnotations/EmailAddressAttribute.cs#L48&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The storage for our system is AWS Cognito, and this was the actual source of our errors. Looking at &lt;a href="https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html"&gt;the documentation of Cognito&lt;/a&gt; AWS tells us the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generally email , Value must be a valid email address string following the standard email format with @ symbol and domain, up to 2048 characters in length.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Luckily we give AWS enough money that they are willing to answer our questions. AWS told me that they use &lt;a href="https://datatracker.ietf.org/doc/html/rfc3696#page-5"&gt;RFC 3696&lt;/a&gt; to validate email addresses.&lt;/p&gt;

&lt;p&gt;An interesting fact is that all the specifications for email related address &lt;em&gt;also&lt;/em&gt; need to be compliant with &lt;a href="https://datatracker.ietf.org/doc/html/rfc1035#section-2.3.1"&gt;RFC 1035&lt;/a&gt;. That RFC describes how a domain name should be constructed.&lt;/p&gt;

&lt;h2&gt;
  
  
  To validate or not to validate
&lt;/h2&gt;

&lt;p&gt;According to &lt;a href="https://david-gilbertson.medium.com/the-100-correct-way-to-validate-email-addresses-7c4818f24643"&gt;David Gilbertson&lt;/a&gt; the only proper way to validate an email address is by sending an email to that address containing a link. When that link is clicked then we know for sure that the email address is valid. But we are in the e-commerce business, and we want to remove as many &lt;em&gt;blockers&lt;/em&gt; from our customer journey as possible. As such we don't want to interrupt the checkout process with a verification email.&lt;/p&gt;

&lt;p&gt;So, yes ideally we would not validate the email syntax, and yes ideally we would send a verification email, but in the real world we are sometimes faced with non-ideal scenarios. In our situation it did not help that the error messages coming from Cognito do not contain distinctive error codes. And even if Cognito &lt;em&gt;did&lt;/em&gt; then our .NET service would have to respond with a Bad Request status code, and we still have to interpret the response. Validation of the syntax of an email address is not ideal, but for our scenario it allows us to quickly give feedback to our user and prevent "invalid" email addresses to make their way into the rest of our system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison
&lt;/h2&gt;

&lt;p&gt;The email addresses that were marked as invalid can be grouped in three scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;invalid &lt;code&gt;.&lt;/code&gt; usage; the local part of an email address cannot start of end with &lt;code&gt;.&lt;/code&gt; and two of more &lt;code&gt;.&lt;/code&gt; are not allowed. So &lt;code&gt;.name@example.com&lt;/code&gt;, &lt;code&gt;name.@example.com&lt;/code&gt;, and &lt;code&gt;na..me@example.com&lt;/code&gt; are not allowed&lt;/li&gt;
&lt;li&gt;missing TLD extensions; according to RFC 5233 the domain part can be any internet address, which makes &lt;code&gt;name@localhost&lt;/code&gt; a valid email address, however this is in violation of RFC 3696&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's make a comparison of how the different layers handle these addresses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                                    HTML    .NET    Cognito  
name@example.com                     ✅      ✅       ✅
name.name@example.com                ✅      ✅       ✅
"name..name"@example.com             ❌      ✅       ❌
name@localhost                       ✅      ✅       ✅
nåme@example.com                     ❌      ✅       ✅
aA0!#$%&amp;amp;'*+-/=?^_`{|}~@example.com   ✅      ✅       ✅

name.example.com                     ❌      ❌       ❌
.name@example.com                    ✅      ✅       ❌
name.@example.com                    ✅      ✅       ❌
name..name@example.com               ✅      ✅       ❌
&amp;lt;name&amp;gt;@example.com                   ❌      ✅       ❌

name@-example.com                    ❌      ✅       ❌
name@example-.com                    ❌      ✅       ❌
name@example.com-                    ❌      ✅       ❌

# extra examples from the 2024-6-28 update
name@x.com                           ✅      ✅       ✅
name@e.mail.com                      ✅      ✅       ✅
name@12mail.com                      ✅      ✅       ✅
name@1.1                             ✅      ✅       ❌
name@1.com                           ✅      ✅       ✅
name@1.2.com                         ✅      ✅       ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code used to test this using .NET and Cognito can be found in this Gist: &lt;a href="https://gist.github.com/timoschinkel/fe409ce4e019138778d4f0d9d1879e1e"&gt;https://gist.github.com/timoschinkel/fe409ce4e019138778d4f0d9d1879e1e&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was surprised by this outcome; AWS had told me that Cognito required an RFC 3696 compliant email address, but it still rejected &lt;code&gt;"name..name"@example.com&lt;/code&gt;, which is a valid address. At least how I interpret the specification.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl/dr;
&lt;/h2&gt;

&lt;p&gt;Although we would love to, we don't actually write code under perfect circumstances. Sometimes we are bound by limitations outside our influence. It was our choice to strive for a frictionless customer journey, without email verification via an actual email, and the consequence of this choice is that we depend on Cognito accepting our data, and when Cognito rejects it we introduce friction in our customer journey. By matching the validation rules in all layers with the layer that has the strictest rules we can at least tell our customers that their email address has been rejected and why.&lt;/p&gt;

&lt;p&gt;At the end of the day we created a regular expression that allowed addresses that are accepted in any layer of our application. It is not fully compliant with any of the specifications mentioned, but it will allow us to explain to our customers that their email address was rejected based on the structure. If a customer has an address that is blocked by our system we will find out where it is blocked and we'll try to find a way around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Addendum
&lt;/h2&gt;

&lt;p&gt;I did not manage to write a regular expression that meets all criteria - the maximum length is still an issue - but I did manage to create one that at works against the test set from this article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;^[\p{L}\d!#$%&amp;amp;'*+\-/=?^_`{|}~]+(?:\.[\p{L}\d!#$%&amp;amp;'*+\-/=?^_`{|}~]+)*@(?:(?!-[a-z0-9]+\.)(?![a-z0-9]+-\.)(?![a-z0-9]+--[a-z0-9]+\.)[a-z0-9-]+\.)+[a-z][a-z0-9]+$
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or for your HTML input&lt;sup id="fnref2"&gt;2&lt;/sup&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;pattern=&lt;/span&gt;&lt;span class="s"&gt;"[\p{L}\d!#$%&amp;amp;\x27*+\-\/=?^_`\{\|\}~]+(?:\.[\p{L}\d!#$%&amp;amp;\x27*+\-\/=?^_`\{\|\}~]+)*@(?:(?!-[a-z0-9]+\.)(?![a-z0-9]+-\.)(?![a-z0-9]+--[a-z0-9]+\.)[a-z0-9\-]+\.)+[a-z][a-z0-9]+"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Concessions have been made in creating this pattern. It does &lt;em&gt;not&lt;/em&gt; completely match any of the specifications mentioned in this article, but it does filter out all email addresses that would have been blocked by any of the layers in our application. And because the pattern element does not have any flags the pattern is by definition case-sensitive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update 2024-06-28
&lt;/h2&gt;

&lt;p&gt;After deploying this validation rule our observability platform detected a rise in errors; my regular expression missed a number of scenarios. As we don't log privacy-sensitive data to our observability platform we decided to run all our existing users against our pattern. In hindsight, we should have done this earlier in the process.&lt;/p&gt;

&lt;p&gt;What we found is that we had email addresses with accented characters like è that were now blocked. We also had missed one character domain names - &lt;code&gt;x.com&lt;/code&gt; and domain names that started with a numeric value.&lt;/p&gt;

&lt;p&gt;This shows that email validation using a pattern is very difficult and that David Gilbertson was right all along. But because we are still bound by the requirements from Cognito, and because we feel that notifying a visitor that their email address is likely invalid is still a better customer journey then risking the email not reaching the customer due to email reasons we still use a pattern validation.&lt;/p&gt;

&lt;p&gt;I have updated my test suite with email addresses that follow the same pattern as the email addresses that were falsely rejected, as well as the gists and the regular expressions. The regular expression now uses &lt;code&gt;\p{L}&lt;/code&gt;. This matches all characters that belong to the "letter" category, and this includes special characters like é. But because this has a larger match, it is only used for the name part of the email address. See &lt;a href="https://www.regular-expressions.info/unicode.html"&gt;https://www.regular-expressions.info/unicode.html&lt;/a&gt; for more explanation.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;This Friday Thought is also applicable if your frontend is built using React or Vue. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;The regular expression for the pattern attribute requires some changes; it is case-sensitive, &lt;code&gt;'&lt;/code&gt; and &lt;code&gt;"&lt;/code&gt; need to be encoded as &lt;code&gt;\x27&lt;/code&gt; and &lt;code&gt;\x22&lt;/code&gt; respectively, and more characters need to be escaped.  ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>Friday Thoughts on abstraction and not wanting to know</title>
      <dc:creator>Timo Schinkel</dc:creator>
      <pubDate>Fri, 02 Feb 2024 15:57:16 +0000</pubDate>
      <link>https://forem.com/timoschinkel/friday-thoughts-on-abstraction-and-not-wanting-to-know-18g0</link>
      <guid>https://forem.com/timoschinkel/friday-thoughts-on-abstraction-and-not-wanting-to-know-18g0</guid>
      <description>&lt;p&gt;Twice this week I found myself in a discussion about how to abstract a &lt;a href="https://en.wikipedia.org/wiki/Multicast"&gt;multicast&lt;/a&gt;-like behavior. Both times the discussion revolved around "what part of the code should have what knowledge"?&lt;/p&gt;

&lt;p&gt;The first situation was about retrieving information. To abstract the retrieval we introduced an interface - let's say &lt;code&gt;IRetrievalService&lt;/code&gt;. For reasons beyond the scope of this text some of this information can still be in a legacy system. When we built this application we decided to ignore the legacy system as it had not been updated in years. But analysis showed we would lose revenue, and so the only solution was to also query the legacy service. One colleague introduced the switch logic in the consumer of the service, in our case a controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;information&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;retrievalService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;NotFoundError&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;legacyRetrievalService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// handle error scenario&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another colleague suggested solving this "within" the interface; by introducing a fallback implementation that calls both the current and - if needed - the legacy system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FallbackRetrievalService&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;IRetrievalService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;retrievalService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IRetrievalService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;fallbackRetrievalService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IRetrievalService&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;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="o"&gt;&amp;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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;retrievalService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;NotFoundError&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fallbackRetrievalService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; 
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&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;Both approaches do &lt;em&gt;exactly&lt;/em&gt; the same. The difference is that for the first every part of the codebase that calls the &lt;code&gt;IRetrievalService&lt;/code&gt; needs to have knowledge about when and how to fall back to the legacy service. The latter approach &lt;em&gt;abstracts&lt;/em&gt; that knowledge away with the result that &lt;em&gt;none&lt;/em&gt; of the parts of the codebase that call the &lt;code&gt;IRetrievalService&lt;/code&gt; needs to know about the legacy service. In fact only two parts of the code need to have some knowledge about this behavior; the actual &lt;code&gt;FallbackRetrievalService&lt;/code&gt; and the code that handles dependency injection/initialization. &lt;/p&gt;

&lt;p&gt;I think that for every abstraction that you write you need to ask yourself the question: Who needs to know what? I have seen too many occurrences where an interface required a table name as parameter - should the code calling the interface have the knowledge that the data is stored in a database? -, and too many occurrences where an interface could throw a database exception or an HTTP exception - again; should the code calling the interface have the knowledge that that is coming from a database or API? No. At least, not in my opinion.&lt;/p&gt;

&lt;p&gt;By consequently asking yourself the question "where should this knowledge be?" you can make your code much more flexible and concise. If a year from now we decide to remove the legacy service, all that is to be done is change the dependency injection/initialization and remove a few files. None of the calling code needs to be changed. It also helps you with testing; you want to be sure that the fallback scenario is working as expected. With a &lt;code&gt;FallbackRetrievalService&lt;/code&gt; you only need to test that class, and you don't need to test all possible variations at every location where it is called. As a bonus it is much easier to ensure the fallback (or multicast) is applied everywhere.&lt;/p&gt;

</description>
      <category>abstraction</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Constructor promotion in serializable objects</title>
      <dc:creator>Timo Schinkel</dc:creator>
      <pubDate>Fri, 16 Jun 2023 11:42:27 +0000</pubDate>
      <link>https://forem.com/timoschinkel/constructor-promotion-in-serializable-objects-3b31</link>
      <guid>https://forem.com/timoschinkel/constructor-promotion-in-serializable-objects-3b31</guid>
      <description>&lt;p&gt;I am not one to easily get excited about new syntactical sugar in languages. As such I was also sceptical about the introduction of &lt;a href="https://www.php.net/manual/en/language.oop5.decon.php#language.oop5.decon.constructor.promotion"&gt;constructor promotion&lt;/a&gt; in PHP 8.0. But I have grown to really like it. It is a great way to shorten the definition of you objects, and I actually miss it now when I'm working in C# or TypeScript. I use constructor promotion in both services and in value objects, but recently we suffered an outage caused by applying constructor on an object that was serialized for caching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt; Serialization does not necessarily have to happen explicitly. Session handlers and cache handlers often serialize and deserialize objects implicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our object
&lt;/h2&gt;

&lt;p&gt;In order to demonstrate the issue let's assume an object:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Client&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="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="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&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;getId&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&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;No, what happens when we serialize this object?&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="nb"&gt;file_put_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'client.serialized'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;serialize&lt;/span&gt;&lt;span class="p"&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;'abc'&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will output the following string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;O:6:"Client":1:{s:10:"Clientid";s:3:"abc";}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt; &lt;code&gt;Clientid&lt;/code&gt; is not a string with a length of 10. Because &lt;code&gt;Client::$id&lt;/code&gt; is a private property the property in the string representation is surrounded by special byte characters.&lt;/p&gt;

&lt;h2&gt;
  
  
  A new property appears
&lt;/h2&gt;

&lt;p&gt;As time goes by we find that we want to add another property to our object, so we update the definition:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Client&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="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="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="o"&gt;=&lt;/span&gt; &lt;span class="s1"&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;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;getId&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&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;getName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&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;After deployment the codebase tries to deserialize the previous data, and we&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;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;unserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'O:6:"Client":1:{s:10:"Clientid";s:3:"abc";}'&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;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will break on the line where we call &lt;code&gt;Client::getName()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fatal error: Uncaught Error: Typed property Client::$name must not be accessed before initialization in {filename}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's happening
&lt;/h2&gt;

&lt;p&gt;When unserializing PHP interprets the serialized string and tries to rebuild the object. The serialized string contains the name of the class and all the properties. This includes private and protected properties. The rebuilding of the object is not done via the constructor, but the values are set directly on the object instance. Because the constructor is not called, the new property &lt;code&gt;name&lt;/code&gt; is not defined. This is the cause of the error.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to prevent
&lt;/h2&gt;

&lt;p&gt;There are a number of ways to prevent this. &lt;/p&gt;

&lt;h3&gt;
  
  
  Don't use constructor promotion
&lt;/h3&gt;

&lt;p&gt;Easiest solution is to not use constructor promotion for objects that can be serialized. That will add some code, but it will prevent these errors:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;
&lt;span class="p"&gt;{&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="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="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&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="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="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&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;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$id&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="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&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;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&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;getName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&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;In this example I opted to declare all properties for consistency reasons. Keep in mind that this can potentially still cause issues if you add properties without a default value. Those will result in the same error that the property must not be accessed before initialization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the magic methods &lt;code&gt;__serialize()&lt;/code&gt; and &lt;code&gt;__unserialize()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;By using the &lt;code&gt;__serialize()&lt;/code&gt; and &lt;code&gt;__unserialize()&lt;/code&gt; you can steer how your object is serialized and unserialized:&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Client&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;__serialize&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;get_object_vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;);&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;__unserialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// instantiate new properties:&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&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="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$value&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;This adds more difficulties as you still need to update your &lt;code&gt;__unserialize()&lt;/code&gt; method body with every new property you add.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt; PHP has the &lt;a href="https://www.php.net/manual/en/class.serializable.php"&gt;&lt;code&gt;Serializable&lt;/code&gt;&lt;/a&gt; interface, but that has been deprecated in favor of &lt;code&gt;__serialize()&lt;/code&gt; and &lt;code&gt;__unserialize()&lt;/code&gt;, so I will not mention that as a solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run your own serialization
&lt;/h3&gt;

&lt;p&gt;You can of course build your own serialization mechanism. You can opt to export to JSON, but you will have to handle your unserialization yourself as well. In which case this whole article might not be relevant to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl/dr;
&lt;/h2&gt;

&lt;p&gt;Object serialization, although often used, has some pitfalls that you as a developer should be aware of, but that are often overlooked. One of those pitfalls is constructor promotion. I found that the easiest way around that is to not use constructor promotion for properties that you add while you may still have string representations that were created before the property was added.&lt;/p&gt;

</description>
      <category>php</category>
    </item>
    <item>
      <title>Make your Cloudformation conditions mean something</title>
      <dc:creator>Timo Schinkel</dc:creator>
      <pubDate>Mon, 10 Oct 2022 11:22:33 +0000</pubDate>
      <link>https://forem.com/timoschinkel/make-your-cloudformation-conditions-mean-something-2f69</link>
      <guid>https://forem.com/timoschinkel/make-your-cloudformation-conditions-mean-something-2f69</guid>
      <description>&lt;p&gt;Within &lt;a href="https://aws.amazon.com/cloudformation/"&gt;AWS Cloudformation&lt;/a&gt; it is possible to create conditions. You can use these conditions to change behavior of the stack, like create a resource only in some situations. It is tempting to use the environment as a base for your condition. Even the &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html"&gt;documentation of AWS&lt;/a&gt; has an example with the condition &lt;code&gt;CreateProdResources&lt;/code&gt;. While performing some migrations I realised that these conditions don't mean anything, and so I renamed my conditions to have meaningful names.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment
&lt;/h2&gt;

&lt;p&gt;A typical list of conditions as I've seen so far might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="na"&gt;IsTesting&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Equals&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;testing"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;IsProductionOrAcceptance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Or&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;!Equals&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;production"&lt;/span&gt; &lt;span class="pi"&gt;],&lt;/span&gt; &lt;span class="kt"&gt;!Equals&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;acceptance"&lt;/span&gt; &lt;span class="pi"&gt;]]&lt;/span&gt;
  &lt;span class="na"&gt;IsProduction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Equals&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;production"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These conditions are typically used like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;RdsClusterNew&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::RDS::DBCluster"&lt;/span&gt;
    &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IsTesting&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# ...&lt;/span&gt;
      &lt;span class="na"&gt;DBClusterParameterGroupName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!If&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;IsTesting&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RdsClusterParameterGroupWithPerformanceInsights"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RdsClusterParameterGroup"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a random resource and when you look at this example it makes sense; Only on the testing stack do we want to create this database cluster and only on the testing stack do we want to enable performance insights for the database. But a feature rarely has a single resource; When creating an RDS cluster you'll need a cluster, a parameter group, instances, instance parameter groups, and possibly even other resources. Enabling the RDS on another environment would mean changing multiple lines. This has an increased risk of changing a condition too many or too few.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meaningful conditions
&lt;/h2&gt;

&lt;p&gt;One way to avoid this is to give your conditions meaningful names, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;CreateNewRdsCluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Equals&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;testing"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;EnablePerformanceInsights&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Equals&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;testing"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;RdsClusterNew&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::RDS::DBCluster"&lt;/span&gt;
    &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CreateNewRdsCluster&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# ...&lt;/span&gt;
      &lt;span class="na"&gt;DBClusterParameterGroupName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!If&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;EnablePerformanceInsights&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RdsClusterParameterGroupWithPerformanceInsights"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RdsClusterParameterGroup"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now also creating the new RDS cluster on the acceptance environment as well is a single line change; You only need to change the condition. And the same thing goes for enabling Performance Insights.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl/dr;
&lt;/h2&gt;

&lt;p&gt;Naming is hard, and just like with your methods and variables in code you will benefit from meaningful and descriptive names when working with (conditions in) Cloudformation. Not only does it make the resource definitions better to read and understand, it also makes enabling or disabling resources easier as they are one-line changes.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudformation</category>
      <category>quicktips</category>
    </item>
    <item>
      <title>The case for immutability</title>
      <dc:creator>Timo Schinkel</dc:creator>
      <pubDate>Fri, 29 Apr 2022 19:05:21 +0000</pubDate>
      <link>https://forem.com/timoschinkel/the-case-for-immutability-1gfa</link>
      <guid>https://forem.com/timoschinkel/the-case-for-immutability-1gfa</guid>
      <description>&lt;p&gt;Some common questions I get on pull requests are "what's with those with-methods?" and "why do you use DateTimeImmutable?". The reason is I am a fan of &lt;em&gt;immutability&lt;/em&gt;. I became a fan of immutability the hard way; By introducing bugs caused by (unintentional) mutability.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is immutability
&lt;/h2&gt;

&lt;p&gt;When an object is immutable its state can not be modified after the object has been created. Concrete this means that an immutable object does not have any &lt;em&gt;writable&lt;/em&gt; properties nor any &lt;em&gt;setters&lt;/em&gt; to update the properties.&lt;/p&gt;

&lt;p&gt;For clarification; The most simple implementation of a &lt;em&gt;mutable&lt;/em&gt; object:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MutableObject&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;$type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&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;A more elaborate implementation could have a constructor and a setter. Using a constructor and a setter allows for validation on the value for both initialization and for mutation:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MutableObject&lt;/span&gt;
&lt;span class="p"&gt;{&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;$type&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="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;)&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="nb"&gt;setType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;);&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;setType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&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="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InvalidArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Type cannot be empty'&lt;/span&gt;&lt;span class="p"&gt;);&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="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;;&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;getType&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;type&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;h2&gt;
  
  
  Why make an object immutable
&lt;/h2&gt;

&lt;p&gt;In short; To guarantee the validity of an object.&lt;/p&gt;

&lt;p&gt;In PHP scalar values - integer, float, string and boolean are &lt;em&gt;passed by value&lt;/em&gt; by default. That means that in a function or method where I pass an integer as argument we can assign the value of that integer without any side effects on the code that made the call:&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;function&lt;/span&gt; &lt;span class="n"&gt;doSomething&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;$number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$number&lt;/span&gt; &lt;span class="o"&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="nv"&gt;$number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$number&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$number&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This above example will output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;12345
12345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Objects and arrays&lt;sup id="fnref1"&gt;1&lt;/sup&gt; are by default &lt;em&gt;passed by reference&lt;/em&gt;. That means that any changes I apply on an object inside a function or method that was passed as an argument will have side effects on the case that made the call:&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;function&lt;/span&gt; &lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;DateTime&lt;/span&gt; &lt;span class="nv"&gt;$date&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$date&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;DateInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'P1D'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$date&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;DateTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"2022-04-26"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$date&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$date&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Y-m-d'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This above example will  output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2022-04-26
2022-04-27
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contents of &lt;code&gt;$date&lt;/code&gt; has been mutated. And there is no way to prevent this in PHP. Apart from making sure your objects can not be mutated. With an immutable object you can be sure that another piece of code does not (accidentally) change the object causing unexpected side effects. Let's assume another example - a scenario I actually encountered myself:&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;$today&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;DateTime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// this could be injected from a clock&lt;/span&gt;

&lt;span class="nv"&gt;$openingHours&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;openingHoursService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getOpeningHoursForUpcomingDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$today&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isCurrentlyClosed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$today&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$openingHours&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// try to find an alternative that is currently open&lt;/span&gt;
    &lt;span class="nv"&gt;$currentlyOpenStores&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;openingHoursService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getCurrentlyOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$today&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After releasing this change it took a few days for one of the stakeholders to start complaining about wrong information being shown. We were unable to reproduce this until a colleague decided to set &lt;code&gt;$today&lt;/code&gt; to the moment the stakeholder reported the issue. Now we saw the wrong information as well! Stepping through the code we discovered that properties of &lt;code&gt;$today&lt;/code&gt; were changing after calling the opening hours service. We had a look at the implementation and found that it queried the database as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt;
    &lt;span class="k"&gt;open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;closed&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt;
    &lt;span class="n"&gt;opening_hours&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt; 
    &lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;store_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DateInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"P${days}D"&lt;/span&gt;&lt;span class="p"&gt;))}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;$today&lt;/code&gt; is an instance of &lt;code&gt;DateTime&lt;/code&gt; calling the &lt;a href="https://www.php.net/manual/en/datetime.add.php"&gt;&lt;code&gt;add()&lt;/code&gt;&lt;/a&gt; method on it actually updated the internal value of &lt;code&gt;$today&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We can now get into a discussion about this implementation. If the developer that implemented this method had used the date manipulation features of the database this issue would not have existed. More important is that &lt;em&gt;unexpectedly&lt;/em&gt; an unrelated piece of code changed "my object". This is exactly the scenario where immutability can help; If we were to pass an immutable object we can be absolutely certain that no matter how &lt;code&gt;getOpeningHoursForUpcomingDays()&lt;/code&gt; is implemented the object that we pass to it will never change.&lt;/p&gt;

&lt;p&gt;The solution for this specific scenario was to replace the &lt;code&gt;DateTime&lt;/code&gt; with &lt;code&gt;DateTimeImmutable&lt;/code&gt;. It required a change in signature for the service we called, but from that moment on our bug was fixed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to implement an immutable object
&lt;/h2&gt;

&lt;p&gt;The immutable equivalent of &lt;code&gt;MutableObject&lt;/code&gt; could look something 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="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImmutableObject&lt;/span&gt;
&lt;span class="p"&gt;{&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;$type&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="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$type&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="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InvalidArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Type cannot be empty'&lt;/span&gt;&lt;span class="p"&gt;);&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="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;;&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;getType&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;type&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;So what about those "with-methods" mentioned earlier. Ideally all properties are to be part of the constructor. This can lead to some readability difficulties when working with a large amount of properties and when some properties are optional. Another scenario is when you want to change one or more values after instantiation of the object. The convention we have been using - and that is used in PSR's as well - is to use methods that start with &lt;code&gt;with&lt;/code&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="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImmutableObject&lt;/span&gt;
&lt;span class="p"&gt;{&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;$type&lt;/span&gt;&lt;span class="p"&gt;;&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;$label&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="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="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$label&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="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InvalidArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Type cannot be empty'&lt;/span&gt;&lt;span class="p"&gt;);&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="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$type&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="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$label&lt;/span&gt;&lt;span class="p"&gt;;&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;getType&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&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;withLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$label&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;static&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;self&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="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$label&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;Another implementation uses &lt;code&gt;clone&lt;/code&gt;. This implementation is useful when an object had a high number of properties or when the validity of your object requires a combination of arguments to be specified&lt;sup id="fnref2"&gt;2&lt;/sup&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="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImmutableObject&lt;/span&gt;
&lt;span class="p"&gt;{&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;$type&lt;/span&gt;&lt;span class="p"&gt;;&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;$label&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="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="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$type&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="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InvalidArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Type cannot be empty'&lt;/span&gt;&lt;span class="p"&gt;);&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="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;;&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;getType&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&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;withLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$label&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;static&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$clone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;clone&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$clone&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$label&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;$clone&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;Instantiating these objects becomes a bit more verbose, but will almost resemble prose:&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;$object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ImmutableObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'my-type'&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;withLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'My type'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the examples shown so far I have opted for verbosity. With the syntactic sugar that is introduced in PHP 8 and PHP 8.1 we can shorten object definitions drastically:&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;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImmutableObject&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$type&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;This example will make the property available for usage by other objects. If you prefer to use methods for retrieval of data all you need to do is make the property &lt;code&gt;private&lt;/code&gt; and introduce a &lt;code&gt;getter&lt;/code&gt; similar to the examples above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should every object be immutable?
&lt;/h2&gt;

&lt;p&gt;Short answer: no. In my opinion writing code is like being in traffic; You need to be predictable. I think most data containers would benefit from immutability. There are however some scenarios where a mutable object makes more sense as some objects are expected to maintain state. For example a form abstraction; A form contains objects that represent the fields and these fields have a value. This value can be pre-populated, but will be updated based on the info that is submitted. In that scenario it makes sense that the form instance has some form of state.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl/dr;
&lt;/h2&gt;

&lt;p&gt;Mutable objects can cause bugs that might be difficult to find. By making object immutable you have the guarantee that you are in control of your objects and their state. Making objects in immutable requires only a relative small amount of code. &lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Arrays are technically passed by reference, but because most operations on an array creates a new array instance this is not very apparent. Calling methods that change the internal pointer of an array - like &lt;code&gt;reset()&lt;/code&gt; and &lt;code&gt;next()&lt;/code&gt; - &lt;em&gt;do&lt;/em&gt; have effects on the array instance and can therefore "leak".  ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;PHP 8 has introduced &lt;a href="https://stitcher.io/blog/php-8-named-arguments"&gt;named arguments&lt;/a&gt;. This makes working with a large number of arguments easier. The downsides of this are that your argument names have now become part of your public facing API and you will have to add more complex validation rules when arguments can only be set in combination with other arguments. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>php</category>
      <category>programming</category>
    </item>
    <item>
      <title>Keeping dependencies up-to-date in Composer</title>
      <dc:creator>Timo Schinkel</dc:creator>
      <pubDate>Wed, 28 Jul 2021 11:58:23 +0000</pubDate>
      <link>https://forem.com/timoschinkel/keeping-dependencies-up-to-date-in-composer-5g4f</link>
      <guid>https://forem.com/timoschinkel/keeping-dependencies-up-to-date-in-composer-5g4f</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/timoschinkel/good-practices-when-working-with-composer-5a1c"&gt;Good practices when working with Composer&lt;/a&gt; I discussed some basics about &lt;a href="https://getcomposer.org/"&gt;Composer&lt;/a&gt;. Something that is not discussed in that article is the importance of keeping your dependencies up-to-date. This goes for both libraries and applications. In this article I will focus on applications - codebases that also maintain a &lt;code&gt;composer.lock&lt;/code&gt; file in source control. The majority of the tips and tricks however can also be used for libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should I keep my dependencies up-to-date?
&lt;/h2&gt;

&lt;p&gt;Not updating your dependencies has its benefits - you are guaranteed that the interface of the dependency will not change for example. It has some downsides as well however; You will miss out on security updates, new features and improvements. &lt;/p&gt;

&lt;p&gt;Another reason to keep your dependencies up-to-date is to keep your migrations small. It is - usually - simpler to migrate a minor version than to migrate a major version&lt;sup id="fnref1"&gt;1&lt;/sup&gt; as minor upgrades usually contain fewer changes and &lt;em&gt;should&lt;/em&gt; not introduce breaking changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  composer outdated
&lt;/h2&gt;

&lt;p&gt;The simplest way to find out if you have dependencies that are not up-to-date is to run &lt;a href="https://getcomposer.org/doc/03-cli.md#outdated"&gt;&lt;code&gt;composer outdated&lt;/code&gt;&lt;/a&gt;. This command will output a list of all dependencies - both direct dependencies and indirect dependencies&lt;sup id="fnref2"&gt;2&lt;/sup&gt; -, their current version in your &lt;code&gt;composer.lock&lt;/code&gt; and their most recent version. Dependencies that are up-to-date are by default &lt;strong&gt;not&lt;/strong&gt; shown. If you do want to show these add the flag &lt;code&gt;-a&lt;/code&gt; or &lt;code&gt;--all&lt;/code&gt;. This is an excerpt of the output of &lt;code&gt;composer outdated --all&lt;/code&gt; I ran on one of my codebases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;phpunit/phpunit                       9.5.6     9.5.6     The PHP Unit Testing framework.
psr/container                         1.1.0     2.0.1     Common Container Interface &lt;span class="o"&gt;(&lt;/span&gt;PHP FIG PSR-11&lt;span class="o"&gt;)&lt;/span&gt;
psr/log                               1.1.3     1.1.4     Common interface &lt;span class="k"&gt;for &lt;/span&gt;logging libraries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is good to know that &lt;code&gt;composer outdated&lt;/code&gt; does not take any version constraints into account when compiling the list. The version constraint for &lt;code&gt;psr/container&lt;/code&gt; is set to &lt;code&gt;^1.1&lt;/code&gt;, but &lt;code&gt;composer outdated&lt;/code&gt; shows &lt;code&gt;2.0.1&lt;/code&gt; as the most recent version. &lt;/p&gt;

&lt;p&gt;Apart from the &lt;code&gt;--all&lt;/code&gt; flag a few other useful flags are available for &lt;code&gt;composer outdated&lt;/code&gt;. The documentation of Composer explains these flags very well. &lt;/p&gt;

&lt;h2&gt;
  
  
  Updating packages
&lt;/h2&gt;

&lt;p&gt;So what if one or more dependencies is outdated? You update them! To update dependencies two commands can be used: &lt;code&gt;composer update&lt;/code&gt; and &lt;code&gt;composer require&lt;/code&gt;. The difference between these two commands is that &lt;code&gt;composer update&lt;/code&gt; will try to update a dependency based on the current constraints in &lt;code&gt;composer.json&lt;/code&gt; and will only update &lt;code&gt;composer.lock&lt;/code&gt;. With &lt;code&gt;composer require&lt;/code&gt; however Composer will try to install the latest version - keeping existing dependencies and platform constraints in mind - and will update both &lt;code&gt;composer.json&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; &lt;code&gt;composer.lock&lt;/code&gt;. This difference also means that &lt;code&gt;composer update&lt;/code&gt; typically will not update a package to a new major version.&lt;/p&gt;

&lt;h3&gt;
  
  
  composer update
&lt;/h3&gt;

&lt;p&gt;Taking the output from &lt;code&gt;composer outdated&lt;/code&gt; from before we can run &lt;code&gt;composer update&lt;/code&gt;. This will try to update all dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; composer update
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 2 updates, 0 removals
  - Upgrading psr/container &lt;span class="o"&gt;(&lt;/span&gt;1.1.0 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 1.1.1&lt;span class="o"&gt;)&lt;/span&gt;
  - Upgrading psr/log &lt;span class="o"&gt;(&lt;/span&gt;1.1.3 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 1.1.4&lt;span class="o"&gt;)&lt;/span&gt;
Writing lock file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you're working on a large codebase with a lot of dependencies, updating all of them might result in a lot of new packages. This can be undesirable as you might not know how and where all these dependencies are used. If that is the case you can limit the dependencies to be updated by specifying them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer update psr/container psr/log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The side effect of specifying what dependencies should be updated is that Composer will &lt;em&gt;not&lt;/em&gt; update any other packages. This can be a problem when you are trying to update to a new minor version, but one of the indirect dependencies needs a newer version as well. Assume that I have installed &lt;a href="https://packagist.org/packages/timoschinkel/codeowners-cli"&gt;&lt;code&gt;timoschinkel/codeowners-cli&lt;/code&gt;&lt;/a&gt; with the constraint &lt;code&gt;^1.0&lt;/code&gt; and I have currently installed &lt;code&gt;1.0.0&lt;/code&gt;. This library depends on &lt;code&gt;timoschinkel/codeowners:^1.0&lt;/code&gt; and version &lt;code&gt;1.0.0&lt;/code&gt; is therefore installed. A new version of &lt;code&gt;timoschinkel/codeowners-cli&lt;/code&gt; is released, tagged &lt;code&gt;1.1.0&lt;/code&gt; and now it requires &lt;code&gt;timoschinkel/codeowners:^1.1&lt;/code&gt;. Running &lt;code&gt;composer update timoschinkel/codeowners-cli&lt;/code&gt; will result in Composer not updating the dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; composer update timoschinkel/codeowners-cli
Loading composer repositories with package information
Updating dependencies
Nothing to modify &lt;span class="k"&gt;in &lt;/span&gt;lock file
Writing lock file
Installing dependencies from lock file &lt;span class="o"&gt;(&lt;/span&gt;including require-dev&lt;span class="o"&gt;)&lt;/span&gt;
Nothing to &lt;span class="nb"&gt;install&lt;/span&gt;, update or remove
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Composer will see that the constraint &lt;code&gt;timoschinkel/codeowners:^1.1&lt;/code&gt; does not match the already installed version &lt;code&gt;1.0.0&lt;/code&gt;. We can specify a specific version to be installed. Maybe Composer just needs some help:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; composer update timoschinkel/codeowners-cli:1.1.0
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable &lt;span class="nb"&gt;set &lt;/span&gt;of packages.

  Problem 1
    - Root composer.json requires timoschinkel/codeowners-cli ^1.0, 1.1.0 -&amp;gt; satisfiable by timoschinkel/codeowners-cli[1.1.0].
    - timoschinkel/codeowners-cli 1.1.0 requires timoschinkel/codeowners ^1.1.0 -&amp;gt; found timoschinkel/codeowners[1.1.0] but the package is fixed to 1.0.0 &lt;span class="o"&gt;(&lt;/span&gt;lock file version&lt;span class="o"&gt;)&lt;/span&gt; by a partial update and that version does not match. Make sure you list it as an argument &lt;span class="k"&gt;for &lt;/span&gt;the update command.

Use the option &lt;span class="nt"&gt;--with-all-dependencies&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;-W&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; to allow upgrades, downgrades and removals &lt;span class="k"&gt;for &lt;/span&gt;packages currently locked to specific versions.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One option to solve this would be to add &lt;code&gt;timoschinkel/codeowners&lt;/code&gt; to the list of packages to update as well. This could however lead to just another dependency that is causing the same problem. The solution is to use either &lt;code&gt;-W&lt;/code&gt; or &lt;code&gt;-w&lt;/code&gt; with the &lt;code&gt;composer update&lt;/code&gt; command - as Composer tells us already in the output. What this flag will do is also update dependencies of the dependencies that you are updating. The difference between &lt;code&gt;-w&lt;/code&gt; (lowercase) and &lt;code&gt;-W&lt;/code&gt; (uppercase) is that the latter will also update any direct dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; composer update timoschinkel/codeowners-cli &lt;span class="nt"&gt;-w&lt;/span&gt;
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 2 updates, 0 removals
  - Upgrading timoschinkel/codeowners &lt;span class="o"&gt;(&lt;/span&gt;1.0.0 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 1.1.0&lt;span class="o"&gt;)&lt;/span&gt;
  - Upgrading timoschinkel/codeowners-cli &lt;span class="o"&gt;(&lt;/span&gt;1.0.0 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 1.1.0&lt;span class="o"&gt;)&lt;/span&gt;
Writing lock file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  composer require
&lt;/h3&gt;

&lt;p&gt;As mentioned before, running &lt;code&gt;composer update&lt;/code&gt; will seek newer versions of your dependencies &lt;em&gt;while taking the version constraints into account&lt;/em&gt;. That means that a new major version is not likely to be installed. I found that the easiest way to upgrade a dependency to a new major version is to use &lt;code&gt;composer require&lt;/code&gt;. This will work in the same way as when you would require a dependency that is not already present in your &lt;code&gt;composer.json&lt;/code&gt;; It will find the most recent version - taking any existing constraints into account - and updates the &lt;code&gt;composer.json&lt;/code&gt; with the closest minor version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; composer require psr/log
Using version ^3.0 &lt;span class="k"&gt;for &lt;/span&gt;psr/log
./composer.json has been updated
Running composer update psr/log
Loading composer repositories with package 
Lock file operations: 0 installs, 1 update, 0 removals
  - Upgrading psr/log &lt;span class="o"&gt;(&lt;/span&gt;1.1.4 &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 3.0.0&lt;span class="o"&gt;)&lt;/span&gt;
Writing lock file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to &lt;code&gt;composer update&lt;/code&gt; you can specify a specific version, require multiple dependencies, and you can use &lt;code&gt;-w&lt;/code&gt; and &lt;code&gt;-W&lt;/code&gt; if needed. Nice side effect is that Composer will verify if any indirect dependencies are now no longer needed and will remove them from your &lt;code&gt;composer.lock&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt; When using &lt;code&gt;composer require&lt;/code&gt; on an existing development dependency don't forget to use the &lt;code&gt;--dev&lt;/code&gt; flag, otherwise Composer will mark the dependency a production dependency.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to update a dependency constraint
&lt;/h3&gt;

&lt;p&gt;Let's assume your codebase uses PHPUnit via the constraint &lt;code&gt;^9.4&lt;/code&gt;. You are currently using version &lt;code&gt;9.4.4&lt;/code&gt; and you are updating to version &lt;code&gt;9.5.7&lt;/code&gt;. Should you update the constraint in &lt;code&gt;composer.json&lt;/code&gt; to &lt;code&gt;^9.5&lt;/code&gt;? &lt;/p&gt;

&lt;p&gt;Your constraint should reflect the versions that your codebase supports. Does your codebase require a feature introduced in &lt;code&gt;9.5&lt;/code&gt;? In that case you should definitely update the constraint to &lt;code&gt;^9.5&lt;/code&gt; and thus update via &lt;code&gt;composer require --dev phpunit/phpunit:^9.5 -w&lt;/code&gt;. Are you updating just the dependency with the purpose of running the most recent version? In that case there is no need to update the constraint and thus update via &lt;code&gt;composer update phpunit/phpunit -w&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging updates
&lt;/h2&gt;

&lt;p&gt;Composer offers two commands that are instrumental when maintaining larger codebases; &lt;a href="https://getcomposer.org/doc/03-cli.md#depends-why-"&gt;&lt;code&gt;composer why&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://getcomposer.org/doc/03-cli.md#prohibits-why-not-"&gt;&lt;code&gt;composer why-not&lt;/code&gt;&lt;/a&gt;&lt;sup id="fnref3"&gt;3&lt;/sup&gt;. Just as the names imply can you use these commands to ask Composer why a certain dependency is available or why a certain dependency cannot be installed.&lt;/p&gt;

&lt;p&gt;The main use case for &lt;code&gt;composer why&lt;/code&gt; is to find out why an indirect dependency is present in your &lt;code&gt;composer.lock&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; composer why paragonie/random_compat
ramsey/uuid  3.9.3  requires  paragonie/random_compat &lt;span class="o"&gt;(&lt;/span&gt;^1 | ^2 | 9.99.99&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;composer why-not&lt;/code&gt; can tell you the exact opposite. I have found this to be very useful when I find myself in a situation where I'm unable to update an indirect dependency to a specific version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; composer why-not paragonie/random_compat:9.99.100
ramsey/uuid  3.9.3  requires  paragonie/random_compat &lt;span class="o"&gt;(&lt;/span&gt;^1 | ^2 | 9.99.99&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hidden power
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;composer why-not&lt;/code&gt; has a "hidden power"; It also works for requirements like PHP version. This realisation was a very big help in preparing our codebases for the migration to PHP 8:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; composer why-not php:8.0.0
paragonie/random_compat  v9.99.99  requires  php &lt;span class="o"&gt;(&lt;/span&gt;^7&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Automation
&lt;/h2&gt;

&lt;p&gt;I've used different approaches trying to keep dependencies up-to-date. For a while I blocked an afternoon every month to update outdated dependencies. This works great as long as you have a limited number of codebases and dependencies to keep up-to-date. As these grow a few hours every month is no longer enough. Luckily this can be automated to a certain point. &lt;/p&gt;

&lt;p&gt;The most known tool for this is &lt;a href="https://dependabot.com/"&gt;Dependabot&lt;/a&gt;. Dependabot integrates seemlessly into Github and is able to create pull requests for outdated dependencies. If you have set up automated tests on your codebase all you have to do is merge the pull request created by Dependabot. It does not get any easier.&lt;/p&gt;

&lt;p&gt;If you're not using Github or you don't want to use Dependabot, there's also the possibility to build something yourself. &lt;code&gt;composer oudated&lt;/code&gt; can be "configured" to help you with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer outdated &lt;span class="nt"&gt;--format&lt;/span&gt; json &lt;span class="nt"&gt;--strict&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flag &lt;code&gt;--strict&lt;/code&gt; will make that the Composer executable will return a non-zero status code if any dependency is outdated, where &lt;code&gt;--format json&lt;/code&gt; switches the output from text to json. The latter is much easier to parse. With the output of this call you can create a pull request, an issue or an alert to whatever communication channel you prefer. All you need to do is run this periodically.&lt;/p&gt;

&lt;h2&gt;
  
  
  tl/dr;
&lt;/h2&gt;

&lt;p&gt;There are multiple reasons why it's a good idea to keep your dependencies as up-to-date as possible, ranging from preventing vulnerabilities to making future migrations easier. Composer is well equipped to detect outdated dependencies and to update them without you needing to open an editor to change &lt;code&gt;composer.json&lt;/code&gt;. If you want to update to a version supported by the constraints you can use &lt;code&gt;composer update&lt;/code&gt;. If you need - or want - to update the constraints as well you can use &lt;code&gt;composer require&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If Composer gives you an error trying to update a dependency you can find the culprit by running &lt;code&gt;composer why-not&lt;/code&gt;. A good way pf preventing blocking dependencies is to use either &lt;code&gt;-w&lt;/code&gt; or &lt;code&gt;-W&lt;/code&gt; when running &lt;code&gt;composer update&lt;/code&gt; or &lt;code&gt;composer require&lt;/code&gt;.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;See &lt;a href="https://semver.org/"&gt;Semantic Versioning&lt;/a&gt; for the difference between minor and major versions. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Direct dependencies are dependencies that are specified in the &lt;code&gt;composer.json&lt;/code&gt; of your project ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Officially these commands are called &lt;code&gt;depends&lt;/code&gt; and &lt;code&gt;prohibits&lt;/code&gt;, but I have a personal preference for using &lt;code&gt;why&lt;/code&gt; and &lt;code&gt;why-not&lt;/code&gt; as it almost makes your command into a grammatically correct sentences. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>php</category>
      <category>composer</category>
    </item>
    <item>
      <title>Using Swagger UI in AWS' serverless stack</title>
      <dc:creator>Timo Schinkel</dc:creator>
      <pubDate>Tue, 08 Jun 2021 09:47:29 +0000</pubDate>
      <link>https://forem.com/coolblue/using-swagger-ui-in-aws-serverless-stack-4hi5</link>
      <guid>https://forem.com/coolblue/using-swagger-ui-in-aws-serverless-stack-4hi5</guid>
      <description>&lt;p&gt;Few things are as frustrating as working with an API that is not properly documented. That is why we aim to equip our applications with &lt;a href="https://swagger.io/resources/open-api/"&gt;Swagger / OpenAPI documentation&lt;/a&gt;. This exposes the url &lt;code&gt;/swagger&lt;/code&gt; where a nice documentation for the API is available. At the same time have we been using more and more serverless technologies, which in our situation means &lt;a href="https://aws.amazon.com/lambda/"&gt;AWS Lambda&lt;/a&gt;. In order to use an AWS Lambda function as an HTTP API the function needs to be triggered by a route defined in &lt;a href="https://aws.amazon.com/api-gateway/"&gt;AWS API Gateway&lt;/a&gt;. I want to share the setup we use to quickly expose Swagger documentation for our serverless stacks. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt; The code examples use NodeJS and &lt;a href="https://aws.amazon.com/cloudformation/"&gt;Cloudformation&lt;/a&gt; as those are the tools we currently use at Coolblue. This trick is not very complex, so it should be easily translated to other languages. &lt;/p&gt;

&lt;h2&gt;
  
  
  Swagger. Or OpenAPI?
&lt;/h2&gt;

&lt;p&gt;OpenAPI is a specification that is used to describe an API. It is the de facto industry standard for describing REST APIs and as such there is a lot of tooling available to generate or interpret OpenAPI specifications.&lt;/p&gt;

&lt;p&gt;For clarification: the terms OpenAPI and Swagger are both used. As &lt;a href="https://swagger.io/blog/api-strategy/difference-between-swagger-and-openapi/"&gt;the OpenAPI Initiative explains themselves&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The easiest way to understand the difference is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAPI = Specification&lt;/li&gt;
&lt;li&gt;Swagger = Tools for implementing the specification&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order to serve a nice documentation we need three things; an OpenAPI specification of the API, a way to generate html from that specification and a way to serve the generated html. &lt;/p&gt;

&lt;p&gt;Creating an OpenAPI specification is outside the scope of this text - although that might be an interesting topic for a followup. For this text I will assume you already have an OpenAPI specification. Either generated from code (annotations) or created by hand, maybe using the online &lt;a href="https://editor.swagger.io/"&gt;Swagger Editor&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exposing the generated documentation
&lt;/h2&gt;

&lt;p&gt;Given that you have an OpenAPI specification the next step is to convert this to html and expose it. There are a couple of ways to build up html based on an OpenAPI specification; The OpenAPI Initiative themselves offer two NPM packages to do this: &lt;a href="https://www.npmjs.com/package/swagger-ui"&gt;swagger-ui&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/swagger-ui-dist"&gt;swagger-ui-dist&lt;/a&gt;. Both these packages offer an example html and the required javascript and css resources. The benefit of using &lt;code&gt;swagger-ui-dist&lt;/code&gt; over &lt;code&gt;swagger-ui&lt;/code&gt; is that it is dependency free and ready to use.&lt;/p&gt;

&lt;p&gt;Using a serverless architecture has a downside; For every url we need to create an endpoint. We can either create a function and an endpoint for every resource or work with some form of wildcards. The first means additional work, where the latter introduces some additional complexity. Both result in Lambda invocations for static content. &lt;/p&gt;

&lt;p&gt;Another option that is actually suggested on the &lt;a href="https://swagger.io/docs/open-source-tools/swagger-ui/usage/installation/"&gt;installation instructions&lt;/a&gt; of &lt;code&gt;swagger-ui&lt;/code&gt; is to use a CDN. There are multiple CDNs that offer these files, like &lt;a href="https://www.jsdelivr.com/package/npm/swagger-ui-dist"&gt;jsdelivr&lt;/a&gt; and &lt;a href="https://cdnjs.com/libraries/swagger-ui"&gt;cdnjs&lt;/a&gt;. I'll be using &lt;a href="https://unpkg.com/"&gt;unpkg&lt;/a&gt; in these examples, just like in the installation instructions. &lt;/p&gt;

&lt;p&gt;In the scenario where you don't want to use an external CDN you can also expose these files through your own CDN solution, for example an S3 bucket. This approach has an additional bonus as you will be able to keep all of your Swagger documentations running on the same version of &lt;code&gt;swagger-ui&lt;/code&gt; and you might be able to host additional CSS files to apply some house styles to your Swagger documentations. &lt;/p&gt;

&lt;h3&gt;
  
  
  Cloudformation
&lt;/h3&gt;

&lt;p&gt;I'll be following the convention to offer the documentation on the &lt;code&gt;/swagger&lt;/code&gt; url:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type &lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;String"&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;development"&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Environment&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;which&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;resources&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;are&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;deployed."&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Lambdas&lt;/span&gt;
  &lt;span class="na"&gt;SwaggerFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Function&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;swagger.swagger&lt;/span&gt;
      &lt;span class="na"&gt;FunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${AWS::StackName}-swagger"&lt;/span&gt;
      &lt;span class="na"&gt;CodeUri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="na"&gt;Events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;GetHtml&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Api&lt;/span&gt;
          &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/swagger&lt;/span&gt;
            &lt;span class="na"&gt;Method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
            &lt;span class="na"&gt;RestApiId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ServerlessApi"&lt;/span&gt;
        &lt;span class="na"&gt;GetSpec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Api&lt;/span&gt;
          &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/swagger.json&lt;/span&gt;
            &lt;span class="na"&gt;Method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
            &lt;span class="na"&gt;RestApiId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ServerlessApi"&lt;/span&gt;

  &lt;span class="c1"&gt;# Api gateway&lt;/span&gt;
  &lt;span class="na"&gt;ServerlessApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::Serverless::Api"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;StageName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Environment"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm applying a little trick here; It is possible to add multiple events to the same &lt;code&gt;AWS::Serverless::Function&lt;/code&gt; resource. The reason I am also routing &lt;code&gt;/swagger.json&lt;/code&gt; to the Lambda function is to enable consumers to download the specification. This specification can be used to autogenerate client code for consuming the API. &lt;/p&gt;

&lt;h3&gt;
  
  
  Javascript
&lt;/h3&gt;

&lt;p&gt;Now that Cloudformation end of things is set up we need to actually generate the documentation, which is where &lt;code&gt;swagger-ui&lt;/code&gt; comes in play:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFileSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;applicationName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Awesome Application&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;swagger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/swagger.json&lt;/span&gt;&lt;span class="dl"&gt;'&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="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./etc/swagger.json&lt;/span&gt;&lt;span class="dl"&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;!DOCTYPE html&amp;gt;
        &amp;lt;html lang="en"&amp;gt;
        &amp;lt;head&amp;gt;
            &amp;lt;meta charset="UTF-8"&amp;gt;
            &amp;lt;title&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;applicationName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/title&amp;gt;
            &amp;lt;link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@3/swagger-ui.css"&amp;gt;
        &amp;lt;/head&amp;gt;
        &amp;lt;body&amp;gt;
            &amp;lt;div id="swagger"&amp;gt;&amp;lt;/div&amp;gt;
            &amp;lt;script src="https://unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"&amp;gt;&amp;lt;/script&amp;gt;
            &amp;lt;script&amp;gt;
              SwaggerUIBundle({
                dom_id: '#swagger',
                url: '/swagger.json'
            });
            &amp;lt;/script&amp;gt;
        &amp;lt;/body&amp;gt;
        &amp;lt;/html&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nx"&gt;body&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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Writing documentation is just as much part of the development process as writing code. OpenAPI offers a standardized way of describing an API and &lt;code&gt;swagger-ui&lt;/code&gt; offers an off-the-shelf solution that can generate a very readable documentation. Exposing Swagger documentation on a standardized url - &lt;code&gt;/swagger&lt;/code&gt; - adds a consistent way for any consumers of the API to know what endpoints the API exposes and how these endpoints can be exposed. With just a handful lines of code it is possible to expose Swagger documentation for your serverless stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continue reading
&lt;/h2&gt;

&lt;p&gt;There are a lot of great resources about OpenAPI. I want to point out a couple of resources that have been very helpful to me while working with OpenAPI.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://petstore.swagger.io/"&gt;Swagger Petstore&lt;/a&gt; - A demo and showcase of all the features offered by OpenAPI and Swagger. A great resource if you prefer to read example code over reading the documentation of the OpenAPI specification.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://swagger.io/specification/"&gt;OpenAPI specification&lt;/a&gt; - An extensive documentation of all properties and their allowed values for the OpenAPI specification.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>openapi</category>
      <category>node</category>
    </item>
    <item>
      <title>Testing with immutable PSR-7 objects and Prophecy</title>
      <dc:creator>Timo Schinkel</dc:creator>
      <pubDate>Thu, 04 Mar 2021 16:32:46 +0000</pubDate>
      <link>https://forem.com/timoschinkel/testing-with-immutable-psr-7-objects-and-prophecy-3590</link>
      <guid>https://forem.com/timoschinkel/testing-with-immutable-psr-7-objects-and-prophecy-3590</guid>
      <description>&lt;p&gt;Recently I have been working a lot with &lt;a href="https://www.php-fig.org/psr/psr-15/"&gt;PSR-15&lt;/a&gt; and &lt;a href="https://www.php-fig.org/psr/psr-18/"&gt;PSR-18&lt;/a&gt; and one of the characteristics of these recommendations is that it uses the &lt;a href="https://en.wikipedia.org/wiki/Immutable_object"&gt;immutable objects&lt;/a&gt; specified in &lt;a href="https://www.php-fig.org/psr/psr-7/"&gt;PSR-7&lt;/a&gt;. Soon after we introduced PSR-18 in our codebase a colleague implemented a client including a unit test that was passing. And yet the code was failing when run in the browser. The cause of this was that the fact that &lt;code&gt;RequestInterface&lt;/code&gt; objects are immutable by specification was overlooked. Due to the use of &lt;a href="https://github.com/phpspec/prophecy"&gt;Prophecy&lt;/a&gt; and prophesized objects we were struggling to properly test it. Until another colleague introduced me to &lt;code&gt;Argument::that()&lt;/code&gt; that is.&lt;/p&gt;

&lt;p&gt;Let's consider the following class as a simplified example of the situation described above:&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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&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\Client\ClientInterface&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="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApiKeyMiddleware&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;MiddlewareInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/** @var string */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$apiKey&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="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$apiKey&lt;/span&gt;&lt;span class="p"&gt;)&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="n"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$apiKey&lt;/span&gt;&lt;span class="p"&gt;;&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;process&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;ClientInterface&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;ResponseInterface&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;withHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Api-Key'&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="n"&gt;apiKey&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;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sendRequest&lt;/span&gt;&lt;span class="p"&gt;(&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an example of a &lt;a href="https://medium.com/@timoschinkel/implementing-psr-18-and-extending-it-with-middleware-b33eeceb2753"&gt;PSR-18 middleware&lt;/a&gt; we created and introduced into our codebase shortly after the approval of PSR-18&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. Seems correct at first glance. Now let's have a look at a simple unit test to test the happy path using Prophecy:&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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&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;PHPUnit\Framework\TestCase&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;Prophecy\Argument&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\Client\ClientInterface&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="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApiKeyMiddlewareTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&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;testApiKeyIsAddedAndResponseIsReturned&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'api key'&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="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClientInterface&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="nv"&gt;$client&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sendRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Argument&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RequestInterface&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;shouldBeCalled&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;willReturn&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;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResponseInterface&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;reveal&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;=&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;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RequestInterface&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="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;'Api-Key'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$apiKey&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;shouldBeCalled&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;willReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$middleware&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;ApiKeyMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$apiKey&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;=&lt;/span&gt; &lt;span class="nv"&gt;$middleware&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;process&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;reveal&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;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;reveal&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertInstanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResponseInterface&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="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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance the code and the unit test look good. But while the test will pass, the code does not actually do what it should; when running this code the remote server will most likely respond with a &lt;code&gt;403 Forbidden&lt;/code&gt; response, because we are &lt;strong&gt;not&lt;/strong&gt; sending the &lt;code&gt;Api-Key&lt;/code&gt; header with the request. This is caused by the immutability of the &lt;code&gt;\Psr\Http\Message\RequestInterface&lt;/code&gt;. The header &lt;strong&gt;is&lt;/strong&gt; being set, but this operation returns a new instance of the request. Unfortunately the new object is not assigned to anything and therefore the request object &lt;em&gt;without&lt;/em&gt; the header is passed to the actual client. We have found the culprit and the fix is simple, but how can we make sure this will not happen again in the future?&lt;/p&gt;

&lt;h2&gt;
  
  
  Prophecies, Prophecies everywhere
&lt;/h2&gt;

&lt;p&gt;The first approach one can take is to make sure every operation return a new prophesized object:&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;testApiKeyIsAddedAndResponseIsReturned&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'api key'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;$requestWithApiKey&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="nf"&gt;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RequestInterface&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;reveal&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;=&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;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RequestInterface&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="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;'X-Api-Key'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$apiKey&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;shouldBeCalled&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;willReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$requestWithApiKey&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="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClientInterface&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="nv"&gt;$client&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sendRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Argument&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$requestWithApiKey&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;shouldBeCalled&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;willReturn&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;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResponseInterface&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;reveal&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="nv"&gt;$middleware&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;ApiKeyMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$apiKey&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;=&lt;/span&gt; &lt;span class="nv"&gt;$middleware&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;process&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;reveal&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;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;reveal&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertInstanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResponseInterface&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="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;This test will fail, as it should. But now consider a situation where not just &lt;em&gt;one operation&lt;/em&gt; is done, but multiple. Maybe a header is set, another is modified. Or - shifting away from PSR-7 objects - look at other immutable objects that might have multiple operations. The amount of prophesized objects would grow and every time the order in which the object methods are called changes the unit tests have to be changed. Every call to the immutable object adds three methods on the prophesized object and &lt;a href="https://gist.github.com/timoschinkel/29962f13331dc0bec77d62a7ebd3ee22"&gt;decreases readibility&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Value object do not need prophesizing
&lt;/h2&gt;

&lt;p&gt;The objects for the example are not just immutable objects, but can also be seen as &lt;a href="https://martinfowler.com/bliki/ValueObject.html"&gt;value objects&lt;/a&gt;&lt;sup id="fnref2"&gt;2&lt;/sup&gt;. And there is some &lt;a href="https://stackoverflow.com/questions/47304193/don-t-mock-value-objects-too-generic-rule-without-explanation"&gt;discussion&lt;/a&gt; whether one would even mock value objects. Maybe instantiating these objects &lt;em&gt;is&lt;/em&gt; a solution. In that case the order in which the object is modified is irrelevant and our test will focus more on what comes out, than on the order methods are called.&lt;/p&gt;

&lt;p&gt;This works great if a method is tested that modifies and returns an object; we'll get an instance of that object and we are able to run all sorts of assertions on it. But what if this is not the case. What if we have a situation where a value object is passed as a parameter, some modifications are done and the value object is passed to another object. Something like the middleware from the example earlier. Some testing frameworks like &lt;a href="https://github.com/mockery/mockery"&gt;Mockery&lt;/a&gt; offer spies to test these situations. When using Prophecy this situation can be handled using &lt;code&gt;Argument::that()&lt;/code&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testApiKeyIsAddedAndResponseIsReturned&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'api key'&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;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/url'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'GET'&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="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClientInterface&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="nv"&gt;$client&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sendRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;Argument&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;that&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="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$apiKey&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&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;getHeaderLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'X-Api-Key'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nv"&gt;$apiKey&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;shouldBeCalled&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;willReturn&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;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResponseInterface&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;reveal&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="nv"&gt;$middleware&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;ApiKeyMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$apiKey&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;=&lt;/span&gt; &lt;span class="nv"&gt;$middleware&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&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;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;reveal&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertInstanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResponseInterface&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="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;Instead of testing against mocked value objects this code check if &lt;code&gt;sendRequest()&lt;/code&gt; is called with an instance of &lt;code&gt;RequestInterface&lt;/code&gt; that has the expected value for the &lt;code&gt;X-Api-Key&lt;/code&gt; header. The nice thing about this is that we are no longer testing whether the code makes a certain set of calls in a given order. We are actually testing whether an object is in the correct state when passed.&lt;/p&gt;

&lt;h2&gt;
  
  
  PSR-7 - a special case
&lt;/h2&gt;

&lt;p&gt;This unit test will fail when ran against the implementation from earlier. And in this situation a failing test is a good thing. But for this specific situation another "issue" has made it's way into the testcase; the unit test is now depending on the implementation that is being used for PSR-7. When working in a large codebase - like I currently am - one might have more than just a few usages of these interfaces and thus unit tests. Using the suggested approach, instantiating value objects instead of prophesizing, will lead to a large amount of object instantiations. And this will make switching to another implementation more work. Ideally this instantiating is centralized as much as possible. This is exactly why &lt;a href="https://www.php-fig.org/psr/psr-17/"&gt;PSR-17&lt;/a&gt; - HTTP Factories - was introduced. Typically dependencies - like these factories - are injected. For unit tests this is not feasible without &lt;a href="https://github.com/jakzal/phpunit-injector"&gt;plugins&lt;/a&gt;. My solution is a bit less fancy; a trait:&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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&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="kd"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;Psr7Factories&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;createRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;RequestInterface&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RequestFactory&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;createRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$uri&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;This can be applied in the unit test:&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="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&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;PHPUnit\Framework\TestCase&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;Prophecy\Argument&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\Client\ClientInterface&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="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApiKeyMiddlewareTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&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;Psr7Factories&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;testApiKeyIsAddedAndResponseIsReturned&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'api key'&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;=&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;createRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GET'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/url'&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="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClientInterface&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="nv"&gt;$client&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sendRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nc"&gt;Argument&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;that&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="k"&gt;use&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$apiKey&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&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;getHeaderLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'X-Api-Key'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;$apiKey&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="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;shouldBeCalled&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;willReturn&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;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResponseInterface&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;reveal&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

        &lt;span class="nv"&gt;$middleware&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;ApiKeyMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$apiKey&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;=&lt;/span&gt; &lt;span class="nv"&gt;$middleware&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&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;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;reveal&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertInstanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResponseInterface&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="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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When testing a class that creates the PSR-7 objects via a PSR-17 factory this approach can also be used:&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;$requestFactory&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="nf"&gt;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RequestFactoryInterface&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="nv"&gt;$requestFactory&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GET'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/url'&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;shouldBeCalled&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;willReturn&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;createRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GET'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/url'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  More usages
&lt;/h2&gt;

&lt;p&gt;In the examples up until now instances of &lt;code&gt;\Psr\Http\Message\RequestInterface&lt;/code&gt; have been created. But this approach can also be used for instances of &lt;code&gt;Psr\Http\Message\ResponseInterface&lt;/code&gt; or other PSR-7 objects, simply by adding the methods you want to use to the trait. We have opted to follow the PSR-17 method signatures for consistency. This will make it easy to inject different response fixtures to test how the code responds to them:&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;$client&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="nf"&gt;prophesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClientInterface&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="nv"&gt;$client&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sendRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Argument&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RequestInterface&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="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;willReturn&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;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&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;withBody&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;createStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'path/to/response/fixture.json'&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;And when testing controllers or request handlers it allows for constructing instances of &lt;code&gt;ServerRequestInterface&lt;/code&gt; in a more readable way than prophesizing the object:&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;$request&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="nf"&gt;createServerRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GET'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/uri'&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;withAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'attribute'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'value'&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;withHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'content-type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'application/json'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Working with immutable objects is tricky; forget one assignment and your code stops behaving the way you expect it should. By testing for this the right way the resilience of a codebase is improved. Using Prophecy and prophesized objects does not immediately remedy this. &lt;/p&gt;

&lt;p&gt;When opting to not mock value objects, but rather use them as is in the unit test &lt;code&gt;Argument::that()&lt;/code&gt; can act as a spy allowing for more specific assertions on the value objects. This will also allow assertions to determine the immutability of the object has been satisfied.&lt;/p&gt;

&lt;p&gt;The PSR-7 objects are a special case; you could consider them as value objects, but they are also interfaced. Using instances of these objects instead of mocks or prophecies allows for these same immutability asserts. In order to prevent a lot of object instantiations of these objects in unit tests one can use the PSR-17 factories. But since the unit tests don't normally allow for dependency injection an alternative way of centralizing this object instantiation is by creating a trait that handles this. &lt;/p&gt;

&lt;p&gt;With the described approach we have managed to reduce the references to the PSR-17 implementation we used to two locations; the dependency injection container and one trait. If for whatever reason a decision is made to move away from the current PSR-7 or PSR-17 implementation this should be a relative small task.&lt;/p&gt;

&lt;p&gt;This approach can also be used for packages. The nice thing of the PHP-FIG HTTP foundation is that you can create packages relying just on interfaces. But you also want to test your code. By adding an implementation of PSR-7 as a development dependency consumers of the package won't notice this dependency. Only maintainers and contributors will need to notice.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Middleware is &lt;em&gt;not&lt;/em&gt; part of the PSR-18 specification. It is a layer on top of PSR-18 that we built ourselves. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;According to Martin Fowler are value objects comparable to eachother based on the values. Since the PSR-7 objects are interfaced there is no documentation on how the object values should be represented internally, but there is a standardized format to represent HTTP requests as strings. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>php</category>
      <category>psr7</category>
      <category>testing</category>
      <category>prophecy</category>
    </item>
    <item>
      <title>Private serverless APIs in AWS</title>
      <dc:creator>Timo Schinkel</dc:creator>
      <pubDate>Wed, 17 Feb 2021 14:29:39 +0000</pubDate>
      <link>https://forem.com/coolblue/private-serverless-apis-in-aws-22d5</link>
      <guid>https://forem.com/coolblue/private-serverless-apis-in-aws-22d5</guid>
      <description>&lt;p&gt;Our application landscaping is growing to more interfacing applications; A website, mobile apps and customer service tooling just to give a few examples. We've been using the &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html"&gt;AWS Serverless Application Model&lt;/a&gt; to quickly create stacks that are consumable by multiple applications. One downside of using AWS SAM is that the API Gateway endpoints are public by default. We protect these endpoints against abuse via an authentication, but for some endpoints we would like to have an additional layer of protected by making these endpoints only available from inside our &lt;a href="https://aws.amazon.com/vpc/"&gt;VPC&lt;/a&gt;. In other words make our endpoints private.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt; This article specifically outlines making an &lt;em&gt;AWS Serverless Application Model&lt;/em&gt; stack private. A serverless infrastructure has a great amount of similarities with &lt;code&gt;AWS::ApiGateway::RestApi&lt;/code&gt;, but is still subtly different. I like to look at it as a simplification of &lt;code&gt;AWS::ApiGateway::RestApi&lt;/code&gt; and &lt;code&gt;AWS::Lambda::Function&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A serverless stack
&lt;/h2&gt;

&lt;p&gt;A typical serverless stack consists of two parts: an &lt;a href="https://aws.amazon.com/lambda/"&gt;AWS Lambda&lt;/a&gt; function and a trigger. This trigger can be anything from an upload on an S3 bucket, a message being pushed on a SQS or a call to an HTTP endpoint. In this last scenario the endpoint is defined as an &lt;a href="https://aws.amazon.com/api-gateway/"&gt;API Gateway&lt;/a&gt; resource.&lt;/p&gt;

&lt;p&gt;We use &lt;a href="https://aws.amazon.com/cloudformation/"&gt;Cloudformation&lt;/a&gt; to define our stacks. Let's consider a minimal function that allows retrieval of entities of the type &lt;code&gt;entity&lt;/code&gt; via the call &lt;code&gt;GET /entities&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type &lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;String"&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;development"&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Environment&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;which&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;resources&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;are&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;deployed."&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Lambdas&lt;/span&gt;
  &lt;span class="na"&gt;GetEntitiesFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Function&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.getEntities&lt;/span&gt;
      &lt;span class="na"&gt;FunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${AWS::StackName}-get-entities"&lt;/span&gt;
      &lt;span class="na"&gt;CodeUri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"&lt;/span&gt;
      &lt;span class="na"&gt;Events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;GetResource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Api&lt;/span&gt;
          &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/entities&lt;/span&gt;
            &lt;span class="na"&gt;Method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
            &lt;span class="na"&gt;RestApiId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ServerlessApi"&lt;/span&gt;

  &lt;span class="c1"&gt;# Api gateway&lt;/span&gt;
  &lt;span class="na"&gt;ServerlessApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::Serverless::Api"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;StageName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Environment"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When deployed this should result in a serverless stack with a single endpoint that is publicly available for everyone that knows the url. &lt;/p&gt;

&lt;h2&gt;
  
  
  VPC endpoint
&lt;/h2&gt;

&lt;p&gt;Making an API Gateway private requires a VPC. Every stack that requires access to the private API must be part of the VPC. Benefit of having a VPC is that access control is centralized in the VPC configuration. &lt;/p&gt;

&lt;p&gt;In order to make the API private the traffic will have to pass through the VPC. This is done via a VPC endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;APIGatewayVpcEndpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::EC2::VPCEndpoint"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;SubnetIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!ImportValue&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exported-subnet-id"&lt;/span&gt;
      &lt;span class="na"&gt;SecurityGroupIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resource&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;AWS::EC2::SecurityGroup"&lt;/span&gt;
      &lt;span class="na"&gt;ServiceName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;com.amazonaws.eu-west-1.execute-api"&lt;/span&gt;
      &lt;span class="na"&gt;VpcId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!ImportValue&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exported-vpc-id"&lt;/span&gt;
      &lt;span class="na"&gt;VpcEndpointType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Interface"&lt;/span&gt;
      &lt;span class="na"&gt;PrivateDnsEnabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disabling the private DNS is a deliberate choice. The reason for that is explained later in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Marking an API private
&lt;/h2&gt;

&lt;p&gt;By default API Gateway resources are publicly available. In 2018 &lt;a href="https://aws.amazon.com/blogs/compute/introducing-amazon-api-gateway-private-endpoints/"&gt;AWS introduced the possibility to mark API Gateway resources as private&lt;/a&gt;. Marking an API Gateway as private is easily done in the Cloudformation definition of our stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;

  &lt;span class="c1"&gt;# Api gateway&lt;/span&gt;
  &lt;span class="na"&gt;ServerlessApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::Serverless::Api"&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;StageName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Environment"&lt;/span&gt;
      &lt;span class="na"&gt;EndpointConfiguration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PRIVATE"&lt;/span&gt;
        &lt;span class="na"&gt;VPCEndpointIds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!ImportValue&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;infrastructure-api-gateway-vpc-endpoint"&lt;/span&gt;
      &lt;span class="na"&gt;Auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;ResourcePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;IntrinsicVpceWhitelist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!ImportValue&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;infrastructure-api-gateway-vpc-endpoint"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt; This example imports a VPC endpoint. We try to separate stacks as much as possible for ownership and maintainability. In a separate &lt;em&gt;infrastructure&lt;/em&gt; stack the VPC endpoint(s) are defined and the required identifiers are exported from those stacks. That way every other stack can use them while the hosting team still has the possibility to make changes to the endpoint. &lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html#sam-api-endpointconfiguration"&gt;&lt;code&gt;EndpointConfiguration&lt;/code&gt;&lt;/a&gt; tells AWS that the API should no longer be publicly available. A required property of &lt;code&gt;EndPointConfiguration&lt;/code&gt; is a list of VPC endpoints.&lt;/p&gt;

&lt;p&gt;Next to marking the API private we also need to tell the API it is allowed to be called from the endpoint. This is done via a resource policy. In a &lt;code&gt;AWS::Serverless::Api&lt;/code&gt; this is done via the &lt;code&gt;Auth&lt;/code&gt; property. &lt;/p&gt;

&lt;p&gt;When we now deploy this stack, the API will no longer be publicly available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consuming the private API
&lt;/h2&gt;

&lt;p&gt;The downside of making an API Gateway resource is that consuming becomes a little bit more complicated. There are two methods that work out-of-the-box. Those methods use the VPC endpoint as entry for the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -v https://{public-dns-hostname}.execute-api.{region}.vpce.amazonaws.com/{stage}/{path}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;{public-dns-hostname}&lt;/code&gt; of the VPC endpoint is visible in the AWS Console. For the following examples I will call the &lt;code&gt;/entities&lt;/code&gt; endpoint defined in the Cloudformation for region &lt;code&gt;eu-west-1&lt;/code&gt; and stage &lt;code&gt;testing&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first method uses the &lt;code&gt;Host&lt;/code&gt; header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -v https://vpce-01234567abcdef012-01234567.execute-api.eu-west-1.vpce.amazonaws.com/testing/entities \
-H 'Host: 01234567ab.execute-api.eu-west-1.amazonaws.com'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second method uses the &lt;code&gt;x-apigw-api-id&lt;/code&gt; header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -v https://vpce-01234567abcdef012-01234567.execute-api.eu-west-1.vpce.amazonaws.com/testing/entities \
-H 'x-apigw-api-id: 01234567ab'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both the host and the API id can be found in the AWS Console after deploying your stack.&lt;/p&gt;

&lt;p&gt;There are other options to call your private endpoints that a bit more user-friendly, but that have their own caveats. You can enable the "Private DNS Name" while creating an interface VPC endpoint for API Gateway, but this also means that the VPC where the VPC endpoint is present will no longer be able to access public APIs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When you select the Enable Private DNS Name option while creating an interface VPC endpoint for API Gateway, the VPC where the VPC Endpoint is present won't be able to access public (edge-optimized and regional) APIs. For more information, see &lt;a href="https://aws.amazon.com/premiumsupport/knowledge-center/api-gateway-vpc-connections/"&gt;Why can't I connect to my public API from an API Gateway VPC endpoint?&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Source: &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-api-test-invoke-url.html#w7aac17b9c33c26c11"&gt;Invoking your private API using private DNS names&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we have both public and private APIs and we also consume public APIs from within our VPC we are not able to use this approach.&lt;/p&gt;

&lt;p&gt;Another option is to use a &lt;code&gt;Route53&lt;/code&gt; alias. We have not yet tried this, so I cannot make any comments on this option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The SAM model offered by AWS allows for fast development of applications as you don't have to worry too much about your infrastructure choices. AWS will scale if needed. Building a modest sized API can be achieved using the tandem Lambda and API Gateway, but this will result in a public endpoint by default.&lt;/p&gt;

&lt;p&gt;If you want to utilize the benefits of the SAM model, but you don't want to expose your API to the public you can make your API private. This will increase security on your endpoint, but it will also introduce some downsides like the necessity to have a VPC and a VPC endpoint. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Mocking third party classes in TypeScript</title>
      <dc:creator>Timo Schinkel</dc:creator>
      <pubDate>Mon, 19 Oct 2020 06:54:11 +0000</pubDate>
      <link>https://forem.com/coolblue/mocking-third-party-classes-in-typescript-4o38</link>
      <guid>https://forem.com/coolblue/mocking-third-party-classes-in-typescript-4o38</guid>
      <description>&lt;p&gt;&lt;a href="https://www.typescriptlang.org"&gt;TypeScript&lt;/a&gt; is becoming increasingly popular as a replacement for plain JavaScript; the strict type checking should result in more resilient code. Initiatives like &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped"&gt;Definitely Typed&lt;/a&gt; make that the majority of often used &lt;a href="https://www.typescriptlang.org"&gt;NPM packages&lt;/a&gt; have type definitions. This is great when writing code, but can become a nuisance when writing tests. Especially when &lt;a href="https://en.wikipedia.org/wiki/Mock_object"&gt;mocking&lt;/a&gt; these sometimes large third party classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mocking with type definitions
&lt;/h2&gt;

&lt;p&gt;Let's consider the following code that takes a payload and stores it on an AWS S3 bucket using the &lt;a href="https://www.npmjs.com/package/aws-sdk"&gt;AWS SDK&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;S3&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyS3Repository&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;MyRepositoryInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyEntity&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;putObject&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
            &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIdentifier&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PutObjectOutput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;strong&gt;NB&lt;/strong&gt; This is a simplified example, but it will work as an example.&lt;/p&gt;

&lt;p&gt;After creating an implementation the next logical step is to create a unit test for this class. We don't want to actually make a connection with an S3 bucket every time we run our test suite. One way to prevent this is to &lt;em&gt;mock&lt;/em&gt; the S3 object that is injected into the repository. Coming from JavaScript &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt; is my go-to tool to write tests and that means &lt;code&gt;jest.fn()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyS3Repository&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;store()&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should store on S3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;putObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;mockReturnValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                    &lt;span class="na"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;mockResolvedValue&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;repository&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;MyS3Repository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entity&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;MyEntity&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;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;resolves&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&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;When working with "plain" JavaScript this would work as expected, and the unit test would pass. But when using TypeScript you will encounter an error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Argument of type '{ putObject: jest.Mock; }' is not assignable to parameter of type 'S3'.&lt;br&gt;
    Type '{ getObject: Mock; putObject: Mock; }' is missing the following properties from type 'S3': config, abortMultipartUpload, completeMultipartUpload, copyObject, and 98 more.ts(2345)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What happens here is that TypeScript is detecting that the object that should impersonate the &lt;code&gt;S3&lt;/code&gt; object is missing 98 methods. A trade off needs to be made here; do I use an existing package and try to work with it or do I write the necessary code myself. When not working on personal projects the scale typically tilts towards the first. So let's see if we can make this work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pick me!
&lt;/h2&gt;

&lt;p&gt;A number of solutions for this problem are described like using the &lt;a href="https://medium.com/@davguij/mocking-typescript-classes-with-jest-8ef992170d1d"&gt;&lt;code&gt;__mocks__&lt;/code&gt;&lt;/a&gt; functionality, &lt;a href="https://www.jonathancreamer.com/testing-typescript-classes-with-jest-and-jest-mocks/"&gt;introducing interfaces&lt;/a&gt; and using &lt;a href="https://dev.to/codedivoire/how-to-mock-an-imported-typescript-class-with-jest-2g7j"&gt;&lt;code&gt;jest.mock()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For multiple reasons none of these really worked well for me. As I don't have control over the code introducing an interface is not possible. &lt;code&gt;jest.mock()&lt;/code&gt; seems to only work on modules that have a default export and &lt;code&gt;__mocks__&lt;/code&gt; still requires mocking the entire signature of a class.&lt;/p&gt;

&lt;p&gt;Another option is to use additional tooling like &lt;a href="https://github.com/florinn/typemoq"&gt;&lt;code&gt;typemoq&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://github.com/NagRock/ts-mockito"&gt;&lt;code&gt;ts-mockito&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://www.npmjs.com/package/@fluffy-spoon/substitute"&gt;&lt;code&gt;substitute&lt;/code&gt;&lt;/a&gt;. But I am a bit reluctant to add a full-fledged mocking library if it is not completely necessary.&lt;/p&gt;

&lt;p&gt;Here I find myself with a very useful object with 99 methods and I only use one. Enter the &lt;a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys"&gt;&lt;code&gt;Pick&amp;lt;Type, Keys&amp;gt;&lt;/code&gt; utility&lt;/a&gt;! &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Constructs a type by picking the set of properties &lt;code&gt;Keys&lt;/code&gt; from &lt;code&gt;Type&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It allows us to tell TypeScript that even if we have an object with 99 methods we only really care about a small subset of those methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;S3&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyS3Repository&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;MyRepositoryInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Pick&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;putObject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Pick&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;putObject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucketName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bucketName&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;Result of this is that in our unit test we only have to mock &lt;code&gt;putObject()&lt;/code&gt; without TypeScript complaining about missing types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you find yourself with a large third party class that you want to mock you can resort to tooling like &lt;code&gt;typemoq&lt;/code&gt;, &lt;code&gt;ts-mockito&lt;/code&gt; or &lt;code&gt;substitute&lt;/code&gt;. Or you can leverage features offered by TypeScript. By using &lt;code&gt;Pick&lt;/code&gt; you are able to specify exactly what properties you need in your code. Doing that will make your mocking work a lot simpler.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>testing</category>
      <category>mocking</category>
    </item>
  </channel>
</rss>
