1:"$Sreact.fragment" 2:I[138,["244","static/chunks/244-94685f07977af2ff.js","831","static/chunks/app/blog/page-ed0148ef5c7335f0.js"],"default"] 4:I[2920,["87","static/chunks/0e762574-07919328fc2b362b.js","244","static/chunks/244-94685f07977af2ff.js","177","static/chunks/app/layout-6de1279a3de71d8e.js"],"default"] 5:I[7555,[],""] 6:I[1295,[],""] 8:I[9665,[],"MetadataBoundary"] a:I[9665,[],"OutletBoundary"] d:I[4911,[],"AsyncMetadataOutlet"] f:I[9665,[],"ViewportBoundary"] 11:I[6614,[],""] :HL["/_next/static/media/3273710ae43a970a-s.p.woff2","font",{"crossOrigin":"","type":"font/woff2"}] :HL["/_next/static/media/4b2a774852d1c06b-s.p.woff2","font",{"crossOrigin":"","type":"font/woff2"}] :HL["/_next/static/css/adfc29178418a091.css","style"] 3:T44f,M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z0:{"P":null,"b":"bBuat6XflHu8iZeyfdua8","p":"","c":["","blog","2015-01-13-url-routing"],"i":false,"f":[[["",{"children":["blog",{"children":[["slug","2015-01-13-url-routing","d"],{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/adfc29178418a091.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","className":"__className_c51aed __className_febfbb","children":[["$","head",null,{"children":["$","script",null,{"defer":true,"data-domain":"littledev.nl","src":"https://plausible.littledev.nl/js/script.js"}]}],["$","body",null,{"className":"bg-white text-black dark:bg-gray-900 dark:text-gray-100","children":["$","div",null,{"children":[null,["$","a",null,{"className":"sr-only focus:not-sr-only","href":"#content","children":"Naar content"}],["$","div",null,{"className":"bg-nav dark:bg-dark-nav py-3","children":["$","nav",null,{"className":"container mx-auto flex justify-between flex-wrap text-white","children":[["$","$L2",null,{"className":"ml-3 md:mx-3 md:text-xl font-fancy no-underline","href":"/","children":"Littledev"}],["$","ul",null,{"className":"flex text-white no-underline items-center","children":[["$","li",null,{"className":"px-3","children":["$","$L2",null,{"href":"/about","inactiveClassName":"no-underline","activeClassName":"underline","children":"About"}]}],["$","li",null,{"className":"px-3","children":["$","$L2",null,{"href":"/blog","inactiveClassName":"no-underline","activeClassName":"underline","children":"Blog"}]}],["$","li",null,{"className":"px-3","children":["$","$L2",null,{"href":"/projects","inactiveClassName":"no-underline","activeClassName":"underline","children":"Projects"}]}],["$","li",null,{"className":"px-3","children":["$","a",null,{"rel":"me noopener noreferrer","href":"https://mas.to/@littledev","target":"_blank","title":"@littledev on Mastodon","children":["$","svg",null,{"stroke":"currentColor","fill":"currentColor","strokeWidth":"0","role":"img","viewBox":"0 0 24 24","className":"text-white dark:text-white","children":["$undefined",[["$","path","0",{"d":"$3","children":[]}]]],"style":{"color":"$undefined"},"height":"1rem","width":"1rem","xmlns":"http://www.w3.org/2000/svg"}]}]}],["$","li",null,{"className":"px-3","children":["$","a",null,{"href":"https://github.com/blackshadev/","target":"_blank","title":"My Github","rel":"noreferrer noopener","children":["$","svg",null,{"stroke":"currentColor","fill":"currentColor","strokeWidth":"0","role":"img","viewBox":"0 0 24 24","className":"text-white dark:text-white","children":["$undefined",[["$","path","0",{"d":"M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12","children":[]}]]],"style":{"color":"$undefined"},"height":"1rem","width":"1rem","xmlns":"http://www.w3.org/2000/svg"}]}]}],["$","li",null,{"className":"px-3","children":["$","$L4",null,{"size":"1rem"}]}]]}]]}]}],["$","main",null,{"id":"content","className":"container mt-6 px-4 md:mx-auto md:px-0 ","children":["$","$L5",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]]}]}]]}]]}],{"children":["blog",["$","$1","c",{"children":[null,["$","$L5",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["slug","2015-01-13-url-routing","d"],["$","$1","c",{"children":[null,["$","$L5",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":["$L7",["$","$L8",null,{"children":"$L9"}],null,["$","$La",null,{"children":["$Lb","$Lc",["$","$Ld",null,{"promise":"$@e"}]]}]]}],{},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","m8kQwFbAV4szJ8JPV74Ab",{"children":[["$","$Lf",null,{"children":"$L10"}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],null]}],false]],"m":"$undefined","G":["$11","$undefined"],"s":false,"S":true} 12:"$Sreact.suspense" 13:I[4911,[],"AsyncMetadata"] 9:["$","$12",null,{"fallback":null,"children":["$","$L13",null,{"promise":"$@14"}]}] c:null 10:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]] b:null 14:{"metadata":[["$","title","0",{"children":"Littledev"}],["$","meta","1",{"name":"description","content":"Personal homepage of Vincent Hagen aka Littledev"}]],"error":null,"digest":"$undefined"} e:{"metadata":"$14:metadata","error":null,"digest":"$undefined"} 15:T429,So our weights are as followed: [1]:static, [2]:parameter, [3 times the size of the leftover URL]:wildcard. I know the wildcard is the ugly duck in this case, but I will explain that later. Now when we use greedy search — which always takes the cheapest route first, ‘/test/json/’ will in fact be routed to ‘/test/json’ instead of ‘/test/{id}/’, this is because ‘/test/json’ as a total cost of 2 and ‘/test/{id}’ has a cost of 3. Now the wildcard, we always want the static routes first and the parameters after that, say we have a ‘/{1}/{2}/{3}/’ route and a ‘/*’ route. The parameter route has a cost of 6 (2 for each parameter), in fact the maximum cost of any route containing only static and parameters is 2 times the length of the URL items. Therefore if we want the wildcards to be last, we need to scale according to the left over URL parts, we could suffice with 2n+1 but anything greater than 2 times the URL items is good, and with 3 times the URL items you have some space to apply ranking between the wildcards themselves.7:["$","article",null,{"className":"mx-0 sm:mx-5 md:mx-20","children":[["$","header",null,{"children":["$undefined",["$","p",null,{"children":"13/01/2015"}],["$","h1",null,{"children":"URL routing"}]]}],["$","div",null,{"children":[["$","p",null,{"children":"Ever wondered how packages like flask and express route their URLs to the correct functions, even with properties like wildcards and parameters? In this post I will discuss a solution to this URL routing problem which uses a search algorithm to find the correct route.\n"}],["$","div",null,{"className":"wysiwyg","children":[["$","p","0",{"children":"A few weeks ago I needed to create a way of deploying webservices in nodeJS for a client of mine. I looked at some of the existing packages out on the web, but I couldn’t find anything to my liking. I decided to custom build it, not only for learning purposes, but also to be able to use a framework the client was already accustomed to."}],"\n",["$","p","2",{"children":"One of the problems I faced was the URL routing. Of course there were no problems with static routes, but one of the nice things to have in these kind of situations is parameters within the URL and other fancy things like wildcards. Once again I turned to the web, but the only given solution I found was “just regex all routes and per request iterate over all route regexsâ€. Although this will work, it isn’t a really elegant approach, I even dare to say that this is almost as brute force of a solution as it gets."}],"\n",["$","p","4",{"children":"In this post I will use the following routes (and syntax) as an example. The routes are the key within the JSON, where the accepted HTTP verbs are prepended between square brackets. The resource (a file containing the webservice) is the value in this map."}],"\n",["$","pre","6",{"children":["$","code",null,{"className":"language-js","children":"var routes = {\n '/': 'index.js',\n '[GET]/test/{id}/': 'test.js:paramExample',\n '[GET]/test/{1}/{2}/': 'test.js:paramExample',\n '/test/hallo/world/': 'test.js:halloworld',\n '[GET,PUT]/test/json/': 'test.js:getJson',\n '[POST]/test/': 'test.js:post',\n '/statics/*': 'statics.js',\n};\n"}]}],"\n",["$","h2","8",{"children":"Tree building"}],"\n",["$","p","10",{"children":"Ok, of course we could regex the whole thing, but let’s first use our brains. We need a way to structure all routes given. I have done this by creating a tree structure which can be seen in te figure to the right. Every purple node is a node which is bound to a resource, so those are possible end nodes. The once with curly brackets are parameters and the astrix is a wildcard. The HTTP verbs are not seen in this picture, but can still be present in the actual node structure, I choose not to show them to allow for a cleaner representation."}],"\n",["$","h2","12",{"children":"Tree traversing"}],"\n",["$","p","14",{"children":["$","img",null,{"src":"/uploads/roadieroutegraph-300x271.png#right","alt":"Routes structured in a tree where each purple has a resource bound to it","children":"$undefined"}]}],"\n",["$","p","16",{"children":"Routes structured in a tree where each purple has a resource bound to it"}],"\n",["$","p","18",{"children":"For the people that read my previous post about search algorithms, this will look awfully familiar to a state space representation. In fact it can be used as such, we can use the created tree as possible paths. If we have an input URL we can traverse the tree in that order. Say we have ‘/test/hallo/world/’ the order of traversing will be ‘/’->’test’->’hallo’->’world’, great this works! Except for an URL like ‘/test/hallo/’, with the given routing table we would like to end up as a ‘/test/{id}/’ route, but in our implementation it will end up at ‘/test/hallo/’ which does not have a resource bound to it. So in fact, we need a search algorithm to solve this."}],"\n",["$","h2","20",{"children":"Searching the answer"}],"\n",["$","p","22",{"children":"Before anyone tries an uninformed search algorithm let’s revisit our tree. We now know that all purple states are goal states if and only if the HTTP verb matches and the complete user’s route is used — wildcards use up the complete left-over route. When we try an uninformed search algorithm for ‘/test/json/’ it will map to ‘/test/{id}/’ before ‘/test/json/’, this is because we need to apply a kind of ranking in our routes. We could restructure our whole tree to make sure the static routes are looked at first, than the routes with parameters and lastly the wildcards. But instead of restructuring the whole tree with every added route, we could also add weights and use a informed search algorithm."}],"\n",["$","p","24",{"children":"$15"}],"\n",["$","h2","26",{"children":"Worth it?"}],"\n",["$","p","28",{"children":"Hell yeah! The main problem with regexing everything is that your worst case scales according to the total of routes you have. This thing scales with the size of the user route, because shorter URLs need to check less states before reaching their goal state. Of course this model can be expanded to include some kind of regex mechanism inside each node, typed parameters, ect. Also a thing to note is that adding or removing routes is really easy. Just add a node per URL part if it doesn’t exist yet and add a resource to the end."}],"\n",["$","p","30",{"children":["See a live example in the nodeJs roadie package, available on ",["$","a","1",{"href":"https://www.npmjs.com/package/roadie","children":"npm"}]," and ",["$","a","3",{"href":"https://github.com/blackshadev/Roadie","children":"github"}]]}],"\n"]}]]}]]}]