{"id":3740,"date":"2013-11-10T20:33:04","date_gmt":"2013-11-10T19:33:04","guid":{"rendered":"http:\/\/blog.visisoft.de\/yalst\/?p=812"},"modified":"2015-05-28T23:52:19","modified_gmt":"2015-05-28T21:52:19","slug":"null-and-undefined-values-in-a-type-safe-uri-query","status":"publish","type":"post","link":"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/","title":{"rendered":"Encoding of null and undefined in a type-safe URI query"},"content":{"rendered":"<div  style='padding-bottom:10px; ' class='av-special-heading av-special-heading-h4    avia-builder-el-0  el_before_av_codeblock  avia-builder-el-first  '><h4 class='av-special-heading-tag '  itemprop=\"headline\"  >Encoding of null and undefined in a type-safe URI query<\/h4><div class='special-heading-border'><div class='special-heading-inner-border' ><\/div><\/div><\/div>\n\n<section class=\"av_textblock_section \"  itemscope=\"itemscope\" itemtype=\"https:\/\/schema.org\/BlogPosting\" itemprop=\"blogPost\" ><div class='avia_textblock  '   itemprop=\"text\" ><h4>TL;DR<\/h4>\n<p>When transferring variables in the query part of an URI, encode the JavaScript value <code>null<\/code>\u00a0in\u00a0<code>key=null<\/code> as <code>?key<\/code>. Distinguish between <code>undefined<\/code>, <code>null<\/code> and an empty string by omitting the key altogether for <code>undefined<\/code> and appending an equal\u00a0sign for the latter. I.e.\u00a0<code>?key=<\/code>\u00a0stands for\u00a0<code>key=\"\"<\/code>. Use the\u00a0<a title=\"URI.js homepage\" href=\"http:\/\/medialize.github.io\/URI.js\/\" target=\"_blank\" rel=\"noopener\">URI.js<\/a>\u00a0as helper library for\u00a0URI query extraction and composition.<\/p>\n<h4>The Problem<\/h4>\n<p>The <a title=\"HTML 4 - Processing Form Data\" href=\"http:\/\/www.w3.org\/TR\/html401\/interact\/forms.html#form-content-type\" target=\"_blank\" rel=\"noopener\">standard way of encoding of data in the query part of an URI<\/a> in the format<br \/>\n<code>\"?key1=value1&amp;key2=value2...\"<\/code> is created for the purpose of submitting a <em>HTML form<\/em> via a HTTP GET request (with content type <code>application\/x-www-form-urlencoded<\/code>).<\/p>\n<p>In general the types of the variables encoded in this way are not preserved.<\/p>\n<p>Imagine for instance that <em>booleans<\/em> could get encoded as <code>true<\/code> and <code>false<\/code> making then indistinguishable from strings with those values.<\/p>\n<h4>Type-safe URI query for <code>null<\/code> , <code>undefined<\/code> and <code>\"\"<\/code><\/h4>\n<p>Outside the use for HTML forms the syntactic format of the query part of a URI is largely by convention.<br \/>\nFrom the <a title=\"RFC 3986\" href=\"http:\/\/tools.ietf.org\/html\/rfc3986#section-3.4\" target=\"_blank\" rel=\"noopener\">URI rfc<\/a>:<\/p>\n<blockquote>\n<p>The query component is indicated by the first question mark (&#8220;?&#8221;) character and terminated by a number sign (&#8220;#&#8221;) character or by the end of the URI.<\/p>\n<\/blockquote>\n<pre class=\"prettyprint\"><code>http_URL = \"http:\" \"\/\/\" host [ \":\" port ] [ abs_path [ \"?\" query ] \"#\" fragment ]<\/code><\/pre>\n<p>Thus the query part can contain anything except the number sign (&#8220;#&#8221;).<\/p>\n<p>URIs containing query components like <code>?key<\/code> and <code>?key=<\/code> for a variable <code>key<\/code> are valid URIs. This can be leveraged to fix type safety for <code>null<\/code> values.<\/p>\n<p>The problem however is how these formats are interpreted by different query component parsers.<\/p>\n<p><small><strong>Note:<\/strong> This discussion just applies to cases where you are forced to resort to the HTTP GET query component to transmit variables which can be <code>null<\/code> or <code>undefined<\/code>. In general it is advised to use a more suitable format like <a title=\"JSON.org\" href=\"http:\/\/www.json.org\/\" target=\"_blank\" rel=\"noopener\">JSON<\/a> for more type-safe en\/decoding of your data.<\/small><\/p>\n<h4>Choosing the right query component builder\/parser library<\/h4>\n<h5>URI.js<\/h5>\n<p>Values of <code>null<\/code> or <code>undefined<\/code> are <em>invariant<\/em> with respect to URI query component encoding-decoding.<\/p>\n<pre class=\"prettyprint\"><code>\/\/ composing\r\nURI.buildQuery({keyN: null, keyU: undefined, keyS: \"\"});  \/\/ <\/code><\/pre>\n<h5>Node.js, jQuery-Purl<\/h5>\n<p><a title=\"URL module in the Node.js Documentation\" href=\"http:\/\/nodejs.org\/api\/url.html#url_url_format_urlobj\" target=\"_blank\" rel=\"noopener\">Node.js&#8217; url module<\/a> as well as the combination of <a title=\"jQuery\" href=\"http:\/\/jquery.com\/\" target=\"_blank\" rel=\"noopener\">jQuery<\/a> and <a title=\"Purl on GitHub\" href=\"https:\/\/github.com\/allmarkedup\/purl\" target=\"_blank\" rel=\"noopener\">Purl<\/a> coalesce <code>null<\/code>, <code>undefined<\/code> and <code>\"\"<\/code> into <code>?key=<\/code>. which in turn always get decoded as empty string.<\/p>\n<pre class=\"prettyprint\"><code>\/\/\/\/\/ Node.js \/\/\/\/\/\r\nurl = require('url');\r\n\/\/ composing\r\nurl.format({query: {keyN: null, keyU: undefined, keyS: \"\"}});  \/\/ <\/code><\/pre>\n<pre class=\"prettyprint\"><code>\/\/ composing with jQuery\r\n$.param({keyN: null, keyU: undefined, keyS: \"\"}); \/\/ <\/code><\/pre>\n<ul>\n<li>The query part <code>?key=<\/code> is <em>ambiguous<\/em> (can result from an empty string, <code>undefined<\/code> or <code>null<\/code>).<\/li>\n<li>The parse result of an empty string is <em>ambiguou<\/em>s since it may stem from <code>?key=<\/code> or <code>?key<\/code>.<\/li>\n<\/ul>\n<h4>References<\/h4>\n<ol>\n<li><a title=\"URI.js library\" href=\"http:\/\/medialize.github.io\/URI.js\/\" target=\"_blank\" rel=\"noopener\">URI.js<\/a><\/li>\n<li><a title=\"URL module in the Node.js Documentation\" href=\"http:\/\/nodejs.org\/api\/url.html#url_url_format_urlobj\" target=\"_blank\" rel=\"noopener\">Node.js<\/a><\/li>\n<li><a title=\"Purl on GitHub\" href=\"https:\/\/github.com\/allmarkedup\/purl\" target=\"_blank\" rel=\"noopener\">Purl<\/a><\/li>\n<\/ol>\n<\/div><\/section>\n","protected":false},"excerpt":{"rendered":"<p>When transferring variables in the query part of an URI, encode the JavaScript value null in key=null as ?key. Distinguish between undefined, null and an empty string by omitting the key altogether for undefined and appending an equal sign for the latter. I.e. ?key= stands for key=&#8221;&#8221;. Use the URI.js as helper library for URI query extraction and composition.<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[67],"tags":[89,68,90],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v20.12 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Encoding of null and undefined in a type-safe URI query<\/title>\n<meta name=\"description\" content=\"Encode the JavaScript value null in key=null as ?key, an empty string as ?key= and undefined by omitting the key to create a type-safe URI query.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Encoding of null and undefined in a type-safe URI query\" \/>\n<meta property=\"og:description\" content=\"Encode the JavaScript value null in key=null as ?key, an empty string as ?key= and undefined by omitting the key to create a type-safe URI query.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/\" \/>\n<meta property=\"og:site_name\" content=\"yalst - Live Support | Live Chat | Live Help | Help Desk\" \/>\n<meta property=\"article:published_time\" content=\"2013-11-10T19:33:04+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2015-05-28T21:52:19+00:00\" \/>\n<meta name=\"author\" content=\"Matthias Seemann\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Matthias Seemann\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"2 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/\",\"url\":\"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/\",\"name\":\"Encoding of null and undefined in a type-safe URI query\",\"isPartOf\":{\"@id\":\"https:\/\/www.yalst.de\/en\/#website\"},\"datePublished\":\"2013-11-10T19:33:04+00:00\",\"dateModified\":\"2015-05-28T21:52:19+00:00\",\"author\":{\"@id\":\"https:\/\/www.yalst.de\/en\/#\/schema\/person\/32edfd67d7dc13e809181afe316fcccb\"},\"description\":\"Encode the JavaScript value null in key=null as ?key, an empty string as ?key= and undefined by omitting the key to create a type-safe URI query.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.yalst.de\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Encoding of null and undefined in a type-safe URI query\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.yalst.de\/en\/#website\",\"url\":\"https:\/\/www.yalst.de\/en\/\",\"name\":\"yalst - Live Support | Live Chat | Live Help | Help Desk\",\"description\":\"Ihr umfassender Live Support Chat\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.yalst.de\/en\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.yalst.de\/en\/#\/schema\/person\/32edfd67d7dc13e809181afe316fcccb\",\"name\":\"Matthias Seemann\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.yalst.de\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/6d883a962ac315cf385799a15783f440?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/6d883a962ac315cf385799a15783f440?s=96&d=mm&r=g\",\"caption\":\"Matthias Seemann\"},\"description\":\"Entwickler und Mitglied der Gesch\u00e4ftsf\u00fchrung bei der Visisoft OHG\",\"url\":\"https:\/\/www.yalst.de\/en\/author\/seemannvisisoft-de\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Encoding of null and undefined in a type-safe URI query","description":"Encode the JavaScript value null in key=null as ?key, an empty string as ?key= and undefined by omitting the key to create a type-safe URI query.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/","og_locale":"en_US","og_type":"article","og_title":"Encoding of null and undefined in a type-safe URI query","og_description":"Encode the JavaScript value null in key=null as ?key, an empty string as ?key= and undefined by omitting the key to create a type-safe URI query.","og_url":"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/","og_site_name":"yalst - Live Support | Live Chat | Live Help | Help Desk","article_published_time":"2013-11-10T19:33:04+00:00","article_modified_time":"2015-05-28T21:52:19+00:00","author":"Matthias Seemann","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Matthias Seemann","Est. reading time":"2 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/","url":"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/","name":"Encoding of null and undefined in a type-safe URI query","isPartOf":{"@id":"https:\/\/www.yalst.de\/en\/#website"},"datePublished":"2013-11-10T19:33:04+00:00","dateModified":"2015-05-28T21:52:19+00:00","author":{"@id":"https:\/\/www.yalst.de\/en\/#\/schema\/person\/32edfd67d7dc13e809181afe316fcccb"},"description":"Encode the JavaScript value null in key=null as ?key, an empty string as ?key= and undefined by omitting the key to create a type-safe URI query.","breadcrumb":{"@id":"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.yalst.de\/en\/null-and-undefined-values-in-a-type-safe-uri-query\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.yalst.de\/en\/"},{"@type":"ListItem","position":2,"name":"Encoding of null and undefined in a type-safe URI query"}]},{"@type":"WebSite","@id":"https:\/\/www.yalst.de\/en\/#website","url":"https:\/\/www.yalst.de\/en\/","name":"yalst - Live Support | Live Chat | Live Help | Help Desk","description":"Ihr umfassender Live Support Chat","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.yalst.de\/en\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.yalst.de\/en\/#\/schema\/person\/32edfd67d7dc13e809181afe316fcccb","name":"Matthias Seemann","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.yalst.de\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/6d883a962ac315cf385799a15783f440?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6d883a962ac315cf385799a15783f440?s=96&d=mm&r=g","caption":"Matthias Seemann"},"description":"Entwickler und Mitglied der Gesch\u00e4ftsf\u00fchrung bei der Visisoft OHG","url":"https:\/\/www.yalst.de\/en\/author\/seemannvisisoft-de\/"}]}},"_links":{"self":[{"href":"https:\/\/www.yalst.de\/en\/wp-json\/wp\/v2\/posts\/3740"}],"collection":[{"href":"https:\/\/www.yalst.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.yalst.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.yalst.de\/en\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.yalst.de\/en\/wp-json\/wp\/v2\/comments?post=3740"}],"version-history":[{"count":12,"href":"https:\/\/www.yalst.de\/en\/wp-json\/wp\/v2\/posts\/3740\/revisions"}],"predecessor-version":[{"id":4236,"href":"https:\/\/www.yalst.de\/en\/wp-json\/wp\/v2\/posts\/3740\/revisions\/4236"}],"wp:attachment":[{"href":"https:\/\/www.yalst.de\/en\/wp-json\/wp\/v2\/media?parent=3740"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.yalst.de\/en\/wp-json\/wp\/v2\/categories?post=3740"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.yalst.de\/en\/wp-json\/wp\/v2\/tags?post=3740"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}