<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Evert Pot</title>
    <description>The latest articles on DEV Community by Evert Pot (@evert).</description>
    <link>https://dev.to/evert</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%2F90741%2F64e17d43-7a2e-41c4-ba05-ccc4514c14a0.jpg</url>
      <title>DEV Community: Evert Pot</title>
      <link>https://dev.to/evert</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/evert"/>
    <language>en</language>
    <item>
      <title>Discovering features via HTTP OPTIONS</title>
      <dc:creator>Evert Pot</dc:creator>
      <pubDate>Wed, 16 Oct 2024 13:44:00 +0000</pubDate>
      <link>https://dev.to/evert/discovering-features-and-information-via-http-options-2ged</link>
      <guid>https://dev.to/evert/discovering-features-and-information-via-http-options-2ged</guid>
      <description>&lt;p&gt;Say you have an API, and you want to communicate what sort of things a user can do on a specific endpoint. You can use external description formats like OpenAPI or JSON Schema, but sometimes it’s nice to also dynamically communicate this on the API itself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS" rel="noopener noreferrer"&gt;&lt;code&gt;OPTIONS&lt;/code&gt;&lt;/a&gt; is the method used for that. You may know this HTTP method from&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" rel="noopener noreferrer"&gt;CORS&lt;/a&gt;, but it’s general purpose is for clients to passively find out ‘What can I do here?’.&lt;/p&gt;

&lt;p&gt;All HTTP clients typically support making &lt;code&gt;OPTIONS&lt;/code&gt; request. For example with&lt;code&gt;fetch()&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;const response = await fetch(
  'https://example.org',
  {method: 'OPTIONS'}
);

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

&lt;/div&gt;



&lt;p&gt;A basic &lt;code&gt;OPTIONS&lt;/code&gt; response might might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 204 No Content
Date: Mon, 23 Sep 2024 02:57:38 GMT
Server: KKachel/1.2
Allow: GET, PUT, POST, DELETE, OPTIONS

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

&lt;/div&gt;



&lt;p&gt;Based on the &lt;a href="https://www.rfc-editor.org/rfc/rfc9110.html#field.allow" rel="noopener noreferrer"&gt;&lt;code&gt;Allow&lt;/code&gt;&lt;/a&gt; header you can quickly tell which HTTP methods are available at a given endpoint. Many web frameworks emit this automatically and generate the list of methods dynamically per route, so chances are that you get this one for free.&lt;/p&gt;

&lt;p&gt;To find out if your server does, try running the command below (with your URL!):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X OPTIONS http://localhost:3000/some/endpoint/

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

&lt;/div&gt;



&lt;p&gt;One nice thing you could do with the &lt;code&gt;Allow&lt;/code&gt; header, is that you could also communicate access-control information on a very basic level. For example, you could only include &lt;code&gt;DELETE&lt;/code&gt; and &lt;code&gt;PUT&lt;/code&gt; if a user has write access to a resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accept and Accept-Encoding
&lt;/h2&gt;

&lt;p&gt;There’s server other standard headers for discovery. Here’s an example showing a few at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 204 No Content
Date: Mon, 23 Sep 2024 02:57:38 GMT
Server: KKachel/1.2
Allow: GET, PUT, POST, DELETE, OPTIONS
Accept: application/vnd.my-company-api+json, application/json, text/html
Accept-Encoding: gzip,brotli,identity

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

&lt;/div&gt;



&lt;p&gt;You may already be familiar with &lt;a href="https://www.rfc-editor.org/rfc/rfc9110.html#name-accept" rel="noopener noreferrer"&gt;&lt;code&gt;Accept&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-encoding" rel="noopener noreferrer"&gt;&lt;code&gt;Accept-Encoding&lt;/code&gt;&lt;/a&gt; from HTTP requests, but they can also appear in responses. &lt;code&gt;Accept&lt;/code&gt; in a response lets you tell the client which kind of mimetypes are available at an endpoint. I like adding &lt;code&gt;text/html&lt;/code&gt; to every JSON api endpoint and making sure that API urls can be opened in browsers and shared between devs for easy debugging.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Accept-Encoding&lt;/code&gt; lets a client know in this case that they can compress their request bodies with either &lt;code&gt;gzip&lt;/code&gt; or &lt;code&gt;brotli&lt;/code&gt; (&lt;code&gt;identity&lt;/code&gt; means no compression).&lt;/p&gt;

&lt;h2&gt;
  
  
  Patching, posting and querying
&lt;/h2&gt;

&lt;p&gt;3 other headers that can be used are &lt;a href="https://www.rfc-editor.org/rfc/rfc5789#section-3.1" rel="noopener noreferrer"&gt;&lt;code&gt;Accept-Patch&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://www.w3.org/TR/ldp/#header-accept-post" rel="noopener noreferrer"&gt;&lt;code&gt;Accept-Post&lt;/code&gt;&lt;/a&gt;and &lt;a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-safe-method-w-body-05#name-the-accept-query-header-fie" rel="noopener noreferrer"&gt;&lt;code&gt;Accept-Query&lt;/code&gt;&lt;/a&gt;. These three headers are used to tell a client what content-types are available for the &lt;a href="https://www.rfc-editor.org/rfc/rfc5789#section-2" rel="noopener noreferrer"&gt;&lt;code&gt;PATCH&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://www.rfc-editor.org/rfc/rfc9110.html#name-post" rel="noopener noreferrer"&gt;&lt;code&gt;POST&lt;/code&gt;&lt;/a&gt; and&lt;a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-safe-method-w-body-05#name-query" rel="noopener noreferrer"&gt;&lt;code&gt;QUERY&lt;/code&gt;&lt;/a&gt; http methods respectively.&lt;/p&gt;

&lt;p&gt;For all of these headers, their values effectively dictate what valid values are for the &lt;code&gt;Content-Type&lt;/code&gt; header when making 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;HTTP/1.1 204 No Content
Date: Mon, 23 Sep 2024 02:57:38 GMT
Server: KKachel/1.2
Allow: OPTIONS, QUERY, POST, PATCH
Accept-Patch: application/json-patch+json, application/merge-patch+json
Accept-Query: application/graphql
Accept-Post: multipart/form-data, application/vnd.custom.rpc+json

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

&lt;/div&gt;



&lt;p&gt;In the above response, the server indicates it supports both &lt;a href="https://datatracker.ietf.org/doc/html/rfc6902" rel="noopener noreferrer"&gt;JSON Patch&lt;/a&gt;and &lt;a href="https://datatracker.ietf.org/doc/html/rfc7386" rel="noopener noreferrer"&gt;JSON Merge Patch&lt;/a&gt; content-types in &lt;code&gt;PATCH&lt;/code&gt; requests. It also suggests that GraphQL can be used via the &lt;code&gt;QUERY&lt;/code&gt; method, and for &lt;code&gt;POST&lt;/code&gt; it supports both standard file uploads and some custom JSON-based format.&lt;/p&gt;

&lt;p&gt;Typically you wouldn’t find all of these at the same endpoint, but I wanted to show a few examples together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where’s PUT?
&lt;/h2&gt;

&lt;p&gt;Oddly, there’s no specific header for &lt;code&gt;PUT&lt;/code&gt; requests. Arguably you could say that &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;PUT&lt;/code&gt; are symmetrical, so perhaps the &lt;code&gt;Accept&lt;/code&gt; header kind of extends to both. But the spec is not clear on this.&lt;/p&gt;

&lt;p&gt;I think the actual reality is that &lt;code&gt;Accept-Patch&lt;/code&gt; was the first header in this category that really clearly defined this as a means of feature discovery on &lt;code&gt;OPTIONS&lt;/code&gt;. &lt;code&gt;Accept-Post&lt;/code&gt; and &lt;code&gt;Accept-Query&lt;/code&gt; followed suit. I think&lt;code&gt;Accept-Patch&lt;/code&gt; in &lt;code&gt;OPTIONS&lt;/code&gt; was modelled after in-the-wild usage of &lt;code&gt;Accept&lt;/code&gt;in &lt;code&gt;OPTIONS&lt;/code&gt;, even though the HTTP specific doesn’t super clearly define this.&lt;/p&gt;

&lt;p&gt;If I’m wrong with my interpretation here, I would love to know!&lt;/p&gt;

&lt;p&gt;&lt;small&gt;&lt;em&gt;&lt;br&gt;
Aside: If you’re wondering about &lt;code&gt;DELETE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt; should never have a body,&lt;br&gt;
so all a user would need to know is &lt;em&gt;can&lt;/em&gt; they delete, which you can see&lt;br&gt;
in the &lt;code&gt;Allow&lt;/code&gt; header.&lt;br&gt;
If this is new to you to, &lt;a href="https://www.rfc-editor.org/rfc/rfc8631.html#section-4.2" title="service-desc link relationship" rel="noopener noreferrer"&gt;read my other article&lt;/a&gt; about &lt;code&gt;GET&lt;/code&gt; request&lt;br&gt;
bodies. Most of the information there is applicable to &lt;code&gt;DELETE&lt;/code&gt; as well.&lt;br&gt;
&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Linking to documentation
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;OPTIONS&lt;/code&gt; response is also a great place to tell users where to find additional documentation. In the below example, I included both a machine-readable link to a documentation site, a link to an OpenAPI definition, and a message intended for humans in the response body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 200 OK
Date: Mon, 23 Sep 2024 04:45:38 GMT
Allow: GET, QUERY, OPTIONS
Link: &amp;lt;https://docs.example.org/api/some-endpoint&amp;gt;; rel="service-doc"
Link: &amp;lt;https://api.example.org/openapi.yml&amp;gt;; rel="service-desc" type="application/openapi+yaml"
Content-Type: text/plain

Hey there!

Thanks for checking out this API. You can find the docs for this
specific endpoint at: https://docs.example.org/api/some-endpoint

Cheers,
The dev team

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

&lt;/div&gt;



&lt;p&gt;I recommend keeping the response body as mostly informal and minimal any real information should probably just live on its own URL and be linked to.&lt;/p&gt;

&lt;p&gt;I used the &lt;a href="https://www.rfc-editor.org/rfc/rfc8631.html#section-4.1" rel="noopener noreferrer"&gt;&lt;code&gt;service-doc&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" rel="noopener noreferrer"&gt;&lt;code&gt;service-desc&lt;/code&gt;&lt;/a&gt; link relationships here, but you can of course use any of the &lt;a href="https://www.iana.org/assignments/link-relations/link-relations.xhtml" rel="noopener noreferrer"&gt;IANA link relationship types&lt;/a&gt; here or a custom one. Also see the &lt;a href="https://datatracker.ietf.org/doc/html/rfc8288" rel="noopener noreferrer"&gt;Web linking&lt;/a&gt; spec for more info.&lt;/p&gt;

&lt;h2&gt;
  
  
  Obscure uses
&lt;/h2&gt;

&lt;h3&gt;
  
  
  WebDAV usage
&lt;/h3&gt;

&lt;p&gt;WebDAV, CalDAV and CardDAV also use OPTIONS for feature discovery. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 204 No Content
Date: Mon, 23 Sep 2024 05:01:50 GMT
Allow: GET, PROPFIND, ACL, PROPPATCH, MKCOL, LOCK, UNLOCK
DAV: 1, 2, 3, access-control, addressbook, calendar-access

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  The server-wide asterisk request
&lt;/h3&gt;

&lt;p&gt;Normally HTTP requests are made to a path on the server, and the first line looks a bit like the following in HTTP/1.1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /path HTTP/1.1

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

&lt;/div&gt;



&lt;p&gt;But, there are a few other “request line” formats that are rarely used. One of them lets you discover features available on an entire server, using the asterisk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OPTIONS * HTTP/1.1

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

&lt;/div&gt;



&lt;p&gt;The asterisk here is not a path. Normally asterisks aren’t even allowed in URIs. Many HTTP clients (including &lt;code&gt;fetch()&lt;/code&gt;) don’t even support this request.&lt;/p&gt;

&lt;p&gt;Classic webservers like Apache and Nginx should support this. To try it out, use CURL&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -vX OPTIONS --request-target '*' http://example.org

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final notes
&lt;/h2&gt;

&lt;p&gt;If you have a reason to allow clients to discover features on an endpoint, consider using &lt;code&gt;OPTIONS&lt;/code&gt; instead of a proprietary approach! As you can see in many of these examples, it’s especially useful if you use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" rel="noopener noreferrer"&gt;mimetypes&lt;/a&gt;well.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>New Structured Fields RFC out, and so is my Javascript package</title>
      <dc:creator>Evert Pot</dc:creator>
      <pubDate>Sat, 05 Oct 2024 01:55:09 +0000</pubDate>
      <link>https://dev.to/evert/new-structured-fields-rfc-out-and-so-is-my-javascript-package-o4l</link>
      <guid>https://dev.to/evert/new-structured-fields-rfc-out-and-so-is-my-javascript-package-o4l</guid>
      <description>&lt;p&gt;A new RFC was released for Structured Fields: &lt;a href="https://www.rfc-editor.org/rfc/rfc9651.html" rel="noopener noreferrer"&gt;RFC9651&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is it?
&lt;/h2&gt;

&lt;p&gt;HTTP headers have been a bit of a free-for all in terms of how complex values&lt;br&gt;
are encoded, with many headers requiring their own mini-parser.&lt;/p&gt;

&lt;p&gt;A while back an effort was started to fix this for headers going forward, named 'Structured Fields'. They're called Fields and not 'Headers' because HTTP has both Headers and Trailers!&lt;/p&gt;

&lt;p&gt;Structured fields let you encode things like lists, dictionaries, strings, numbers, booleans and binary data. The &lt;a href="https://www.rfc-editor.org/rfc/rfc8941.html" rel="noopener noreferrer"&gt;original RFC&lt;/a&gt; from 2021 is pretty successful and although many existing headers can't be retrofitted to this format, a lot of new standards are taking advantage.&lt;/p&gt;

&lt;p&gt;Some examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;// Parsed an ASCII string
Header: "foo"

// A simple string, called a 'Token' in the spec
Header: foo

// Parsed as number
Header: 5
Header: -10
Header: 5.01415

// Parsed into boolean
Header: ?1
Header: ?0

// Binaries are base64 encoded
Header: :RE0gbWUgZm9yIGEgZnJlZSBjb29raWU=:

// Items can have parameters
Header: "Hello world"; a="5"

// A simple list
Header: 5, "foo", bar, ?1

# Each element can have parameters
Header: sometoken; param1; param2=hi, 42

// A list can also contain lists itself. These are called 'inner lists' and
// use parenthesis
Header: sometoken, (innerlistitem1 innerlistitem2), (anotherlist)

// A simple dictionary
Header: fn="evert", ln="pot", coffee=?1

// Each item may have parameters too
Header: foo=123; q=1, bar=123, q=0.5

// A dictionary value may be an inner list again
Header: foo=(1 2 3)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The new RFC published last week adds 2 new data types: Dates and&lt;br&gt;
'Display strings', which is a Unicode serialization that fits in the HTTP header (and trailer) format.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Parsed into a Date object&lt;br&gt;
Header: @1686634251

&lt;p&gt;// A Unicode string, called a 'Display String' in the spec. They use&lt;br&gt;
// percent encoding, but encode a different set of characters than&lt;br&gt;
// URLs.&lt;br&gt;
Header %"Frysl%C3%A2n"&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Why should you care?&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;If you encounter these headers in the wild, it's a really good idea to use a standard parser. One of the reasons is that with using structured-fields, there's a built-in extension mechanism. You'll want to make sure that when a new parameter appears your application doesn't suddenly break.&lt;/p&gt;

&lt;p&gt;You may also want to define and use your own HTTP headers. The structured fields format is a very good 'default choice' that removes decisions such as 'How should I encode a key value object' or 'how do I encode a UTF-8 string'.&lt;/p&gt;

&lt;p&gt;With parsers popping up for every language, you don't have to worry about writing your own one-off formats.&lt;/p&gt;

&lt;h2&gt;
  
  
  Javascript package
&lt;/h2&gt;

&lt;p&gt;I'm the maintainer of a Javascript library for Structured Fields, called &lt;a href="https://github.com/badgateway/structured-headers" rel="noopener noreferrer"&gt;"structured headers"&lt;/a&gt;, which I've also updated for this new RFC. I wish I picked the name "structured-fields", but I picked the name before the original standard changed it's name.&lt;/p&gt;

&lt;p&gt;I've just released v2 of this library supporting these new types, and also added ES Modules support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comments?
&lt;/h2&gt;

&lt;p&gt;Reply to one of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[Mastodon post][4]&lt;/li&gt;
&lt;li&gt;[Bluesky post][5]&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>http</category>
      <category>headers</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Taking a look at Mastodon</title>
      <dc:creator>Evert Pot</dc:creator>
      <pubDate>Tue, 01 Nov 2022 21:28:20 +0000</pubDate>
      <link>https://dev.to/evert/taking-a-look-at-mastodon-398n</link>
      <guid>https://dev.to/evert/taking-a-look-at-mastodon-398n</guid>
      <description>&lt;p&gt;I've been a Twitter user and fan since 2007. With Twitter's future looking a bit grim, I started looking around if there's another place to go.&lt;/p&gt;

&lt;p&gt;Twitter can't really be replaced with anything else, because everyone's Twitter experience is unique to them and their community. For me, it's the main way I stay in touch with my Open Source / HTTP / API / Hypermedia bubble and some friends. Losing that would suck! Unfortunately, there's no way that group would all flock to another platform.&lt;/p&gt;

&lt;p&gt;But for the ones that do try something else, the talk of the town seems to be &lt;a href="https://joinmastodon.org/"&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mastodon is interesting. On the surface it might just seem like a Twitter clone, but it's based on a federated protocol called 'ActivityPub'. What this means in practice is that there's no central server. There's many &lt;a href="https://joinmastodon.org/servers"&gt;instances&lt;/a&gt;. Each of these instances is managed by different people, and many of them focus on specific interests.&lt;/p&gt;

&lt;p&gt;With email, it doesn't matter which provider you go with Thanks to universal SMTP standards that every server uses, you can exchange messages with everyone else. This is the same with Mastadon. You're not siloed into a single instance,&lt;br&gt;
and you can follow people from any other instance. Unlike email, it appears that with Mastadon you can actually migrate to different instances if you don't like your current one.&lt;/p&gt;

&lt;p&gt;This has some interesting side effects too. I joined the&lt;br&gt;
&lt;a href="https://indieweb.org/"&gt;IndieWeb&lt;/a&gt; instance, which is a community I already loved. And even though I'm not siloed in, I get access to a local feed of like-minded people from that community. Everything feels new and more intimate.&lt;/p&gt;

&lt;p&gt;Also, instead of one central authority that you have to trust to make the right moderation decisions, you can join one of many that aligns with your values, and you can block entire instances that don't.&lt;/p&gt;

&lt;p&gt;So should you join? If you use Twitter to stay on top of news and follow high profile people then probably not. If you're like me, you might be able to find a community that fits your interest.&lt;/p&gt;

&lt;p&gt;Will I stick to this? Who knows... but Twitter, like everything before, will fall out of favor one day and I'm enjoying Mastadon's ad-free, open source, developer-friendly experience. Reminds me of early Twitter or mid-2000's blogging culture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you're just getting started, check out &lt;a href="https://joinmastodon.org/"&gt;https://joinmastodon.org/&lt;/a&gt; and find a server.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://indieweb.social/web/@evert"&gt;Follow me!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;To find your Twitter friends on Mastadon try &lt;a href="https://twitodon.com/"&gt;Twitodon&lt;/a&gt; and &lt;a href="https://fedifinder.glitch.me/"&gt;Fedifinder&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;To automatically cross-post everything from Twitter to Mastodon and vice versa, use &lt;a href="https://moa.party/"&gt;Moa&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lastly, one of the interesting results of Mastodon building on open protocols, is that it allows alternative implementations.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://microblog.pub/"&gt;Microblog.pub&lt;/a&gt; project lets you self-host a single-user instance. Instead of joining some large instance, you deploy an instance on your own domain that's just for you. Can't get more control than that, and this might be something I'll consider in the future.&lt;/p&gt;

&lt;p&gt;I don't see why this blog couldn't one day also be a 'microblog' and part of the &lt;a href="https://en.wikipedia.org/wiki/Fediverse"&gt;fediverse&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>activitypub</category>
      <category>fediverse</category>
      <category>mastodon</category>
      <category>twitter</category>
    </item>
    <item>
      <title>Porting Curveball to Bun</title>
      <dc:creator>Evert Pot</dc:creator>
      <pubDate>Tue, 13 Sep 2022 17:02:46 +0000</pubDate>
      <link>https://dev.to/evert/porting-curveball-to-bun-54j9</link>
      <guid>https://dev.to/evert/porting-curveball-to-bun-54j9</guid>
      <description>&lt;p&gt;&lt;a href="https://bun.sh/"&gt;Bun&lt;/a&gt; is the hot new server-side Javascript runtime, in the same category as &lt;a href="https://nodejs.org/"&gt;Node&lt;/a&gt; and &lt;a href="https://deno.land/"&gt;Deno&lt;/a&gt;. Bun uses the &lt;a href="https://github.com/WebKit/WebKit/tree/main/Source/JavaScriptCore"&gt;JavascriptCore&lt;/a&gt; engine from Webkit, unlike Node and Deno which use &lt;a href="https://v8.dev/"&gt;V8&lt;/a&gt;. A big selling point is that&lt;br&gt;
it's coming out faster in a many benchmarks, however the things I'm personally excited about is some of it's quality of life features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It parses Typescript and JSX by default (but doesn't type check), which means there's no need for a separate 'dist' directory, or a separate tool like &lt;code&gt;ts-node&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It loads &lt;code&gt;.env&lt;/code&gt; files by default.&lt;/li&gt;
&lt;li&gt;It's compatible with NPM, &lt;code&gt;package.json&lt;/code&gt;, and many built-in Node modules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also like that it's 'Hello world HTTP server' is as simple as writing this file:&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;// http.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&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;Response&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;new&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello world!&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then running it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun run http.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bun will recognize that an object with a &lt;code&gt;fetch&lt;/code&gt; function was default-exported, and start a server on port 3000. As you can see here, this uses the standard &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Request"&gt;Request&lt;/a&gt; and &lt;a href="https://github.com/curveball/aws-lambda"&gt;Response&lt;/a&gt; objects you use in a browser, and can use async/await.&lt;/p&gt;

&lt;p&gt;These are all things that didn't exist when Node and Express were first created, but seem like pretty good ideas for something built today. I don't think using &lt;code&gt;Request&lt;/code&gt; and &lt;code&gt;Response&lt;/code&gt; are good for more complex use-cases (streaming&lt;br&gt;
responses, 1xx responses, trailers, upgrading to other protocols, getting tcp connection metadata like remoteAddr are some that come to mind), because these objects are designed for clients first.&lt;/p&gt;

&lt;p&gt;But in many cases people are just building simple endpoints, and for that it's great.&lt;/p&gt;

&lt;p&gt;Bun supports a ton of the standard Node modules, but it's also missing some such as support for server-side websockets and the node http/https/https packages, which for now makes it incompatible with popular frameworks like Express.&lt;/p&gt;
&lt;h2&gt;
  
  
  Porting Curveball
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://curveballjs.org/"&gt;Curveball&lt;/a&gt; is a Typescript micro-framework we’ve been developing since mid-2018 as a modern replacement for Express and Koa. A key difference between&lt;br&gt;
Curveball and these two frameworks is that it fully abstracts and encapsulates the core 'Request' and 'Response' objects Node provides.&lt;/p&gt;

&lt;p&gt;This made it very easy to create a lambda integration in the past; instead of mapping to Node's Request and Response types, All I needed was simple mapping function for Lambdas idea of what a request and response looks like.&lt;/p&gt;

&lt;p&gt;To get Express to run on AWS Lambda the Node &lt;code&gt;http&lt;/code&gt; stack needs to be emulated, or a full-blown HTTP/TCP server needs to be started and proxied to. Each of these workarounds require a ton of code from libraries like &lt;a href="https://github.com/vendia/serverless-express"&gt;serverless-express&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So with Bun up and coming, either the same work would need to be done to emulate Node's APIs, or Bun would would need to add full compability for the Node &lt;code&gt;http&lt;/code&gt; module (which is eventually coming).&lt;/p&gt;

&lt;p&gt;But because Curveball abstractions, it was relatively easy to get up and running. Most of the work was moving the Node-specific code into a new package.&lt;/p&gt;

&lt;p&gt;Here's the Curveball 'hello world' on Bun:&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;Application&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;@curveball/kernel&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Add all your middlewares here! This should look familiar to Koa users.&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;ctx&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;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello world!&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="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's still a bit experimental, but the following middlewares are tested:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/curveball/router"&gt;router&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/curveball/controller"&gt;controller&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/curveball/cors"&gt;cors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/curveball/accesslog"&gt;accesslog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/curveball/bodyparser"&gt;bodyparser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/curveball/validator"&gt;validator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And because JSX also just works in Bun, it's relatively easy to use it to generate HTML:&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;Application&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;@curveball/kernel&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="nx"&gt;reactMw&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;@curveball/react&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="nx"&gt;React&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;react&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reactMw&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;ctx&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;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/html; charset=utf-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;world&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&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 not a full-blown hydration/server-rendering solution, but JSX has replaced template engines like EJS and Handlebars for us at &lt;a href="https://badgateway.net/"&gt;Bad Gateway&lt;/a&gt;. JSX lets you do the same things, but you get the advantage of type checking, it's harder to create XSS bugs and full Javascript access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts on Bun
&lt;/h2&gt;

&lt;p&gt;Compared to Deno, It was considerably easier to port Curveball to Bun.&lt;br&gt;
Deno was a much greater challenge, due to it having such a radically different idea about packages and module loading. This was over a year ago, so it's worth giving a shot again.&lt;/p&gt;

&lt;p&gt;So, I'm curious where all of this goes! Perhaps Bun is the future, or perhaps we'll see Node get parity with Bun and making it obsolete. Either way competition is good.&lt;/p&gt;

&lt;p&gt;I feel Bun has a better chance than Deno, because it delivers many of its advantages and features while mostly staying inside with the Node ecosystem.&lt;/p&gt;

&lt;p&gt;Although as it turns out Deno also has changed their tune and also made it &lt;a href="https://deno.com/blog/changes"&gt;a new goal&lt;/a&gt; to be compatible. I can't help wondering if this was inspired by Bun's recent success as well.&lt;/p&gt;

</description>
      <category>bunjs</category>
      <category>javascript</category>
      <category>deno</category>
      <category>express</category>
    </item>
    <item>
      <title>A new OAuth2 client for Javascript</title>
      <dc:creator>Evert Pot</dc:creator>
      <pubDate>Mon, 20 Jun 2022 20:14:21 +0000</pubDate>
      <link>https://dev.to/evert/a-new-oauth2-client-for-javascript-jjb</link>
      <guid>https://dev.to/evert/a-new-oauth2-client-for-javascript-jjb</guid>
      <description>&lt;p&gt;Frustrated with the lack of well maintained, minimal OAuth2 libraries, I &lt;a href="https://github.com/badgateway/oauth2-client"&gt;wrote my own&lt;/a&gt;. This new OAuth2 library is only &lt;strong&gt;3KB&lt;/strong&gt; gzipped, mainly because it has &lt;strong&gt;0&lt;/strong&gt; dependencies and relies on modern APIs like &lt;code&gt;fetch()&lt;/code&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API"&gt;Web Crypto&lt;/a&gt; which are built in Node 18 (but it works with Polyfills on Node 14 and 16). &lt;/p&gt;

&lt;p&gt;It has support for key features such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;authorization_code&lt;/code&gt; with &lt;a href="https://datatracker.ietf.org/doc/html/rfc7636"&gt;PKCE&lt;/a&gt; support.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;password&lt;/code&gt; and &lt;code&gt;client_credentials&lt;/code&gt; grants.&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;fetch()&lt;/code&gt; wrapper that automatically adds Bearer tokens and refreshes them.&lt;/li&gt;
&lt;li&gt;OAuth2 endpoint discovery via the Server metadata document (&lt;a href="https://datatracker.ietf.org/doc/html/rfc8414"&gt;RFC8414&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;OAuth2 Token Introspection (&lt;a href="https://datatracker.ietf.org/doc/html/rfc7662"&gt;RFC7662&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your server does support the meta-data document, here's how simple the process can be:&lt;/p&gt;

&lt;h2&gt;
  
  
  client_credentials example
&lt;/h2&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;OAuth2Client&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;@badgateway/oauth2-client&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;..&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;..&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://my-auth-server.example&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;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientCredentials&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without the meta-data document, you will need to specify settings such as the &lt;code&gt;tokenEndpoint&lt;/code&gt; and possibly the &lt;code&gt;authorizationEndpoint&lt;/code&gt; depending on which flow you are using.&lt;/p&gt;

&lt;h2&gt;
  
  
  authorization_code example
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;authorization_code&lt;/code&gt; flow is a multi-step process, so a bit more involved.&lt;br&gt;
The library gives you direct access to the primitives, allowing you to integrate in your own frameworks and applications.&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;OAuth2Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;generateCodeVerifier&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;@badgateway/oauth2-client&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;OAuth2Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://authserver.example/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&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="c1"&gt;// Part of PCKE&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;codeVerifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;generateCodeVerifier&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// In a browser this might work as follows:&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorizationCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAuthorizeUri&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;redirectUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://my-app.example/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;some-string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;codeVerifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;scope&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;scope1&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;scope2&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Handling the redirect back
&lt;/h3&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="nx"&gt;oauth2Token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorizationCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getTokenFromCodeRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;redirectUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://my-app.example/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;some-string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;codeVerifier&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;oauth2Token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;authorizationCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;codeResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docs and download
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/badgateway/oauth2-client"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/@badgateway/oauth2-client"&gt;npmjs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>oauth2</category>
      <category>fetch</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Request bodies in GET requests</title>
      <dc:creator>Evert Pot</dc:creator>
      <pubDate>Sat, 29 Jan 2022 19:14:00 +0000</pubDate>
      <link>https://dev.to/evert/request-bodies-in-get-requests-1b85</link>
      <guid>https://dev.to/evert/request-bodies-in-get-requests-1b85</guid>
      <description>&lt;p&gt;12 years ago I asked on Stack Overflow: &lt;a href="https://stackoverflow.com/questions/978061/http-get-with-request-body" rel="noopener noreferrer"&gt;Are HTTP GET requests allowed to have request bodies?&lt;/a&gt;. This got a 2626 upvotes and a whopping 1.6 million views, so clearly it’s something lots of people are still curious about, and in some cases disagree with the accepted answer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/978061/http-get-with-request-body" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rk40tycqtv2t8w20h2f.png" alt="Stack overflow screenshot" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because it keeps popping up in my Stack Overflow notifications (and I compulsively visit the site), the question has lived in my head rent-free. I keep adding context in my head, and I’ve been meaning to write some of this down for a few years now and hopefully evict it.&lt;/p&gt;

&lt;p&gt;Anyway, if you’re just looking for a quick answer, it’s ‘No, you shouldn’t do this.’, you should probably use &lt;a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-safe-method-w-body-02" rel="noopener noreferrer"&gt;&lt;code&gt;QUERY&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Undefined behavior
&lt;/h2&gt;

&lt;p&gt;A number of people (most famously &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html#search-search-api-desc" rel="noopener noreferrer"&gt;ElasticSearch&lt;/a&gt;) have gotten this wrong, but why? I think it’s because of this sentence in the &lt;a href="https://datatracker.ietf.org/doc/html/rfc7231#section-4.3.1" rel="noopener noreferrer"&gt;HTTP Spec&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A payload within a GET request message has no defined semantics&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sentence could easily suggest that there’s no specific behavior associated to request bodies with &lt;code&gt;GET&lt;/code&gt; requests, and that the behavior is left up to the implementor.&lt;/p&gt;

&lt;p&gt;The reality is that this is more like &lt;a href="https://en.wikipedia.org/wiki/Undefined_behavior" rel="noopener noreferrer"&gt;Undefined behavior&lt;/a&gt; from languages like C/C++. My understanding is that leaving certain aspects of the C language undefined (instead of for example requiring an error to be thrown) leaves room for compiler implementations to make certain optimizations. Some compilers also have fun with this; GCC hilariously &lt;a href="https://feross.org/gcc-ownage/" rel="noopener noreferrer"&gt;starts a video game&lt;/a&gt; in a specific case of undefined behavior which really brings home this point.&lt;/p&gt;

&lt;p&gt;If you were to write a C program that relies on how a compiler dealt with specific undefined behavior, it means your program is no longer a portable C program, but it’s written in variant of C that only works on some compilers.&lt;/p&gt;

&lt;p&gt;The same applies for HTTP as well. It’s true that undefined behavior means that &lt;em&gt;you&lt;/em&gt; as a server developer can define it, but you are not an island!&lt;/p&gt;

&lt;p&gt;When working with HTTP, there’s servers but also load balancers, proxies, browsers and other clients that all need to work together. The behavior isn’t just undefined server-side, a load balancer might choose to silently drop bodies or throw errors. There’s many real-world examples of this. &lt;code&gt;fetch()&lt;/code&gt;for example will throw an error.&lt;/p&gt;

&lt;p&gt;This hasn’t stopped people from doing this anyway. OpenAPI &lt;a href="https://swagger.io/docs/specification/describing-request-body/" rel="noopener noreferrer"&gt;removed&lt;/a&gt;support for describing &lt;code&gt;GET&lt;/code&gt; request bodies in version 3.0 (and &lt;code&gt;DELETE&lt;/code&gt;, which has the same issue!), but was quitely &lt;a href="https://github.com/OAI/OpenAPI-Specification/pull/2117" rel="noopener noreferrer"&gt;added back in 3.1&lt;/a&gt; to not prevent people from documenting their arguably broken APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it’s not defined
&lt;/h2&gt;

&lt;p&gt;The best source I have is this quote from Roy Fielding in 2007. Roy Fielding coined REST is and is one of the main authors of the HTTP/1.1 RFCs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Yes. In other words, any HTTP request message is allowed to contain a message body, and thus must parse messages with that in mind. Server semantics for GET, however, are restricted such that a body, if any, has no semantic meaning to the request. The requirements on parsing are separate from the requirements on method semantics. So, yes, you can send a body with GET, and no, it is never useful to do so. This is part of the layered design of HTTP/1.1 that will become clear again once the spec is partitioned (work in progress).&lt;/p&gt;

&lt;p&gt;….Roy&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(&lt;small&gt;His message was originally sent to the now-dead rest-discuss&lt;br&gt;
group on Yahoo Groups, but I found an &lt;a href="https://github.com/jam01/rest-discuss-archive/blob/262d6768f83cdf811c2a997564105fc74bad8987/rest-discuss/9962.json" rel="noopener noreferrer"&gt;archive in JSON format&lt;/a&gt;&lt;/small&gt;)&lt;/p&gt;

&lt;p&gt;However, I always found this answer unsatisfying. I understand that you might want a low-level protocol design that just passes messages containing headers, bodies, urls, methods and statuses and not concern itself with method-specific behavior.&lt;/p&gt;

&lt;p&gt;That design goal doesn’t preclude &lt;code&gt;GET&lt;/code&gt; from specifically rejecting request bodies though, and it also doesn’t preclude the spec from mentioning that request bodies should not be emitted.&lt;/p&gt;

&lt;p&gt;So, unless there’s a different reason for this I’m going to have to assume that this was well-intentioned but just not written clearly enough.&lt;/p&gt;

&lt;p&gt;Despite this explanation from one of the authors of the HTTP spec itself, I noticed some people will still claim a different interpretation, making a sort of a &lt;a href="https://en.wikipedia.org/wiki/The_Death_of_the_Author" rel="noopener noreferrer"&gt;‘death of the author’&lt;/a&gt; argument. It’s a bit funny to think about ‘death of the author’ in technical specs, but I think they have a point. I believe that the definition of a standard such as HTTP is not the written RFC, it’s how everyone actually implements it.&lt;/p&gt;

&lt;p&gt;The goal of the spec is to accurately describe the standard, not to define it. If what everyone is doing is different from the author’s intention, the spec has failed to accurately describe the standard, not vice versa.&lt;/p&gt;

&lt;p&gt;The team behind the HTTP specs believes this too, which is why we’ve seen new releases of &lt;code&gt;HTTP/1.1&lt;/code&gt; without increasing the version. In each iteration major steps are taken to capture real-world usage, sometimes even in conflict with the original RFC2616.&lt;/p&gt;

&lt;p&gt;However, in this case it’s irrelevant. Many popular HTTP implementations will throw errors when seeing &lt;code&gt;GET&lt;/code&gt; bodies, such as &lt;code&gt;fetch()&lt;/code&gt;. Using &lt;code&gt;GET&lt;/code&gt;bodies will give you such poor interopability that it’s worth continuing to not do this.&lt;/p&gt;

&lt;p&gt;In 2019 I’ve &lt;a href="https://github.com/httpwg/http-core/issues/202" rel="noopener noreferrer"&gt;opened a ticket&lt;/a&gt; to request to fix this, and they listened. The upcoming HTTP/1.1 is going to include the following text:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Although request message framing is independent of the method used, content received in a GET request has no generally defined semantics, cannot alter the meaning or target of the request, and might lead some implementations to reject the request and close the connection because of its potential as a request smuggling attack (Section 11.2 of HTTP/1.1).&lt;/p&gt;

&lt;p&gt;A client SHOULD NOT generate content in a GET request unless it is made directly to an origin server that has previously indicated, in or out of band, that such a request has a purpose and will be adequately supported.&amp;gt;An origin server SHOULD NOT rely on private agreements to receive content, since participants in HTTP communication are often unaware of intermediaries along the request chain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-semantics#section-9.3.1" rel="noopener noreferrer"&gt;Source&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should &lt;code&gt;GET&lt;/code&gt; have a body?
&lt;/h2&gt;

&lt;p&gt;I think we feel this way, because we’ve been told over and over again that it’s a good idea to use protocols in a ‘semantically correct’ way.&lt;/p&gt;

&lt;p&gt;But why should be care about semantics? 2 reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you do things in a semantically correct way, other systems can make assumptions about how it should behave. For example: A &lt;code&gt;PUT&lt;/code&gt; request may be automatically repeated if it failed the first time due to a network failure or 5xx error. A &lt;code&gt;GET&lt;/code&gt; request may be cached if it contained a&lt;code&gt;Cache-Control&lt;/code&gt; header.&lt;/li&gt;
&lt;li&gt;It’s self-documenting behavior. If you see a &lt;code&gt;GET&lt;/code&gt; request it tells a developer something is being retrieved.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So while #1 doesn’t really apply here (there’s no technical advantages, because it’s undefined behavior), but #2 makes sense.&lt;/p&gt;

&lt;p&gt;So if we decided to use &lt;code&gt;GET&lt;/code&gt; for our complex search, what can we do? Body is obviously not allowed; our only options are headers and the URL. There’s a number of issues with this: Encoding UTF-8 is unclear, no real support for documents/mine-types, length limitations. It’s a bit of a mess!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why was it designed not to support bodies?
&lt;/h2&gt;

&lt;p&gt;Most developers working with HTTP and learning about it is in the context of APIs, but this is not the original use-case.&lt;/p&gt;

&lt;p&gt;It all starts with HTML and browsers and URLS. The world wide web was&lt;a href="http://info.cern.ch/hypertext/WWW/Summary.html" rel="noopener noreferrer"&gt;designed&lt;/a&gt; as a distributed hypertext document system, where every document has a global unique identifier called a URL.&lt;/p&gt;

&lt;p&gt;To retrieve a hypertext document, you would do a &lt;code&gt;GET&lt;/code&gt; on this url, to replace or create the document a &lt;code&gt;PUT&lt;/code&gt; and to remove the document &lt;code&gt;DELETE&lt;/code&gt;. (&lt;small&gt;Note that it took longer to get a writable web, but I wanted to&lt;br&gt;
illustrate what I think the intended design is without being encumbered&lt;br&gt;
by facts&lt;/small&gt;).&lt;/p&gt;

&lt;p&gt;Taken from this perspective, the idea of ‘parameters’ makes less sense.&lt;code&gt;GET&lt;/code&gt; doesn’t just mean “Do a &lt;a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-semantics#section-9.3.1" rel="noopener noreferrer"&gt;safe&lt;/a&gt; request and read something from the server”, it means: ‘Give me the document with this name’.&lt;/p&gt;

&lt;p&gt;This specific feature is in part why the web was so successful. Given that the URL comprehensively describes to a client exactly how to connect to a server and retrieve a document, it made the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; HTML work. It also let people make bookmarks, share links via email/chat and paint it on store-fronts.&lt;/p&gt;

&lt;p&gt;The URL is the web’s superstar and killer feature. HTTP just let you find documents associated with the URL. &lt;a href="https://www.w3.org/Protocols/HTTP/AsImplemented.html" rel="noopener noreferrer"&gt;HTTP/0.9 didn’t even have headers and can be read during a bathroom break&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our needs have evolved, has HTTP?
&lt;/h2&gt;

&lt;p&gt;I still maintain that even if you’re building a REST api, it’s good to think of your endpoints as documents, and the &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt; as the most important HTTP methods to manipulate these, using the URL as the primary key.&lt;/p&gt;

&lt;p&gt;But, sometimes we need to do something more complicated and it would be nice if HTTP had a prescribed way to handle cases where we want to describe a search query as a document.&lt;/p&gt;

&lt;p&gt;The answer traditionally was to just use &lt;code&gt;POST&lt;/code&gt;. &lt;code&gt;POST&lt;/code&gt; is kind of your no-guarantees catch all method. Often also used to tunnel other protocols that don’t really speak HTTP well, such as SOAP, XMLRPC and more recently GraphQL.&lt;/p&gt;

&lt;p&gt;But there’s a new contender. Now I think your best option is &lt;a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-safe-method-w-body-02" rel="noopener noreferrer"&gt;&lt;code&gt;QUERY&lt;/code&gt;&lt;/a&gt;. This is a new method, that’s not quite standard yet but any compliant HTTP client and server should already support it. The goal of &lt;code&gt;QUERY&lt;/code&gt; is specifically to solve this use-case.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;QUERY&lt;/code&gt; solves the following problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It’s basically a ‘safe’ &lt;code&gt;POST&lt;/code&gt;. This means the implication is that it’s for reading and safe to repeat.&lt;/li&gt;
&lt;li&gt;It also is self-descriptive. It tells a developer that this is a API that’s focused on reading.&lt;/li&gt;
&lt;li&gt;The spec also makes it cachable.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I think you should still continue the use &lt;code&gt;GET&lt;/code&gt; for the majority of cases, but there’s a clear answer now for what to do when that doesn’t fit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anyway…
&lt;/h2&gt;

&lt;p&gt;That’s a lot of writing for what seemingly is a simple question. It’s just one of those things that’s been bouncing around my head for a bit too long.&lt;/p&gt;

&lt;p&gt;I hope it’s out of my system!&lt;/p&gt;

&lt;p&gt;Big thank you to everyone who originally answered my SO question.&lt;/p&gt;

</description>
      <category>get</category>
      <category>http</category>
      <category>method</category>
    </item>
    <item>
      <title>JWT should not be your default for sessions</title>
      <dc:creator>Evert Pot</dc:creator>
      <pubDate>Fri, 14 May 2021 01:30:27 +0000</pubDate>
      <link>https://dev.to/evert/jwt-should-not-be-your-default-for-sessions-3hpf</link>
      <guid>https://dev.to/evert/jwt-should-not-be-your-default-for-sessions-3hpf</guid>
      <description>&lt;h2&gt;
  
  
  Cookies
&lt;/h2&gt;

&lt;p&gt;When designing web applications, (especially the traditional HTML kind), you will at one point have to figure out how to log a user in and keep them logged in between requests.&lt;/p&gt;

&lt;p&gt;The core mechanism we use to achieve this are cookies. Cookies are small strings sent by a server to a client. After a client receives this string, it will repeat this in subsequent requests. We could store a 'user id' in a cookie, and for any future requests we'll know what user_id the client was.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cookie: USER_ID=123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this is very insecure. The information lives in the browser, which means users can change &lt;code&gt;USER_ID&lt;/code&gt; and be identified as a different user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sessions
&lt;/h2&gt;

&lt;p&gt;The traditional way to solve this is what's known as a 'session'. I don't know what the earliest usage of sessions is, but it's in every web framework, and has been since web frameworks are a thing.&lt;/p&gt;

&lt;p&gt;Often, sessions and cookies are described as 2 different things, but they're really not. A session needs a cookie to work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cookie: MY_SESSION_ID=WW91IGdvdCBtZS4gRE0gbWUgb24gdHdpdHRlciBmb3IgYSBmcmVlIGNvb2tpZQ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of a predictable user id, we're sending the client a completely random session id that is impossibly hard to guess. The ID has no further meaning, and doesn't decode to anything. This is sometimes called an opaque token.&lt;/p&gt;

&lt;p&gt;When a client repeats this session id back to the server, the server will look up the id in (for example) a database, which links it back to the user id. When a user wants to log out, the session id is removed from the data storage, which means the cookie is no longer associated with a user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where is the session data stored?
&lt;/h3&gt;

&lt;p&gt;Languages like PHP have a storage system for this built in, and will by default store data in the local filesystem. In the Node.js ecosystem, by default this data will be in 'memory' and disappear after the server restarts.&lt;/p&gt;

&lt;p&gt;These approaches make sense on developer machines, or when sites were hosted on long-lived bare-metal servers, but these days a deploy typically means a completely fresh 'system', so this information needs to be stored in a place that outlives the server. An easy choice is a database, but it's common for sites to use systems like Redis and Memcached, which works for tiny sites, but still works at massive scales.&lt;/p&gt;

&lt;h2&gt;
  
  
  Encrypted token
&lt;/h2&gt;

&lt;p&gt;Over 10 years ago, I started working a bit more with OAuth v1 and similar authentication systems, and I wondered if we could just store all the information in the cookie and cryptographically sign it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/3240246/signed-session-cookies-a-good-idea" rel="noopener noreferrer"&gt;&lt;br&gt;
    &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fevertpot.com%2Fassets%2Fposts%2Fjwt%2Fstackoverflow.png" alt="Question about session tokens on Stack Overflow"&gt;&lt;br&gt;
  &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Despite getting some good answers, I didn't go through with it as I didn't feel confident enough in making this secure, and I felt it required a better understanding in crypto than I did.&lt;/p&gt;

&lt;p&gt;A few years later, we got &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;JWT&lt;/a&gt;, and it's hot shit! JWT itself is a standard for encrypting/signing JSON objects and it's used a LOT for authentication. Instead of an opaque token in a cookie, we actually embed the &lt;code&gt;user_id&lt;/code&gt;  again, but we include a signature. The signature can only be generated by the server, and it's calculated using a 'secret' and the actual data in the cookie.&lt;/p&gt;

&lt;p&gt;This means that if the data is tampered with (the &lt;code&gt;user_id&lt;/code&gt; was changed), the signature no longer matches.&lt;/p&gt;

&lt;p&gt;So why is this useful? The best answer I have for this, is that it's not needed to have a system for session data, like Redis or a database. All the information is contained in the JWT, it means your infrastructure is in theory simpler. You're potentially making fewer calls to a data-store on a per-request basis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drawbacks
&lt;/h2&gt;

&lt;p&gt;There are major drawbacks to using JWT.&lt;/p&gt;

&lt;p&gt;First, it's a complicated standard and users are prone to get the settings wrong. If the settings are wrong, in the worst case it could mean that &lt;em&gt;anyone&lt;/em&gt; can generate valid JWTs and impersonate anyone else. This is not a beginners-level problem either, last year &lt;a href="https://insomniasec.com/blog/auth0-jwt-validation-bypass" rel="noopener noreferrer"&gt;Auth0&lt;/a&gt; had a bug in one of&lt;br&gt;
their products that had this very problem.&lt;/p&gt;

&lt;p&gt;Auth0 is(or was? they just got acquired) a major vendor for security products, and ironically sponsor the &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;jwt.io&lt;/a&gt; website. If they're not safe, what chance does the general (developer) public have?&lt;/p&gt;

&lt;p&gt;However, this issue is part of a larger reason why many security experts &lt;a href="https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid" rel="noopener noreferrer"&gt;dislike&lt;/a&gt; JWT: it has a ton of features and a very large scope, which gives it a large surface area for potential mistakes, by either library authors or users of those libraries. (alternative stateless tokens to JWT &lt;a href="https://www.scottbrady91.com/JOSE/Alternatives-to-JWTs" rel="noopener noreferrer"&gt;exists&lt;/a&gt;, and some of them do solve this.)&lt;/p&gt;

&lt;p&gt;A second issue is 'logging out'. With traditional sessions, you can just remove the session token from your session storage, which is effectively enough to 'invalidate' the session.&lt;/p&gt;

&lt;p&gt;With JWT and other stateless token this is not possible. We can't remove the token, because it's self-contained and there's no central authority that can invalidate them.&lt;/p&gt;

&lt;p&gt;This is typically solved in three ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The tokens are made very short lived. For example, 5 minutes. Before the 5 minutes are over, we generate a new one. (often using a separate refresh token).&lt;/li&gt;
&lt;li&gt;Maintain a system that has a list of recently expired tokens.&lt;/li&gt;
&lt;li&gt;There is no server-driven log out, and the assumption is that the client can delete their own tokens.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Good systems will typically use the first two. An important thing to point out is, in order to support logout, you'll likely still need a centralized storage mechanism (for refresh tokens, revocation lists or both), which is the very&lt;br&gt;
thing that JWT were supposed to 'solve'.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sidenote: some people like JWT because it's fewer systems to hit per request, but that contradicts with being able to revoke tokens before they expire.&lt;/p&gt;

&lt;p&gt;My favourite solution to this is keep a global list of JWTs that have been revoked before they expired (and remove the tokens after expiry). Instead of letting webservers hit a server to get this list, push the list to each server using a pub/sub mechanism.&lt;/p&gt;

&lt;p&gt;Revoking tokens is important for security, but rare. Realistically this list is small and easily fits into memory. This largely solves the logout issue.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A last issue with JWT is that they are relatively big, and when used in cookies it adds a lot of per-request overhead.&lt;/p&gt;

&lt;p&gt;All in all, that's a lot of drawbacks just to avoid a central session store. It's not my opinion that JWT are universally a bad idea or without benefits, but there is a lot to consider.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why are they popular?
&lt;/h2&gt;

&lt;p&gt;One thing that's surprised me when reading tech blogs, is that there is a &lt;em&gt;lot&lt;/em&gt; of chatter around JWT. Especially on Medium and subreddits like &lt;a href="https://www.reddit.com/r/node/" rel="noopener noreferrer"&gt;/r/node&lt;/a&gt; I see intros to JWT on an extremely regular basis.&lt;/p&gt;

&lt;p&gt;I realize that that doesn't mean that 'JWTs are more popular than session tokens', for the same reason that GraphQL isn't more popular than REST, or NoSQL than relational databases: it's just not that interesting to write about the technology that's been tried and tested for a decade or more (See: &lt;a href="https://en.wikipedia.org/wiki/Appeal_to_novelty" rel="noopener noreferrer"&gt;Appeal to novelty&lt;/a&gt;). In addition, subject experts that write about new solutions are likely going to have different problems &amp;amp; scale than the majority of their own readers.&lt;/p&gt;

&lt;p&gt;However, these new technologies create a lot more buzz than their simpler counterparts, and if enough people keep talking about the hot thing, eventually this can translate to actual adoption, despite it being a sub-optimal choice for the majority of simple use-cases.&lt;/p&gt;

&lt;p&gt;This is similar to many newer developers learning how to build SPAs with React before server-rendered HTML. Experienced devs would likely feel that server-rendered HTML should probably be your default choice, and building an SPA &lt;em&gt;when needed&lt;/em&gt;, but this is not what new developers are typically taught.&lt;/p&gt;

&lt;p&gt;Adopting complex systems before the simple option is considered is something I see happening more, but it surprised me for JWT.&lt;/p&gt;

&lt;p&gt;As an  exercise, I looked up the top most popular (by votes) posts on /r/node that mention JWT. I was going to go over the first 100, but got bored after the top 12.&lt;/p&gt;

&lt;p&gt;From these 12 articles and Github repos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1&lt;/strong&gt; mentions using a revocation list, &lt;strong&gt;3&lt;/strong&gt; mention refesh tokens. The remaining articles and github repositories simply have no means of logging out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1&lt;/strong&gt; article mentions that it &lt;em&gt;might&lt;/em&gt; be better to use a standard session storage instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1&lt;/strong&gt; article uses &lt;em&gt;both&lt;/em&gt; a standard session storage and JWT, making JWT unneeded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1&lt;/strong&gt; github repository ships with pre-generated private keys. (yup)&lt;/li&gt;
&lt;li&gt;Most of posts use expiry times of weeks or months and 3 posts &lt;strong&gt;never&lt;/strong&gt; expire their JWTs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Except 1, the quality of these highly upvoted posts was extremely low, the authors were likely not qualified to write about this and can potentially cause real-world harm.&lt;/p&gt;

&lt;p&gt;All this at least confirmed my bias that JWT for security tokens is hard to get right.&lt;/p&gt;

&lt;h2&gt;
  
  
  On JWT and scale
&lt;/h2&gt;

&lt;p&gt;Going through tons of Reddit posts and comments also got me a more refined idea of why people think JWTs are better. The top reason everywhere is: "It's more scalable", but it's not obvious at what scale people &lt;em&gt;think&lt;/em&gt; they'll start to have issues. I believe the point where issues start to appear is likely much higher than is assumed.&lt;/p&gt;

&lt;p&gt;Most of us aren't Facebook, but even at 'millions of active sessions', a distributed key-&amp;gt;value store is unlikely going to buckle.&lt;/p&gt;

&lt;p&gt;Statistically, most of us are building applications that won't make a Raspberry Pi break a sweat.&lt;/p&gt;

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

&lt;p&gt;Using JWTs for tokens add some neat properties and make it possible in some cases for your services to be stateless, which can be desirable property in some architectures.&lt;/p&gt;

&lt;p&gt;Adopting them comes with drawbacks. You either forego revocation, or you need to have infrastructure in place that be way more complex than simply adopting a session store and opaque tokens.&lt;/p&gt;

&lt;p&gt;My point in all this is not to discourage the use of JWT in general, but be deliberate and careful when you do. Be aware of both the security and functionality trade-offs and pitfalls. Keep it out of your 'boilerplates' and templates, and don't make it the default choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Acknowledgements
&lt;/h2&gt;

&lt;p&gt;Thanks to &lt;a href="https://twitter.com/nchangfong?lang=en" rel="noopener noreferrer"&gt;Nick Chang-Fong&lt;/a&gt; and &lt;a href="https://twitter.com/dominikzogg" rel="noopener noreferrer"&gt;Dominik Zogg&lt;/a&gt; for providing feedback and suggestions to this article!&lt;/p&gt;

</description>
      <category>jwt</category>
      <category>json</category>
      <category>auth</category>
      <category>security</category>
    </item>
    <item>
      <title>Ketting 7 released</title>
      <dc:creator>Evert Pot</dc:creator>
      <pubDate>Mon, 12 Apr 2021 16:30:00 +0000</pubDate>
      <link>https://dev.to/evert/ketting-7-released-2i0b</link>
      <guid>https://dev.to/evert/ketting-7-released-2i0b</guid>
      <description>&lt;p&gt;We just released version 7 of &lt;a href="https://github.com/badgateway/ketting/"&gt;Ketting&lt;/a&gt;. Ketting is a generic HATEOAS client for Javascript.&lt;/p&gt;

&lt;p&gt;A whole bunch of features have been added since September. We've been testing Ketting 7 in beta since January, so I'm excited to get this out the door.&lt;/p&gt;

&lt;p&gt;I've been working on this project since 2016. Normally, I would expect a project like this to get a little stale. For me personally, the opposite has been true and using Ketting (especially with React) is starting to feel a bit like a paradigm shift.&lt;/p&gt;

&lt;p&gt;Read on to see what's new!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Ketting?
&lt;/h2&gt;

&lt;p&gt;In short: Ketting is a generic REST client for Javascript. You can use it for pushing JSON objects via HTTP, but the richer your API is in terms of best practices and standard formats, the more it can automatically do for you.&lt;/p&gt;

&lt;p&gt;It has support for Hypermedia formats such as HAL, Siren, Collection+JSON, JSON:API and can even understand and follow links from HTML.&lt;/p&gt;

&lt;p&gt;In the past it was not uncommon to hear that HATEOAS is lacking a good generic client. If you are a Javascript/Typescript user this is no longer true.&lt;/p&gt;

&lt;p&gt;More information can be found on the &lt;a href="https://github.com/badgateway/ketting/"&gt;Github&lt;/a&gt; page.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's new?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Better HAL-Forms support
&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://rwcbook.github.io/hal-forms/"&gt;HAL-Forms&lt;/a&gt; is an extension of &lt;a href="https://tools.ietf.org/html/draft-kelly-json-hal-08"&gt;HAL&lt;/a&gt;, and adds support for 'actions' or 'forms', similar to what the &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; tag is to HTML.&lt;/p&gt;

&lt;p&gt;Since the start of the year HAL-Forms has seen major updates, which was a collaborative effort by several people from projects in the HAL community (including &lt;a href="https://spring.io/projects/spring-hateoas"&gt;Spring HATEOAS&lt;/a&gt; and yours truly) and lead by it's author &lt;a href="https://twitter.com/mamund"&gt;Mike Amudsen&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Spring HATEOAS &lt;a href="https://spring.io/blog/2021/02/19/spring-hateoas-1-3-m2-released"&gt;released&lt;/a&gt; its HAL-Forms updates in version 1.3 M2 (unclear if this is a stable release or not), and Ketting follows today.&lt;/p&gt;

&lt;p&gt;Major new features in HAL-Forms include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for lookups

&lt;ul&gt;
&lt;li&gt;Example use-case is rendering dropdowns/comboboxes.&lt;/li&gt;
&lt;li&gt;The list of possible options can either be provided in-line or via an external resource.&lt;/li&gt;
&lt;li&gt;JSON and &lt;code&gt;text/csv&lt;/code&gt; is support for external resources.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Support for most of the HTML5 input types, such as &lt;code&gt;checkbox&lt;/code&gt;, &lt;code&gt;color&lt;/code&gt;, &lt;code&gt;tel&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;textarea&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;Support for many of the field attributes that also exist in HTML5 form fields, such as &lt;code&gt;placeholder&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;step&lt;/code&gt;, &lt;code&gt;cols&lt;/code&gt;, &lt;code&gt;rows&lt;/code&gt;, and others.&lt;/li&gt;
&lt;li&gt;Support for a form &lt;code&gt;target&lt;/code&gt;. Previously this could also be supplied via the URI.&lt;/li&gt;
&lt;li&gt;Support for multiple forms per document.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  React bindings: &lt;code&gt;&amp;lt;RequireLogin&amp;gt;&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;(note: all of the new react-ketting features were backported to Ketting 6)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/badgateway/react-ketting"&gt;react-ketting&lt;/a&gt; now has a &lt;code&gt;RequireLogin&lt;/code&gt; component, that can be use to handle the OAuth2 &lt;code&gt;authorization_code&lt;/code&gt; flow in React applications.&lt;/p&gt;

&lt;p&gt;Example usage:&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;function&lt;/span&gt; &lt;span class="nx"&gt;MyApp&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RequireLogin&lt;/span&gt;
    &lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-oauth2-client-id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;authorizeEndpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;tokenEndpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://..&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="nx"&gt;logged&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/RequireLogin&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React-bindings: &lt;code&gt;useCollection&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;useCollection&lt;/code&gt; hook was added to easily render a collection on a server.&lt;/p&gt;

&lt;p&gt;Example usage:&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;useCollection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useResource&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;react-ketting&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Resource&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;resource&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&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="nl"&gt;body&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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ArticleList&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useCollection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;&amp;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;/articles&lt;/span&gt;&lt;span class="dl"&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;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;section&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Articles&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ArticleItem&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt; &lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/section&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;ArticleItem&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Resource&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;&amp;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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resource&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;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&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;data&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React-bindings: &lt;code&gt;refreshOnStale&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Both &lt;code&gt;useResource&lt;/code&gt; and &lt;code&gt;useCollection&lt;/code&gt; got a &lt;code&gt;refreshOnStale&lt;/code&gt; flag, that will cause Ketting to automatically ask the server for a new resource state if the cache is marked stale for a resource.&lt;/p&gt;

&lt;p&gt;This can have a pretty magical effect when you (for example) use a &lt;code&gt;POST&lt;/code&gt; request on a collection to add a new member.&lt;/p&gt;

&lt;p&gt;If you also used a &lt;code&gt;useCollection&lt;/code&gt; hook on the same page to show the collection, that collection will automatically refresh it's own list.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;first&lt;/em&gt; fetch of &lt;code&gt;useCollection&lt;/code&gt; will include a &lt;code&gt;Prefer-Transclude&lt;/code&gt; HTTP header, telling the user to (ideally) embed every item of the collection in the response, but subsequent refreshes will not.&lt;/p&gt;

&lt;p&gt;This means the first time we only need 1 HTTP request, but for refreshes only the collection itself (and not it's members) need to be returned.&lt;/p&gt;

&lt;p&gt;If your 'create' operation also returned &lt;code&gt;Content-Location&lt;/code&gt;, you can remove one more HTTP request from that list.&lt;/p&gt;

&lt;p&gt;Similarly this can be used for &lt;code&gt;DELETE&lt;/code&gt; requests of members of the collection, as long as your response includes &lt;code&gt;Link: &amp;lt;/parent-collection&amp;gt;; rel="invalidates"&lt;/code&gt;, the collection will also automatically re-render with the deleted item removed.&lt;/p&gt;

&lt;p&gt;For one application we took this a step further, and used Websockets to emit 'stale' events from the server. With virtually no modifications to the frontend, we were able to turn a single-user web application into an application that&lt;br&gt;
could reflect changes in real-time from other users who were using the application at the same time. This really felt like an emerging property of a well designed system (standing on the shoulders of decades of Hypermedia, HTTP and REST research).&lt;/p&gt;

&lt;p&gt;Personally I'm very hyped about this feature, and I can't wait to demo this on a meetups or a conferences (if my talk proposals ever get accepted!?).&lt;/p&gt;
&lt;h3&gt;
  
  
  Deprecation warnings
&lt;/h3&gt;

&lt;p&gt;Ketting 7 will now emit warnings when it encounters a &lt;code&gt;Deprecation&lt;/code&gt; or &lt;code&gt;Sunset&lt;/code&gt; header, or when a link contains the &lt;code&gt;status: "deprecated"&lt;/code&gt; hint.&lt;/p&gt;

&lt;p&gt;For more information about this feature, read &lt;a href="https://evertpot.com/ketting-7-deprecation-warnings/"&gt;my previous article&lt;/a&gt; about this feature.&lt;/p&gt;
&lt;h3&gt;
  
  
  Removed support for Prefer-Push
&lt;/h3&gt;

&lt;p&gt;HTTP/2 Push support in browsers is &lt;a href="https://evertpot.com/http-2-push-is-dead/"&gt;effectively dead&lt;/a&gt;. To reduce drag, I've removed the &lt;code&gt;Prefer-Push&lt;/code&gt; feature from Ketting.&lt;/p&gt;
&lt;h3&gt;
  
  
  Smarter caching of newly created resoures.
&lt;/h3&gt;

&lt;p&gt;If you use Ketting to create a new resource (for example with &lt;code&gt;POST&lt;/code&gt;), and the server returns a &lt;code&gt;Content-Location&lt;/code&gt; header in its response, it will store the response body with the new URI in it's cache.&lt;/p&gt;

&lt;p&gt;This can potentially reduce roundtrips. &lt;code&gt;Content-Location&lt;/code&gt; is a way for a server to say: 'The response body is the representation of the resource this URI'.&lt;/p&gt;

&lt;p&gt;This is another great example of a HTTP caching feature in Ketting that goes beyond what Web Browsers typically do.&lt;/p&gt;

&lt;p&gt;Other examples of this is being able to tease apart transcluded/embedded responses, allowing servers to invalidate caches for entries with an &lt;code&gt;invalidates&lt;/code&gt; link and exposing cache-related events to the user.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;State&lt;/code&gt; objects now have a &lt;code&gt;.follow()&lt;/code&gt; and &lt;code&gt;.followAll()&lt;/code&gt; function.
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;State&lt;/code&gt; object is returned when you (for example) call &lt;code&gt;resource.get()&lt;/code&gt;, &lt;code&gt;resource.patch()&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;This object represents an 'Entity' or 'State' returned from the server, which really is a fancy way of saying 'the body' + headers that directly pertain to the body.&lt;/p&gt;

&lt;p&gt;It also provides direct access to hypermedia features such as links and actions. The new addition lets you follow hypermedia links straight from any HTTP response.&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="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;myResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;param1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value1&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="c1"&gt;// If response contained a HAL, Siren, HTML link or HTTP Link header,&lt;/span&gt;
&lt;span class="c1"&gt;// we can follow it!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;follow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;more-info&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;h2&gt;
  
  
  Upgrading
&lt;/h2&gt;

&lt;p&gt;Upgrading should be relatively pain-free for most users, except if you extend Ketting with custom format parsers.&lt;/p&gt;

&lt;p&gt;If you run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i ketting@7
npm i react-ketting@2 # React users only
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And typescript &lt;em&gt;doesn't&lt;/em&gt; complain, chances are that everything will work just&lt;br&gt;
as before.&lt;/p&gt;

&lt;p&gt;Ketting 7 has been in development and used by us in production since January.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future plans
&lt;/h2&gt;

&lt;p&gt;Long-term Ketting plans include&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better documentation and educational resources.&lt;/li&gt;
&lt;li&gt;More React support, including a library of components for automatically rendering Hypermedia Forms/Actions and automatic paging of collections.&lt;/li&gt;
&lt;li&gt;Bindings to other frontend-frameworks.&lt;/li&gt;
&lt;li&gt;An official Websocket add-on, to enable real-time multiuser collaboration and bi-direction state updates.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hypermedia</category>
      <category>rest</category>
      <category>typescript</category>
      <category>react</category>
    </item>
    <item>
      <title>A generic middleware pattern in Typescript</title>
      <dc:creator>Evert Pot</dc:creator>
      <pubDate>Thu, 17 Dec 2020 08:50:21 +0000</pubDate>
      <link>https://dev.to/evert/a-generic-middleware-pattern-in-typescript-1856</link>
      <guid>https://dev.to/evert/a-generic-middleware-pattern-in-typescript-1856</guid>
      <description>&lt;p&gt;I just realized this is the third time I'm writing an async middleware invoker, I thought I would share the generic pattern for the benefit of others.&lt;/p&gt;

&lt;p&gt;I'm not sure if this is interesting enough for a NPM package, so I'll leave it here for inspiration.&lt;/p&gt;

&lt;p&gt;The specific middleware pattern I am implementing is also used &lt;a href="https://curveballjs.org/"&gt;Curveball&lt;/a&gt;. (the one here is just a bit simpler).&lt;/p&gt;

&lt;p&gt;We're working off a &lt;code&gt;context&lt;/code&gt;, and we are running a chain of middlewares in order with this context as an argument.&lt;/p&gt;

&lt;p&gt;We're also passing an &lt;code&gt;next&lt;/code&gt; function. If this &lt;code&gt;next&lt;/code&gt; function is called, the next middleware in the list will be called. If not, the chain will bebroken.&lt;/p&gt;

&lt;p&gt;Furthermore, (unlike Express, but like Koa) middlewares can be &lt;code&gt;async&lt;/code&gt; function or return a promise. If it is, we want to await it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Lets start with the setup, describing the middleware:&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="cm"&gt;/**
 * 'next' function, passed to a middleware
 */&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Next&lt;/span&gt; &lt;span class="o"&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="k"&gt;void&lt;/span&gt; &lt;span class="o"&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="cm"&gt;/**
 * A middleware
 */&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Middleware&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Next&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="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Middleware&lt;/code&gt; is the actual async/non-async middleware function. I made a&lt;br&gt;
type for &lt;code&gt;Next&lt;/code&gt; so I don't need to write it out more than once.&lt;/p&gt;
&lt;h2&gt;
  
  
  How we want to use it
&lt;/h2&gt;

&lt;p&gt;This would be the 'getting started' section of the documentation.&lt;/p&gt;

&lt;p&gt;The idea here is that we have an 'app', a set of middlewares and a context&lt;br&gt;
we want to operate on.&lt;/p&gt;

&lt;p&gt;The following code would be written by the user of this framework:&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="cm"&gt;/**
 * The context type of the application.
 *
 * In 'koa' this object would hold a reference to the 'request' and 'response'
 * But our context just has a single property.
 */&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MyContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;a&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="cm"&gt;/**
 * Creating the application object
 */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MwDispatcher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * A middleware
 */&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Next&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="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * An async middleware
 */&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&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;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Next&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="c1"&gt;// wait 2 seconds&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;next&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;
  
  
  Running this application
&lt;/h2&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="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// should emit 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The implementation
&lt;/h2&gt;

&lt;p&gt;Making this all work is surprisingly terse:&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="cm"&gt;/**
 * A middleware container and invoker
 */&lt;/span&gt; 
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MwDispatcher&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="na"&gt;middlewares&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Middleware&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;constructor&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;middlewares&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * Add a middleware function.
   */&lt;/span&gt;
  &lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="na"&gt;mw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Middleware&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;void&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;middlewares&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;mw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * Execute the chain of middlewares, in the order they were added on a
   * given Context. 
   */&lt;/span&gt;
  &lt;span class="nx"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&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="nx"&gt;invokeMiddlewares&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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;middlewares&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="cm"&gt;/**
 * Helper function for invoking a chain of middlewares on a context.
 */&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;invokeMiddlewares&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&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;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;middlewares&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Middleware&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;middlewares&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;middlewares&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;mw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;invokeMiddlewares&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;middlewares&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&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="p"&gt;})&lt;/span&gt;

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

&lt;/div&gt;



</description>
      <category>middleware</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>curveball</category>
    </item>
    <item>
      <title>HTTP/2 Push is dead</title>
      <dc:creator>Evert Pot</dc:creator>
      <pubDate>Thu, 12 Nov 2020 21:05:31 +0000</pubDate>
      <link>https://dev.to/evert/http-2-push-is-dead-51dh</link>
      <guid>https://dev.to/evert/http-2-push-is-dead-51dh</guid>
      <description>&lt;p&gt;One of the hot features that came with HTTP/2 was PUSH frames. The main idea is that if the server can predict what requests a client might want to make, the server can preemptively send request/response pairs to the client and warm it's cache.&lt;/p&gt;

&lt;p&gt;This is a feature I've been very interested in for a long time. I feel that it can be incredibly useful for APIs to invalidate &amp;amp; warm caches, remove the need for compound requests (which I feel is a &lt;a href="https://apisyouwonthate.com/blog/lets-stop-building-apis-around-a-network-hack"&gt;hack&lt;/a&gt;, although sometimes a&lt;br&gt;
necessary one). &lt;/p&gt;

&lt;p&gt;To help advance this idea, I've worked on a &lt;a href="https://tools.ietf.org/html/draft-pot-prefer-push-00"&gt;Internet Draft&lt;/a&gt; to let API clients tell the server what resources they would like to have pushed, I built a &lt;a href="https://github.com/curveball/core"&gt;Node.js framework&lt;/a&gt; with first-class, deeply integrated Push support, and added support for &lt;code&gt;Prefer-Push&lt;/code&gt; to &lt;a href="https://github.com/badgateway/ketting"&gt;Ketting&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Unfortunately HTTP/2 push always felt like feature that wasn't quite there yet. It's usefulness was stunted due to &lt;a href="https://tools.ietf.org/html/draft-ietf-httpbis-cache-digest-05"&gt;Cache-Digest for HTTP/2&lt;/a&gt; being killed off, and no browser APIs to hook into push events.&lt;/p&gt;

&lt;p&gt;The Chrome team has considered removing Push support since at least 2018. The main reason being that they hadn't really seen the performance benefit for pushing static assets. At the time, I tried to &lt;a href="https://evertpot.com/h2-push-for-apis/"&gt;defend&lt;/a&gt; the feature for the API use-case.&lt;/p&gt;

&lt;p&gt;Yesterday, the Chrome team &lt;a href="https://groups.google.com/a/chromium.org/g/blink-dev/c/K3rYLvmQUBY/m/vOWBKZGoAQAJ?pli=1"&gt;announced&lt;/a&gt; to remove the feature from their HTTP/2 and HTTP/3 protocol implementations.&lt;/p&gt;

&lt;p&gt;I'm a little sad that it never got to its full potential, but with this step, I no longer think it's worthwhile to invest in this feature. So I'm ceasing my work on &lt;code&gt;Prefer-Push&lt;/code&gt;, and will also remove support from the next major Ketting version.&lt;/p&gt;

&lt;p&gt;On a positive note, I spent a lot of time thinking and working on this, but it is sometimes nice to just be able to close a chapter, rather than to wait and let it sizzle out. It's not an ideal conclusion, but it's a conclusion&lt;br&gt;
nonetheless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current alternatives
&lt;/h2&gt;

&lt;p&gt;Lacking server-driver push, we're back to many small HTTP request, or compound requests. This means you either have the N+1 problem, or (in the case of compound requests) poor integration with HTTP caches. &lt;a href="https://evertpot.com/h2-parallelism/"&gt;More on this here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you're going the 'compound request' route, there is a draft of a similar header as &lt;code&gt;Prefer-Push&lt;/code&gt;; &lt;a href="https://evertpot.com/http/103-early-hints"&gt;&lt;code&gt;Prefer: transclude&lt;/code&gt;&lt;/a&gt;, which Ketting also supports.&lt;/p&gt;

&lt;p&gt;A feature that I hoped would work well in the future with Server Push was server-initiated cache invalidation. We never quite got that. To work around this, we use Websockets and will keep doing this for the forseeable future.&lt;/p&gt;

&lt;p&gt;To reduce general latency of fetching many things, the &lt;a href="https://evertpot.com/http/103-early-hints"&gt;&lt;code&gt;103 Early Hints&lt;/code&gt;&lt;/a&gt; can help, although this is not supported &lt;em&gt;yet&lt;/em&gt; in Chrome, and this is also only really useful for speeding up delivery of assets like images, css and&lt;br&gt;
Javascript as there's no way to hook into 1xx responses programmatically in a browser.&lt;/p&gt;

</description>
      <category>http</category>
      <category>http2</category>
      <category>push</category>
      <category>chrome</category>
    </item>
    <item>
      <title>Apollo-like hooks for REST APIs with React and Ketting</title>
      <dc:creator>Evert Pot</dc:creator>
      <pubDate>Sat, 03 Oct 2020 20:46:09 +0000</pubDate>
      <link>https://dev.to/evert/using-rest-apis-with-react-and-ketting-5hl7</link>
      <guid>https://dev.to/evert/using-rest-apis-with-react-and-ketting-5hl7</guid>
      <description>&lt;p&gt;A bit ago we released &lt;a href="https://github.com/badgateway/ketting/"&gt;Ketting 6&lt;/a&gt;. This is the accumulation of about a year of learning on how to better integrate REST APIs with frontend frameworks, in particular React.&lt;/p&gt;

&lt;p&gt;It's packed with new features such as local state management, new caching strategies, (client-side) middleware support and change events. It's also the first release that has some larger BC breaks to make this all work.&lt;/p&gt;

&lt;p&gt;Releasing Ketting 6 is a big personal milestone for me, and I'm really excited to unleash it to the world and see what people do with. A big thank you to all the people that beta tested this in the last several months!&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Ketting?
&lt;/h2&gt;

&lt;p&gt;In short: Ketting is a generic REST client for Javascript. You can use it for pushing JSON objects via HTTP, but the richer your API is in terms of best practices and standard formats, the more it can automatically do for you.&lt;/p&gt;

&lt;p&gt;It has support for Hypermedia formats such as HAL, Siren, Collection+JSON, JSON:API and can even understand and follow links from HTML.&lt;/p&gt;

&lt;p&gt;It's often said that REST (and Hypermedia APIs) is lacking a good generic client. GraphQL has a lot of advantages, but a major one is tooling. Ketting aims to close that gap.&lt;/p&gt;

&lt;p&gt;More information can be found on &lt;a href="https://github.com/badgateway/ketting/"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  React support in Ketting 6
&lt;/h2&gt;

&lt;p&gt;Ketting now has a separate &lt;a href="https://github.com/badgateway/react-ketting"&gt;react-ketting&lt;/a&gt; package that provides React bindings to Ketting. These bindings should look very familiar if you've used &lt;a href="https://www.apollographql.com/docs/react/"&gt;Apollo Client&lt;/a&gt; in the past.&lt;/p&gt;

&lt;p&gt;Lets dive into an example:&lt;/p&gt;

&lt;p&gt;Lets assume you have a REST api that has an 'article' endpoint. This returns something like:&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;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello world"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;This article is retrieved with &lt;code&gt;GET&lt;/code&gt;, and updated with &lt;code&gt;PUT&lt;/code&gt;, this is how you would display it:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useResource&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;react-ketting&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;function&lt;/span&gt; &lt;span class="nx"&gt;Article&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loading&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="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example/article/5&lt;/span&gt;&lt;span class="dl"&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;loading&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&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="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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&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;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&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;data&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/article&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what about mutations? Unlike GraphQL, mutations in REST APIs often have the same format for &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;PUT&lt;/code&gt;, so sending an updated resource to a server often just means mutating your 'data' and sending it back.&lt;/p&gt;

&lt;p&gt;The following example would allow a user to edit an article and send it back:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useResource&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;react-ketting&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;function&lt;/span&gt; &lt;span class="nx"&gt;Article&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loading&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;submit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
    &lt;span class="nx"&gt;useResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example/article/5&lt;/span&gt;&lt;span class="dl"&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;loading&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&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="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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&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;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&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;changeTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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;changeBody&lt;/span&gt; &lt;span class="o"&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onsubmit&lt;/span&gt;&lt;span class="o"&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="nx"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;changeTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;textarea&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;changeBody&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/textarea&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Save&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever &lt;code&gt;setData&lt;/code&gt; is called, the internal Ketting cache is updated with the new resource state. This is globally stored, based on the uri of the resource.&lt;/p&gt;

&lt;p&gt;This means that if multiple components use &lt;code&gt;useResource&lt;/code&gt; on that same uri, every component will see that update and triggere a re-render.&lt;/p&gt;

&lt;p&gt;This is similar to Apollo's local state, except it's still bound to a single resource uri and can eventually be saved.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;submit()&lt;/code&gt; is called, the &lt;code&gt;data&lt;/code&gt; is re-serialized and sent in a &lt;code&gt;PUT&lt;/code&gt; request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Non-exhaustive list of other changes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Multiple cache strategies, such as forever, short and never.&lt;/li&gt;
&lt;li&gt;Support for fetch-middlewares. OAuth2 is reimplemented as such a plugin. These plugins can be added globally, or per-origin.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get()&lt;/code&gt; now returns a &lt;code&gt;State&lt;/code&gt; object, and functions such as &lt;code&gt;put()&lt;/code&gt; will require one as an argument.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;put()&lt;/code&gt; now automatically updates the state cache.&lt;/li&gt;
&lt;li&gt;Support for HEAD requests and following links from HEAD response headers.&lt;/li&gt;
&lt;li&gt;PKCE support for OAuth2.&lt;/li&gt;
&lt;li&gt;Links can now be mutated and sent back to the server.&lt;/li&gt;
&lt;li&gt;Nested transcluded items/embeds.&lt;/li&gt;
&lt;li&gt;A separate &lt;code&gt;post()&lt;/code&gt; and &lt;code&gt;postFollow()&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Better support for binary responses and &lt;code&gt;text/*&lt;/code&gt; responses.&lt;/li&gt;
&lt;li&gt;Experimental: Support for Siren actions, HAL forms and submitting HTML forms.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Future plans
&lt;/h2&gt;

&lt;p&gt;The next two things we are working on are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for more hooks/components for common React/REST API patterns (tell us what you want!).&lt;/li&gt;
&lt;li&gt;Deeper support for forms and actions from HAL Forms, Siren and HTML.&lt;/li&gt;
&lt;li&gt;Websocket support for live server-initiated state pushes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  More links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The documentation got a complete rewrite and is now hosted on the &lt;a href="https://github.com/badgateway/ketting/wiki"&gt;Github Wiki&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For a full list of changes and BC breaks, check out the &lt;a href="https://github.com/badgateway/ketting/wiki/Upgrading"&gt;Upgrading&lt;/a&gt; page.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ketting</category>
      <category>rest</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>ECMAScript 4: The missing version</title>
      <dc:creator>Evert Pot</dc:creator>
      <pubDate>Thu, 28 May 2020 09:41:38 +0000</pubDate>
      <link>https://dev.to/evert/ecmascript-4-the-missing-version-11e1</link>
      <guid>https://dev.to/evert/ecmascript-4-the-missing-version-11e1</guid>
      <description>&lt;p&gt;In your build tools, you may have noticed that you have an ECMAScript target, and 5 and up, but never a 4. Why is that?&lt;/p&gt;

&lt;p&gt;I thought it would be fun to dive into ECMAScript 4 a bit and see what we didn't get.&lt;/p&gt;

&lt;h2&gt;
  
  
  A brief history
&lt;/h2&gt;

&lt;p&gt;According to &lt;a href="https://en.wikipedia.org/wiki/ECMAScript#4th_Edition_(abandoned)"&gt;Wikipedia&lt;/a&gt;, the first draft of ECMAScript 4 was dated February 1999. The original target for completion was August 2008.&lt;/p&gt;

&lt;p&gt;ECMAScript 4 was very ambitious, and added a ton of features that were&lt;br&gt;
perceived as important and missing from ECMAScript 3. It also 'fixed' a&lt;br&gt;
number of things in the previous version, making it backwards incompatible in various ways.&lt;/p&gt;

&lt;p&gt;ES4 was met with a bunch of controversies, and lacked sufficient support from browser vendors to be released and was ultimately abandoned.&lt;/p&gt;

&lt;p&gt;In 2008 the standard was pronounced dead, and ES3.1 was renamed to ES5, which was a much more conservative and incremental update to ECMAScript.&lt;/p&gt;

&lt;p&gt;The closest thing we had for ES4, was probably Flash ActionScript 3. There was a point during the release of AS3 that some of us thought that Flash and the Web was eventually going to converge.&lt;/p&gt;

&lt;p&gt;For more details on politics and history of ES4, check out &lt;a href="https://auth0.com/blog/the-real-story-behind-es4/"&gt;this great article&lt;/a&gt; on the auth0 blog.&lt;/p&gt;
&lt;h2&gt;
  
  
  What could have been?
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Classes
&lt;/h3&gt;

&lt;p&gt;Classes eventually landed in ES6, but here's how it might have looked like earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight actionscript"&gt;&lt;code&gt;&lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;C&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

 &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;
 &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

 &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.14&lt;/span&gt;

 &lt;span class="c1"&gt;// A function&lt;/span&gt;
 &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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="nx"&gt;n&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="c1"&gt;// Getters and setters&lt;/span&gt;
 &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="kr"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;foo&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="nx"&gt;val&lt;/span&gt;&lt;span class="o"&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;The syntax here is pretty different, but another notable is that these classes had properties and constants. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Public_class_fields"&gt;Field declarations&lt;/a&gt; are currently 'experimental', so we almost caught up here.&lt;/p&gt;

&lt;p&gt;Another surprising thing is that there is no &lt;code&gt;this&lt;/code&gt;. Instead of variables being global by default, ES4 would first look in the class scope before checking higher scopes.&lt;/p&gt;

&lt;p&gt;ES4 also had the following keywords for class members:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;static&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;final&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;private&lt;/code&gt;, &lt;code&gt;protected&lt;/code&gt;, &lt;code&gt;public&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prototype&lt;/code&gt;, to define class members on its prototype. Not sure what the use-case is, but it's there.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Interfaces
&lt;/h3&gt;

&lt;p&gt;ES4 introduced interfaces, which is something we don't have today (unless you use Typescript):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight actionscript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;MyInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Strict typing
&lt;/h3&gt;

&lt;p&gt;ES4 introduced strict typing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight actionscript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also had the &lt;code&gt;type&lt;/code&gt; keyword similar to Typescript and union types. A typescript union like the following:&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;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Is written as follows in ES4:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight actionscript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ES4 also had generics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight actionscript"&gt;&lt;code&gt;&lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Wrapper&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Like 👍
&lt;/h3&gt;

&lt;p&gt;By default types in ES4 had to be exact types, and not a superset. Using the &lt;code&gt;like&lt;/code&gt; keyword you can make this less restrictive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight actionscript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;like&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&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 probably exists because in ES4 types were Nominal and not Structural like&lt;br&gt;
Typescript.&lt;/p&gt;
&lt;h3&gt;
  
  
  New types
&lt;/h3&gt;

&lt;p&gt;In current ES we have booleans, objects, arrays, number, BigInt, but ES4 was going to introduce:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;byte&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;int&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;double&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;decimal&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of those, only the decimal type is in the planning today, and it will eventually probably look like:&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="nx"&gt;allowance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.50&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;m&lt;/code&gt; suffix also existed in ES4, and stands for "money".&lt;/p&gt;

&lt;h3&gt;
  
  
  triple-quoted strings.
&lt;/h3&gt;

&lt;p&gt;To encode a string like: &lt;code&gt;Hello my name is "Evert"&lt;/code&gt; in ES4, you could use triple-quotes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight actionscript"&gt;&lt;code&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"""Hello my name is "&lt;/span&gt;&lt;span class="nx"&gt;Evert&lt;/span&gt;&lt;span class="s2"&gt;""""&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Packages
&lt;/h3&gt;

&lt;p&gt;Packages are a bit like what we have now with modules. Packages can be&lt;br&gt;
imported, but unlike ES6 modules, namespaces are more like a global naming system.&lt;/p&gt;

&lt;p&gt;If a class is defined as :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight actionscript"&gt;&lt;code&gt;&lt;span class="kr"&gt;package&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;evertpot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// Private&lt;/span&gt;
  &lt;span class="kr"&gt;internal&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyClass&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;Then you could use this class as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight actionscript"&gt;&lt;code&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;evertpot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight actionscript"&gt;&lt;code&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;evertpot&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As far as I know the standard doesn't define a relationship between namespaces and where the files can be loaded from.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generic functions
&lt;/h3&gt;

&lt;p&gt;Generic functions are not parameterized functions, they resemble&lt;br&gt;
&lt;a href="https://www.typescriptlang.org/docs/handbook/functions.html"&gt;"Overloaded functions"&lt;/a&gt; in typescript a bit, but they're not quite the same and much more powerful.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight actionscript"&gt;&lt;code&gt;&lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Foo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


  &lt;span class="nx"&gt;generic&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;int&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;function&lt;/span&gt; &lt;span class="nx"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, I can call &lt;code&gt;addItem&lt;/code&gt; with either a &lt;code&gt;int&lt;/code&gt; or &lt;code&gt;number&lt;/code&gt;, and the correct implementation will be picked at run-time.&lt;/p&gt;

&lt;h3&gt;
  
  
  E4X
&lt;/h3&gt;

&lt;p&gt;While E4X was technically an extension to ES4, I think it deserves a mention.&lt;/p&gt;

&lt;p&gt;E4X stands for ECMAScript for XML, and while that might not sound very exciting, take a look at a code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;welcome&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Evert&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;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;myClass&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks familiar?&lt;/p&gt;

&lt;p&gt;Although not quite the same as &lt;a href="https://reactjs.org/docs/introducing-jsx.htm://reactjs.org/docs/introducing-jsx.html"&gt;JSX&lt;/a&gt;, it's becoming clear that this might have been a part of JSX's origin story.&lt;/p&gt;

&lt;p&gt;While ES4 never landed, E4X actually worked in Firefox, until it was removed in Firefox 10.&lt;/p&gt;

&lt;h3&gt;
  
  
  More features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;let const&lt;/code&gt; as a syntax for block-level constants. In ES5 and up &lt;code&gt;const&lt;/code&gt; is
already block-scope.&lt;/li&gt;
&lt;li&gt;Generators (&lt;code&gt;yield&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Tail-calls&lt;/li&gt;
&lt;li&gt;Namespaced properties, classes and everything to avoid collisions, much like XML namespaces.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How would you load it?
&lt;/h2&gt;

&lt;p&gt;Because Ecmascript 4 would break backwards compatibility, it would be important to tell a browser to interpret a script as ES4:&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;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript;version=4"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not unlike what we do with modules today:&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;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Afterword
&lt;/h2&gt;

&lt;p&gt;I hope this was an interesting view in the Javascript that could have been. Although we are slowly catching up with newer ECMAScript versions and tools like Typescript and JSX preprocessors, we're still not quite at 2007's vision for ECMAScript.&lt;/p&gt;

&lt;p&gt;Perhaps if ES4 landed, fewer people would need complex build tools like Babel, Webpack and Typescript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://auth0.com/blog/the-real-story-behind-es4/"&gt;The Real Story Behind ECMAScript 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ecma-international.org/activities/Languages/Language%20overview.pdf"&gt;Proposed ECMAScript 4th Edition – Language Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/ECMAScript_for_XML"&gt;Wikipedia: ECMAScript for XML&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>ecmascript</category>
      <category>actionscript</category>
      <category>jsx</category>
    </item>
  </channel>
</rss>
