Skip to main content

(Don't) be smart and use web standards

29 min read

As this is quite a lengthy article, let's begin with a quick summary:

  • Using web standards can help you make decisions;
  • Smarter people than myself have thought of various ways to use the world wide web, including edge cases and other considerations;
  • There exists a proposal for anything you can think of;
  • The web wasn't built for the browser;
  • You use web standards.

Are you a front-end developer who wants to know more about the internet or the world wide web? Are you a full-stack developer (in whatever capacity, or meaning of this term) and do you want to know more about web standards? Are you an architect or back-end developer and require aid designing a (web-based) API (application programming interface)?

If you said yes to at least one of those questions, or if this subject has sparked your interest, keep on reading!

  1. What is the world wide web?
    1. HTTP
    2. Hypertext, hyperlinks, hypermedia
    3. HTML
    4. ...what about other media?
    5. Mediatype
    6. Registering a media type?
  2. Request for Comments (RFC)
    1. RFC for everything
    2. RFC for anything
      1. RFC 1121
      2. RFC 1925
      3. RFC 2119
  3. What gives? How does this help me?
    1. HTTP: the why?
    2. Inventing the wheel
    3. How do I prevent re-inventing the wheel?
  4. Webstandards for web developers
  5. Join the development of our www
  6. Final words

What is the World Wide Web?

To be able to talk about web standards, it's good to first define what the web is and consists of, including some elaborations.

HTTP

HTTP is short for Hypertext Transfer Protocol.

A protocol is generally a collection of rules to achieve some goal. In this case we're dealing with a communication and transfer protocol, and it describes the syntax, semantics, error handling and correction, as well as synchronization to accomplish the following:

"...where hypertext documents include hyperlinks to other resources that the user can easily access."

Wikipedia

"Hyper-" from the Greek prefix "ὑπερ-", which means over or beyond, as in exceeding.

  • Hypertext is digitally displayable text, with references (yes, the hyperlinks) to other (hyper)text, which can be accessed directly by a user.
  • Hyperlink is a link (a reference) that grants a user access to the data at the other end of that link (referred data).
  • Hypermedia is an extension of the hypertext term and describes non-lineair (digital) media both including plain text and hyperlinks, as well as images, audio, and video.

An example of hypermedia is the World Wide Web!

HTML

HTML is short for HyperText Markup Language.

It follows that hypertext doesn't equal HTML. Instead, this language is a way to mark up hypertext in such a way that the data (the text, and when we talk about hypermedia also the other types of content) can be displayed or referenced (using hyperlinks).

The HTML standard is meant to describe how to annotate documents so a browser may display it. It's a way to make hypertext interactive. Thus, the web browser is a tool to follow hyperlinks, which we know as browsing the web.

HTTP aids transferring HTML documents, as it's the Hypertext Transfer Protocol for documents written in Hypertext Markup Language.

...what about other media?

When you're browsing the web, you'll often run into content that's not just text or text-based — plain or styled — but rather things such as images, audio, video, and other non-textual content.

The smart humans that brought HTTP to life (and continued developing it) also came up with a smart way to allow HTTP to send more than just hypertext and hypertext-based documents. The way they accomplished this is by using metadata which is sent along with the content requested.

In order to support other (types of) media, HTTP commonly uses a Media type (MIME TYPE).

Mediatype

The data format of a representation is known as a media type [...]

On the web we technically talk about representations of resources. The format of such a representation (meaning the syntax, the rules, the usage, the constraints, etc.) are commonly known as a media type.

Some well known examples of media types are:

  • text/html
  • image/png
  • application/json

There are rules about the syntax and usage of these media types. Together we came up with and agreed on how specific binary data can be interpreted (read) or arranged (written). A PNG image is a PNG image if we interpret the binary data as a PNG. How that would and should work for PNGs is written down and accepted as a standard, after which it was (publicly) registered.

Registering a media type?

Here are another three examples of media types:

  • application/vnd.ms-powerpoint
  • application/graphql
  • application/vnd.xpbytes.errors.v1+json

The first one describes Microsoft Powerpoint files. The second one used to be the (defacto) standard way to desrcibe GraphQL queries and responses. The last one is one out of many vendor (vnd) specific media types that we use at work to describe error messages.

There exists a document (and standard) that defines and explains how to register a media type: RFC 6838: Media Type Specifications and Registration Procedures

"This document defines procedures for the specification and registration of media types for use in HTTP, MIME, and other Internet protocols."

The goal of registering a media type is to make it accessible for other to use on the interwebs, and so that we may agree on how data can be interpreted or arranged. Whilst it's not strictly mandatory to register media types starting with vnd., it will aid in the process of writing, sanitizing, iterating, and improving a media type specification.

For media types outside of the vnd. (vendor) and prs. (personal) trees — in other words: media types that don't start with that prefix — registration is mandatory. It's not a media type until it's officially been registered.

Request for Comments (RFC)

That last document linked to register a media type is called an RFC: a request for comments. It is a publication of a technical document that has the goal of describing a new standard or altering an existing standard (which proliferates into a new standard because of the changes).

XKCD 927: Standards. Comic with three panels. Heading above the panels: "How standards proliferate (see: A/C chargers, character encodings, instant messaging, etc.)". First panel: "Situation: there are 14 competing standards". Second panel: In speech bubbles: "14?! Ridiculous! We need to develop one universal standard that covers everyone's use cases.". The response: "Yeah!". Third panel: "Soon: Situation. There are 15 competing standards."

It's commonly the Internet Engineering Task Force (IETF) that publishes such documents. It's this task force that will ultimately decide if a distributed proposal after receiving commentary will be published as internet (web) standard.

And my oh my... there literally exists an RFC for almost every single thing you can think of.

RFC for everything

As mentioned, media types are standards, and these exist as published RFCs. Example are:

Incredibly helpful, because if you want to know if something is possible or allowed, how to accomplish it, and what the rules are, you can inspect these documents and almost always retrieve the answer.

With "for everything" I did really mean everything.

How plain text is defined and how to work with it can be found in RFC 822, which was written before the internet existed but rather was called ARPANET. How to transfer text using the internet (utilizing HTTP) is defined in RFC 1521, but HTTP itself is also published in various RFCs, including:

RFC for anything

That many technical aspects have been documented and published in RFC (and often have been accepted as Web Standard) may not be unexpected. However, when I was hinting at the fact that there is an RFC for everything, I really did mean anything. So to continue down this rabbit hole, here are three more examples.

RFC 1121

This RFC presents a collection of poems that were presented at "Act One", a symposium held partially in celebration of the 20th anniversary of the ARPANET.

RFC 1925

This memo documents the fundamental truths of networking for the Internet community.

[...]

The Fundamental Truths

(1) It Has To Work.

[...]

(3) With sufficient thrust, pigs fly just fine.

RFC 2119

We've even defined how to talk about standards in RFCs.

The one that's referred to the most is RFC 2119: Key words for use in RFCs to Indicate Requirement Levels:

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

There are narrow definitions for the aforementioned keywords, and knowing those definitions will with both writing and reading RFC, and subsequently any Web Standard.

What gives? How does this help me?

Let's start with the question: Who was HTTP meant for. You've read the word user several times, without a definition Laten we beginnen met de vraag: Voor wie is HTTP bedoeld?. Je hebt het woord gebruiker een aantal maal gelezen, zonder dat ik heb gedefinieerd wie of wat een gebruiker is. Wat is dat, een gebruiker?

Het antwoord hierop kunnen we terug vinden in RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1:

[...] used as a generic protocol for communication between user agents [...]

Eerst wordt beschreven waarvoor HTTP kan worden gebruikt. En verderop staat de definitie:

user agent The client which initiates a request.

These are often browsers, editors, spiders (web-traversing robots), or other end user tools.

Hieruit volgt dat de HTTP standaard niet alleen bedoeld is voor mensen, en ook niet alleen voor browsers.

HTTP: waar is het voor?

Als het protocol niet alleen voor browsers of eind-gebruikers is, dan is er meer aan de hand. Deze standaard wil ons helpen meer te bereiken dan alleen hypertext en andere hypermedia over de netwerkkabel versturen naar onze computerschermen.

We hoeven niet lang te zoeken om erachter te komen welke problemen HTTP probeert te verhelpen of hoe het probeert te faciliteren. Dit artikel is niet de plek om in elke een diepe duik te nemen, maar weet dat er meer is dan de lijst die nu volgt. Slimme mensen hebben bekeken wat de moeilijkheden zijn bij communicatie over het internet, en welke uitdagingen er liggen op om te lossen. HTTP is het resultaat.

HTTP is de oplossing voor zogenoemde hard problems

  • Caching (veel user agents, één server);
  • Consistentie (data format, fouten, en het scheiden van data en fouten);
  • Interoperabiliteit (tussen verschillende implementaties);
  • (en meer).

Het wiel uitvinden

Het is bij veel mensen bekend dat het over het algemeen een heel slecht idee is om zelf een versleuteling te verzinnen voor zaken die echt privé moeten worden. We zeggen dan ook wel "Don't roll your own Encryption/Cryptography/Security". Op de security stackexchange zijn verschillende vragen te vinden over dit wel doen of waarom je dit niet doet en één van de beste antwoorden vind ik:

If you are not convinced of "Don't Roll Your Own [Cryptography/Security]", then you probably are not an expert and there are many mistakes you likely will make.

dr jimbob on security.stackexchange.com

"Als je er niet van overtuigd bent dat het zelf verzinnen van een manier om te versleutelen of te beveiligen, dan ben je waarschijnlijk geen expert en zullen er veel fouten zijn die je gaat maken."

Hoe relateert dat tot een webstandaard?

Je hebt wellicht weleens de uitdrukking "there's a package for that" of "there's a gem for that" gehoord. Hetzelfde is bijna altijd waar voor meer abstracte problemen: "there's a spec for that". Zelfs als er geen spec is, dan is er vaak wel een proposal of een draft. Dit betekent daardoor ook dat het onnodig is om het wiel uit te moeten vinden. Er is al iemand of een groep mensen geweest die over je probleem heeft nagedacht, en daar (hopelijk) wat slimme dingen over heeft opgeschreven.

En als je er toch voor kiest om zelf iets te verzinnen, dan kan je of leren van wat er al is, of je informatie opschrijven in een RFC formaat zodat anderen je standaard kunnen gebruiken. Dit maakt het weer makkelijker.

En als je met front-end (of back-end, of wat dan ook) te maken hebt, dan gebruik je elke dag al webstandaarden!

Hoe voorkom ik dat het wiel opnieuw wordt uitgevonden?

Er is helaas geen makkelijk antwoord op deze vraag, omdat je eigenlijk moet weten of inschatten of er voor iets een standaard bestaat. Het moment dat ik zelf kijk of er een standaard bestaat is tweevoudig: iets voelt tegendraads (moeilijker dan nodig), of iets klinkt complex.

Een aantal voorbeelden die hopelijk een tipje van de sluier kunnen oplichten:

a. Interactie toevoegen aan HTML elementen.

Ook ik heb voorheen gebruik gemaakt van onclick="" attributen of het equivalent in JavaScript. Ik leerde daarna over het web gebruiken zonder muis (en ben zelf een veel-gebruiker van toetsenbord navigatie geworden), en om dan een "knop" klikbaar te maken is best wel wat extra JavaScript nodig. In de laatste jaren ben ik veel bezig geweest met toegankelijkheid. Om screenreaders een div te laten herkennen als knop, heb je nog meer code en markup nodig. Oef.

<!-- iets toegankelijker dan onclick="" -->
<div class="button" role="button" aria-pressed="false" tabindex="0">
  My action
</div>

<script>
  // [...]
  myActionElement.addEventListener('keydown', (e) => {
    if (e.key === ' ' || e.key === 'Enter' || e.key === 'Spacebar') {
      e.target.setAttribute('aria-pressed', 'true');
    }
  });

  // [...] up handler om te activeren als ie pressed was
  // [...] blur handler om pressed weer weg te halen zonder activatie
  // [...] disabled implementatie via aria-disabled
</script>

De HTML standaard heeft een aantal hulpmiddelen om HTML interactief te maken, waaronder het button element. Dit element heeft ondersteuning voor allerlei manieren van interactie. Volgens de MDN (Mozilla Developer Network) beschrijving is het button element een interactief element geactiveerd door een gebruiker met een muis, toetsenbord, vinger, spraakcommando, of andere toegankelijkheidtechnologie.

Daarnaast kan de actie ook worden geblokkeerd door het disabled attribuut te gebruiken, heeft het standaard een kenmerkende rol (namelijk button), is deze standaard focusbaar zonder tabindex en is geen custom CSS nodig om het er als een knop uit te laten zien.

Voordat ik een div gebruik is mijn regel dus: ben bekend met de huidig gangbare HTML elementen en hun doel.

b. Veel gebruikers aankunnen met weinig serverkracht

Ik heb gewerkt aan meerdere producten die dagelijks honderden, duizenden, of zelfs miljoenen gebruikers hadden. Servers zijn kostbaar, bandbreedte in the cloud al helemaal, en het aantal gebruikers is niet consistent.

Dit is een moeilijke uitdaging.

Als je zoekt hoe je het consistentie probleem kan oplossen kom je al gauw terecht op een techniek die auto-scaling heet: het semi-automatisch op en afschalen van servers om meer gebruikers tegelijk aan te kunnen wanneer het nodig is, en minder servers online te hebben wanneer dat niet nodig is. Als je iets langer doorzoekt zie je ook dat auto-scaling op zichzelf ontzettend moeilijk is om goed te doen. Bijvoorbeeld: wat zijn goede regels voor het op-en- afschalen? Wat is het limiet? Hoe ga je om met het langzaam opstarten van de servers (waardoor de regel om bij te schalen actief blijft)? De antwoorden variëren van "it depends" tot "thoughts and prayers".

Nee, er moest een betere (en vooral stabielere) manier zijn om meer gebruikers aan te kunnen zonder dat dat heel veel geld kost.

Onze applicatie had meer gebruikers die pagina's wilden lezen dan bewerken. In HTTP termen, het meest voorkomende werkwoord was GET. Dat biedt mogelijkheden, want hoewel sommige pagina's gebruiker specifieke informatie bevatte, het meeste van de inhoud, en vooral ook de website voor het inloggen was voor iedereen hetzelfde. Ik had al vaker gebruik gemaakt van een Content Delivery Network (CDN) om media (plaatjes, videos, enzovoorts) sneller bij de bezoeker te brengen, waaronder Cloudflare. Amazon Web Services (AWS) heeft een eigen variant genaamd CloudFront, en zo zijn er nog velen. Wellicht kond ik hier gebruik van maken.

Alle CDNs hebben een variant van caching: het tijdelijk opslaan van informatie zodat je deze informatie niet opnieuw hoeft te berekenen of op te halen bij een opvolgend verzoek. Hoewel ze allemaal hun eigen implementatie hebben, ze ondersteunen (bijna) allemaal een gestandaardiseerde vorm: HTTP Caching. (Dit heet vaak Origin Cache Control mocht je het zoeken in jouw CDN). Het MDN artikel hierover beschrijf veel van de opties, maar hier zijn er een aantal die wij gebruikten om de CDNs onze inhoud te laten cachen:

# Je mag de pagina echt niet cachen. Ook niet in de browser. Elk
# verzoek moet een nieuw antwoord genereren en tonen.

Cache-Control: no-store
# Bewaar dit voor 1 jaar in de cache.  Dit wordt gebruikt voor
# bestanden met een hash / versie "identifier" die veranderd
# als het bestand wordt bijgewerkt, waardoor er een nieuwe
# url is.
#
# immutable zorgt ervoor dat browsers niet meer proberen
# conditionele verzoeken te doen om te kijken of de URL toch
# is bijgewerkt.
#
# public zorgt ervoor dat een verzoek's antwoord kan worden
# gedeeld. Oftewel: als iemand anders dit verzoek al heeft
# gedaan, dat kan dat gecachede antwoord worden gebruikt.

Cache-Control: public, max-age=31536000, immutable
# Bewaar dit voor 5 minuten, en markeer het daarna als muf.
# Dit wordt gebruikt voor paginas die niet elke seconde
# nieuwe informatie moeten laten zien, en waarbij het
# belangrijker is om wat oudere informatie te laten zien
# dan dat je niets laat zien.
#
# Dit is vaak waar, voor heel veel informatie op het
# internet!
#
# Gebruik het muffe opgeslagen antwoord nog maximaal 60
# seconden terwijl je op de achtergrond een vers antwoord
# ophaald. Gebruik het muffe opgeslagen antwoord nog een
# uur, als er een foutmelding is gegeneerd bij het ophalen.
#
Cache-Control: private, max-age=300, stale-while-revalidate=60, stale-if-error=3600

Ik kwam er ook achter dat sommige implementaties van HTTP Caching niet spec-compliant zijn. Ofwel: ze volgen niet de standaard. Cloudflare, bijvoorbeeld, respecteerd de Vary header niet. Omdat ik wist dat er een standaard was en konden lezen wat de implicaties waren van het niet respecteren van deze header, hebb ik bewuste keuzes kunnen maken.

Noot: Ga niet overal caching headers toevoegen. Vooral het gebruik van max-age op paginas die worden bijgewerkt kan problemen opleveren als je niet oplet dat dat verwijzingen naar oudere inhoud (zoals CSS en JavaScript bestanden) nog steeds werken tijdens "de max-age" periode. Jake Archibald heeft mooie dingen geschreven over HTTP Caching. Lees dus eerst verder, maar sla je slag!

Oh en die performance? Bedenk je dat als je public, max-age=60 toevoegt wat voor effect dat kan hebben op het aantal bezoekers op de server:

Situatie Bezoekers per minuut Verzoeken per minuut
Geen caching 1000 1000
max-age=5 1000 ~12
max-age=60 1000 ~1

Zelfs voor privé content die gemarkeerd was als must-revalidate (je moet de server vragen om te kijken of wat je in de cache hebt fris is of verouderd is), met een max-age=0 (het antwoord is voor 0 seconden vers, en daarna muf), kan helpen. Als de server namelijk aangeeft dat wat de cache heeft nog steeds hetzelfde is (door middel van bijvoorbeeld een ETag vergelijking) dan bespaar je nog steeds alle bandbreedte en tijd die het kost om die data te versturen en ontvangen.

Voordat ik dus een moeilijk uitdaging zelf probeer op te lossen kijk ik eerst of er een standaard voor bestaat. In dit geval was de oplossing die afdoende werkte de HTTP Caching standaard.

c. Oude software accepteren terwijl de API (veel) is veranderd

Dit is niet een frontend punt, maar full-stackers die bezig zijn met APIs schrijven of bedenken, kunnen hier wellicht ook iets aan hebben.

Het probleem is als volgt:

Ik schreef mee aan een systeem dat aan de server kant een API publiek beschikbaar stelde en die werd aangeroepen door allerlei andere systemen, waaronder een mobiele SDK (Software Development Kit). Zo'n SDK wordt dan onderdeel van één of meerdere apps en die apps worden gedistribueerd, meestal via de Google Play Store en Apple iTunes store. Dit betekent dat als er een wijziging nodig is in de API (in de server code), dat deze wijziging moet worden doorgevoerd in de SDK. De SDK update moet dan worden doorgevoerd in alle apps, en deze apps moeten worden gepubliceerd. Tot slot moeten de mensen die de app hebben geïnstalleerd de app bijwerken.

In andere woorden: je hebt een probleem, ofwel een moeilijke uitdaging!

Roy Fielding, is een ontzettend slim persoon die heeft meegewerkt aan onder andere URI Templates, en was ook editor van de "Do No Track" working group. In 2013 zei Roy tijdens een talk dat de best practice voor het hanteren van een versie in een API is om geen versie te hanteren voor de gehele API. Ja, nou en, denk je misschien? Roy schreef zijn dissertatie over Architectuur stijlen en het ontwerp van netwerk-gebaseerde software architectuur. Wij kennen dit nu als REST (Representational State Transfer) en dat is eigenlijk de ruggengraat geworden van ontzettend veel moderne web interfaces.

Het leuke voor mij is dat Roy een vervolg heeft geschreven op zijn visie van REST, en dat heeft gepubliceerd als, jawel, een RFC, die is aangenomen als current best practice.

Ik zal niet teveel in details treden wat we hier allemaal van hebben gebruikt om ons probleem op te lossen, want dat is meerdere artikelen an sich, maar het komt samengevat neer op:

  • Gebruik versies in media types (dus application/vnd.fronteers.config.v1+json);
  • Doe aan content-negotiation: een tactiek waarbij de server kijkt naar de Accept header van het verzoek en gebaseerd daarop een antwoord geeft met desbetreffende Content-Type header;
  • Valideer antwoorden van de server in de server, en geef een foutmelding als het antwoord niet overeenkomt met een contract. In andere woorden: bepaal van te voren hoe een antwoord met een bepaalde Content-Type er uit gaat zien en forceer dat gedrag;
  • Ondersteun zo lang mogelijk een media type. Het is bijna altijd dezelfde informatie net iets anders gerepresenteerd, dus dit is vaak goedkoop om te doen. Je hoeft namelijk de code voor de oudere versies bijna nooit aan te raken.

Om deze interessante uitdaging op te lossen kon ik dus gebruik maken van het denk werk van meerdere slimmen mensen (iedereen die heeft bijgedragen aan de RFC die uiteindelijk best practice werd) hetgeen er ook toe heeft geleid dat ik nu, vijf jaar later, nog steeds apps kan ondersteunen die versie 1 draaien van de API. Daarnaast konden de mobiele app developers gradueel upgraden: ze konden voor elk verzoek bepalen of ze het nieuwe gedrag wilden ondersteunen door met de Accept en Content-Type headers te spelen. Hier hebben een hele reeks web standaarden aan bijgedragen.

d. Onenigheid over foutmeldingen

Bij deze uitdaging was ik de frontender die een API moest gebruiken om een mobiele app én web applicatie te bouwen. Ik had invloed op de API omdat die werd geschreven door de klant! De uitdaging hier was drievoudig:

  1. De API gaf een 500 Server Error als er iets mis ging, ook al was het een fout van mij.
  2. De API gaf niet een consistente manier van fouten terug. Soms als een regel tekst (maar gemarkeerd als JSON, hoe dan?), soms als een JSON object met een key "error", en soms weer wat totaal anders.
  3. De API gaf foutmeldingen terug die niet duidelijk waren of niet hielpen bij het verhelpen van die foutmelding.

Het eerste probleem was echt erg vervelend. Standaard schrijf ik mijn interactieve frontend code zo dat als het een 5xx status code krijgt, dat ook echt wordt gezien als server gerelateerd probleem. Bij het ophalen van informatie betekent dat ook dat ik automatisch nog een aantal pogingen deed. De klant klaagde erover dat ik "veel verzoeken deed".

RFC 9110 gaat over semantiek, waaronder ook de HTTP status codes. Omdat de foutcode 500 niet veel zegt en ook niet aangeeft of het een permanent of tijdelijk probleem is, en omdat de foutmeldingen in het antwoord ook niet hielp, koos ik ervoor om altijd opnieuw te proberen bij een 5xx code. Bij een 4xx code, hetgeen aangeeft dat er iets mis is met het verzoek zelf, deed ik dat niet.

Na ze te wijzen op de beschrijvingen in de standaard is de API bijgewerkt en gebruikt het zowel 4xx als 5xx codes, en dat was mooi, want het loste probleem 1 op en hielp ontzettend voor probleem 3.

Voor probleem 2 hadden we allebei geen goede ideeën. Uiteindelijk heb ik voorgesteld om een voorstel van iemand anders te gebruiken, en wel RFC 7807: Problem Details for HTTP APIs.

Deze RFC introduceert een standaard formaat (geregistreerd met een media type application/problem+json) en hierdoor zien alle foutmeldingen er min of meer zo uit:

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
Content-Language: en

{
    "type": "https://example.com/probs/out-of-credit",
    "title": "You do not have enough credit.",
    "detail": "Your current balance is 30, but that costs 50.",
    "instance": "/account/12345/msgs/abc",
    "balance": 30,
    "accounts": ["/account/12345",
                 "/account/67890"]
}

In het kort:

  • type is altijd een URI die het type probleem identificeert. Het wordt sterk aangeraden om deze URI "browsebaar" te maken en dat deze wijst naar documentatie over de fout.
  • title is een tekstuele samenvatting voor mensen! Deze kan worden vertaald door middel van Content-Negotiation (aangeven welke talen je zou willen via Accept-Language, en de server kiest dan een ander antwoord gebaseerd op je verzoek).
  • detail: is een tekstuele uitleg van het probleem, voor mensen! Dus geen computer bliep-die-bloep of SQL statements, of een verbatim foutmelding.
  • instance: is een URI voor dit specifieke geval van deze fout.

Doordat de title en detail velden verplicht zijn, werd de klant nu ook verplicht om de API betere foutmeldingen te laten geven (en hier heb ik ook bij geholpen).

Tot slot konden ze ook nog gradueel hun API bijwerken, omdat ik kon zien of iets in het juiste formaat zou moeten staan door de Content-Type van de foutmelding.

In dit geval heb ik dus meerdere standaarden gebruikt om tot een besluit te komen waarbij iedereen weet waar ze aan toe zijn, en anders dan "hier is een idee, dit is al uitgewerkt" hoefde ik het niet te beargumenteren, want het alternatief was de status quo die niet werkbaar was.

e. Toegankelijke emails?

Tot slot heb ik een voorbeeld waarbij een klant graag wilde dat ik een nieuwe gebruikersoptie implementeerde. Deze klant gaf aan dat leden niet allemaal de nieuwsbrief en updates konden lezen die per e-mail werden verstuurd.

Het verzoek was:

Graag de optie toevoegen aan het gebruikersprofiel tussen HTML email en tekst email.

Het was relatief makkelijk voor mij om dit verzoek in te willigen, en zo gezegd, zo gedaan.

Twee weken later kreeg ik een belletje dat de oplossing niet werkte. Waarom niet? Een van de leden had in het profiel de e-mail op tekst gezet, maar klaagde nu dat de email overal alleen maar tekst was.

Wat was het echte probleem? Deze persoon gebruikte een tekst-only email client op sommige apparaten en kon HTML emails wel aan op andere apparaten. Ook gaf deze persoon aan dat dit probleem zich wel vaker voor deed, maar liet ook een paar voorbeelden zien van e-mails die het op alle apparaten correct deden.

Ik ben op zoek gegaan naar de webstandaard, want als meerdere applicaties allemaal het correcte gedrag laten zien, moet er bijna wel een standaard aan te pas zijn gekomen.

De oplossing vond ik in RFC 2046: Multipurpose Internet Mail Extensions (MIME) Part Two. Hierin staat beschreven hoe e-mails in elkaar zitten en hoe e-mail readers ze moeten behandelen. Hierin is ook beschreven hoe een speciale mediatype multipart kan worden gebruikt om een bericht te maken dat uit meerdere delen bestaat, en in het bijzonder multipart/alternative.

"Multipart/alternative" may be used, for example, to send a message in a fancy text format in such a way that it can easily be displayed anywhere.

En dat was ook exact wat de e-mails deden die het lid liet zien.

From: sender@example.com
To: recipient@example.com
Subject: Multipart Email Example
Content-Type: multipart/alternative; boundary="boundary-string"

--your-boundary
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Platte tekst email hier! Dit wordt gebruikt
als text/html niet werkt.

--boundary-string
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

<h1>Woopdiedoo html werkt!</h1>
<p>Hier dan de HTML variant</p>

--boundary-string--

Het was eenvoudig om de instelling weer weg te halen uit het gebruikersprofiel, en alle emails automatisch ook als platte tekst te laten zien.

Helaas is er niet veel meer ondersteuning dan text/plain en text/html, maar onlangs heeft Apple een nieuwe variant geïntroduceerd die text/watch-html gebruikt. Dit is speciaal voor de Apple Watch!

Enfin, de makkelijke oplossing hier was uiteindelijk niet de juiste. Hierbij was het dus zo dat de standaard veel meer gebruikscasussen had dan mijn simpele implementatie.

Webstandaarden voor Fronteers

Pakweg 2300 woorden verder en ik vertel je nu dat je al gebruik maakt van webstandaarden. En dan heb ik het niet eens over HTTP, of tools die gebruik maken van standaarden zoals formatters en linters.

Produceer je HTML? Dan heb je te maken de HTML specificatie

Schrijf je CSS? Dan heb je te maken met de vele CSS specificaties zoals mediaqueries, selectors, en het box-model;

Interactiviteit via een taal zoals JavaScript of TypeScript? Je houdt je waarschijnlijk zoveel mogelijk aan de ECMAScript standard;

Roep jij een API aan in JavaScript? Het is dan handig om te weten dat er een standaard is voor fetch en ook voor xhr (XMLHttpRequest);

Bestanden uploaden via een formulier? Dan gebruik je multipart/form-data.

Stuur je e-mails? Hallo daar Simple Mail Transfer Protocol. Lezen kan bijvoorbeeld via het oude Post Office Protocol of via het Internet Message Access Protocol. De content en headers volgen RFC 2822: Internet Message Format, DomainKeys Identified Mail (DKIM) is RFC 6375, en het sturen van een e-mail als zowel HTML als platte tekst is mede mogelijk gemaakt door multipart/alternative.

Te maken met 3D graphics? De standaard die je gebruikt is waarschijnlijk beschreven en onderhouden door de Khronos Group.

Testen op toegankelijkheid? Je volgt hoogstwaarschijnlijk de Web Content Accessibility Guidelines, zoals beschreven in de specificatie van het W3C (World Wide Web Consortium).

Bovenstaande is maar een klein onderdeel van de vele vele standaarden waar je al met regelmaat gebruik van maakt, waar je op bouwt, waar je van profiteert. Hoe URLs werken, en wat de regels zijn voor een e-mail adres.

Meedoen met het ontwikkelen van ons WWW

Interesseert dit alles je en heb je ideeën over het web door-ontwikkelen? Ben je ergens tegen aan gelopen die een huidige standaard niet beschrijft? Er zijn ontzettend veel manieren om mee te doen.

  1. Veel van de organisaties die standaarden ontwikkelen en onderhouden kan je terug vinden op sites als GitHub.com. Voorbeelden hiervan zijn het WC3, WICG, WhatWG en TC39. Ze hebben allemaal andere regels en richtlijnen, veelal beschreven in hun README en/of Code of Conduct. Dit is een van de eenvoudigste manieren om te zien welke discussies op dit moment leven.
  2. Het WC3 heeft een eigen website. Hier kan je alle werkgroepen en ander-soort samenkomen vinden. Lid worden van een groep is vaak ontzettend eenvoudig en als je het eenmaal bent, ben je vaak direct van harte welkom bij veel van de discussies.
  3. De Web Incubator Community Group (WICG) heb ik nog niet genoemd. Deze groep ontwikkeld voorstellen voor nieuwe features! Je kan veel van deze features terug vinden op hun website, alsmede een link naar hun Discourse.
  4. Dan hebben we de Web Hypertext Application Technology Working Group (WHATWG). Deze groep onderhoudt en ontwikkelt de HTML standaard! Hoe je daar mee aan kan doen staat uitgelegd op hun website.
  5. Voor JavaScript (en gerelateerde) is er de TC39 standaard. De website zelf geeft aan dat eigenlijk alle contributies lopen via hun GitHub, maar er staat wel wat extra informatie op de website.

Is onderdeel worden van zo'n groep dan de enige manier?

NEE!. Je kan als individu reageren op issues, nieuwe voorstellen indienen, maar ook deelnemen aan evenementen gehost door de IETF. Er is een Datatracker die alle voorstellen (aangenomen, klad, verlopen, enzovoorts) bijhoudt en beschrijft welke vragen open staan. Ook kan je hier terug vinden wanneer het volgende synchrone moment is om vragen te stellen over zo'n voorstel. Zelf heb ik hier een aantal keer aan meegedaan.

Er zijn leden van Fronteers die actief meewerken aan of hebben meegewerkt aan voorstellen van specificaties. Zij kunnen je waarschijnlijk net als ik vertellen dat dit niet altijd zonder uitdagingen gaat. Ontwikkeling duurt vaak lang en consensus bereiken is niet altijd mogelijk. Het zijn relatief logge machines. Aan de andere kant is het wel zo dat alles waar wij digitaal, online van genieten mede mogelijk is gemaakt door deze standaarden.

Tot slot

Door het gebruik van webstandaarden was het voor ons mogelijk om voor een klant met behulp van 5 developers in totaal (in de hele stack) een applicatie neer te zetten met meer dan 15 miljoen requests elke avond, 2.2 TB data per dag, met een gemiddelde (en mediaan) laadtijd van 35 ms gebruikmakende van één (relatief krachtige) server.

Door het gebruik van webstandaarden konden we tegen een andere klant zeggen: "Jullie hebben klanten die screenreaders gebruiken? Dat is geen probleem. Daar zijn geen extra kosten aan verbonden." waarna ze erachter kwamen dat vrijwel de hele applicatie al enigszins tot goed toegankelijk was.

Door het gebruik van webstandaarden kunnen we veel eindeloze discussies voorkomen omdat we (bijna) altijd iets hebben om op terug te vallen en naar te refereren, en zo ook achterhalen of er een programmeer- of denkfout zit in onze code, of dat er een fout is gemaakt bij het implementeren van een specificatie in bijvoorbeeld een browser.

Ook jij gebruikt webstandaarden en dat is slim, dus ga zo door.