[{"data":1,"prerenderedAt":439},["ShallowReactive",2],{"post:three-coldbox-learnings":3},{"id":4,"title":5,"body":6,"date":426,"description":427,"draft":428,"extension":429,"meta":430,"navigation":431,"path":432,"seo":433,"stem":434,"tags":435,"__hash__":438},"posts\u002Fposts\u002Fthree-coldbox-learnings.md","Three ColdBox Features I Learned While Building A URL Shortener",{"type":7,"value":8,"toc":420},"minimark",[9,21,24,29,43,53,81,84,104,111,118,127,155,159,166,172,175,217,240,244,267,287,293,383,403,407,416],[10,11,12,13,20],"p",{},"Last night I did another live-stream where I finished the first draft of a URL shortener I'm calling \"cfShorty\". During live-streams I typically end up searching the ColdBox docs for help, but this time ",[14,15,19],"a",{"href":16,"rel":17},"https:\u002F\u002Ftwitter.com\u002Fgpickin",[18],"nofollow","Gavin Pickin"," watched and commented with some cool tips, most of which I'd never used before.",[10,22,23],{},"Here are the three ColdBox features I learned while building my URL shortener last night.",[25,26,28],"h2",{"id":27},"resourceful-routes","Resourceful Routes",[10,30,31,32,36,37,42],{},"This one was cool. Rather than define and tweak my URL routes manually in ",[33,34,35],"code",{},"\u002Fconfig\u002FRouter.cfc",", Gavin told me how to use the ",[14,38,41],{"href":39,"rel":40},"https:\u002F\u002Fcoldbox.ortusbooks.com\u002Fthe-basics\u002Frouting\u002Frouting-dsl\u002Fresourceful-routes",[18],"resourceful routing feature"," to auto-generate my CRUD routes for me.",[10,44,45,46,49,50,52],{},"By simply adding ",[33,47,48],{},"resources( \"photos\" )"," to my ColdBox Router config file (that's ",[33,51,35],{},"), ColdBox will set up all the routes necessary for a CRUD management screen:",[54,55,56,63,69,75],"ul",{},[57,58,59,60],"li",{},"List resources page (aka table of entries with Edit\u002FDelete button) via ",[33,61,62],{},"GET \u002Fresource",[57,64,65,66],{},"Show individual resource (aka readonly view of a single entry) via ",[33,67,68],{},"GET \u002Fresource\u002F:id",[57,70,71,72],{},"Show \"New Resource\" form to create a new resource entry via ",[33,73,74],{},"GET \u002Fresource\u002Fnew",[57,76,77,78],{},"Show edit form for an existing resource via ",[33,79,80],{},"GET \u002Fresource\u002F:id\u002Fedit",[10,82,83],{},"As well as the three main routes necessary for creating, updating and deleting entries from the database:",[54,85,86,92,98],{},[57,87,88,89],{},"Create new resource entry via ",[33,90,91],{},"POST \u002Fresource",[57,93,94,95],{},"Update an existing resource entry via ",[33,96,97],{},"PUT \u002Fresource\u002F:id",[57,99,100,101],{},"Delete an existing resource entry via ",[33,102,103],{},"DELETE \u002Fresource\u002F:id",[10,105,106,107,110],{},"Obviously, I still had to write the code to handle each event, but ColdBox even makes that party easy by offering a CommandBox CLI command which can quickly build out your event handler, HTML view files, a model object, and even base test specs in your ",[33,108,109],{},"tests\u002Fspecs"," directory:",[10,112,113],{},[114,115],"img",{"alt":116,"src":117},"Running \"coldbox create resource Users\" inside the commandbox shell to build handlers, views, models and test files","https:\u002F\u002Fthepracticaldev.s3.amazonaws.com\u002Fi\u002Fzedt6vnhpx2icliqcvzp.png",[10,119,120,121,126],{},"The ",[14,122,125],{"href":123,"rel":124},"https:\u002F\u002Fcoldbox.ortusbooks.com\u002Fthe-basics\u002Frouting\u002Frouting-dsl\u002Fresourceful-routes#scaffolding-resources",[18],"\"Scaffolding Resources\" ColdBox docs"," outline this, but it's as easy as running:",[128,129,134],"pre",{"className":130,"code":131,"language":132,"meta":133,"style":133},"language-sh shiki shiki-themes github-light github-dark","coldbox create resource Users\n","sh","",[33,135,136],{"__ignoreMap":133},[137,138,141,145,149,152],"span",{"class":139,"line":140},"line",1,[137,142,144],{"class":143},"sScJk","coldbox",[137,146,148],{"class":147},"sZZnC"," create",[137,150,151],{"class":147}," resource",[137,153,154],{"class":147}," Users\n",[25,156,158],{"id":157},"coldbox-route-visualizer-module","ColdBox Route Visualizer Module",[10,160,161,162,165],{},"This module is super handy for debugging your ColdBox routes. Here's what I see when I browse the ",[33,163,164],{},"\u002Froute-visualizer"," page to debug my routes in cfShorty:",[10,167,168],{},[114,169],{"alt":170,"src":171},"ColdBox Route Visualizer debug page shows list of ColdBox routes","https:\u002F\u002Fthepracticaldev.s3.amazonaws.com\u002Fi\u002Fytbye9gtkpkae9zx0ikl.png",[10,173,174],{},"To install and use Route Visualizer, all it takes is these three steps:",[176,177,178,185,211],"ol",{},[57,179,180,181,184],{},"Run ",[33,182,183],{},"install route-visualizer --saveDev"," from your CommandBox shell",[57,186,187,192,193],{},[14,188,191],{"href":189,"rel":190},"https:\u002F\u002Fcoldbox.ortusbooks.com\u002Fgetting-started\u002Fconfiguration#reinitializing-an-application",[18],"Reinitialize ColdBox"," by browsing:\n",[54,194,195,205],{},[57,196,197,200,201,204],{},[33,198,199],{},"\u002F?fwreinit=mypass"," if you have a reinit password set in ",[33,202,203],{},"config\u002FColdbox.cfc",", OR",[57,206,207,210],{},[33,208,209],{},"\u002F?fwreinit=1"," if no reinit password is configured.",[57,212,213,214,216],{},"Head to ",[33,215,164],{}," in your ColdBox app.",[10,218,219,220,223,224,227,228,232,233,236,237,239],{},"One thing to note: Make sure to add the ",[33,221,222],{},"--saveDev"," flag when you install Route Visualizer. You might notice in the live-stream recording that I neglected to do this, causing ColdBox to (by default) install this module as a production dependency in ",[33,225,226],{},"box.json",". ",[229,230,231],"strong",{},"I do not want production users viewing my ColdBox routes",", so I came back later and moved the dependency to ",[33,234,235],{},"devDependencies"," in my ",[33,238,226],{},".",[25,241,243],{"id":242},"http-method-spoofing","HTTP Method Spoofing",[10,245,246,247,249,250,255,256,259,260,263,264,266],{},"This is a small tip, but still super useful for my project. Since my cfShorty is a rough draft\u002Fprototype, I am not using any frontend JS like Vue. And since I am not using frontend JS, I have no way to edit a route via ",[33,248,97],{}," because ",[14,251,254],{"href":252,"rel":253},"https:\u002F\u002Fstackoverflow.com\u002Fa\u002F8054241",[18],"HTML forms do not support the PUT method",". (This is something I was shocked to learn when Gavin told me. I guess I'm used to using ",[33,257,258],{},"PUT"," inside AJAX calls, and never actually tried it in a plain ",[33,261,262],{},"\u003Cform method=\"PUT\">"," before.) Likewise, I can't delete any resource entries via ",[33,265,103],{}," because HTML forms do not support the DELETE method either. (And besides - I wanted to use a link tag!)",[10,268,269,270,275,276,279,280,283,284,239],{},"ColdBox (and Gavin) to the rescue, once again. ColdBox supports ",[14,271,274],{"href":272,"rel":273},"https:\u002F\u002Fcoldbox.ortusbooks.com\u002Fthe-basics\u002Frouting\u002Fhttp-method-spoofing",[18],"spoofing the HTTP method",". All you need to do is add a ",[33,277,278],{},"_method"," url or form parameter which passes your desired HTTP method as the value, like ",[33,281,282],{},"_method=delete"," or ",[33,285,286],{},"_method=PUT",[10,288,289,290,292],{},"With HTTP method spoofing, hitting the ColdBox ",[33,291,97],{}," route is as simple as this:",[128,294,298],{"className":295,"code":296,"language":297,"meta":133,"style":133},"language-html shiki shiki-themes github-light github-dark","\u003Cform action=\"#event.buildLink( 'resource.#prc.id#')#\" method=\"POST\">\n  \u003Cinput type=\"hidden\" name=\"_method\" value=\"PUT\" \u002F>\n  \u003C!--- my form goes here --->\n\u003C\u002Fform>\n","html",[33,299,300,330,366,373],{"__ignoreMap":133},[137,301,302,306,310,313,316,319,322,324,327],{"class":139,"line":140},[137,303,305],{"class":304},"sVt8B","\u003C",[137,307,309],{"class":308},"s9eBZ","form",[137,311,312],{"class":143}," action",[137,314,315],{"class":304},"=",[137,317,318],{"class":147},"\"#event.buildLink( 'resource.#prc.id#')#\"",[137,320,321],{"class":143}," method",[137,323,315],{"class":304},[137,325,326],{"class":147},"\"POST\"",[137,328,329],{"class":304},">\n",[137,331,333,336,339,342,344,347,350,352,355,358,360,363],{"class":139,"line":332},2,[137,334,335],{"class":304},"  \u003C",[137,337,338],{"class":308},"input",[137,340,341],{"class":143}," type",[137,343,315],{"class":304},[137,345,346],{"class":147},"\"hidden\"",[137,348,349],{"class":143}," name",[137,351,315],{"class":304},[137,353,354],{"class":147},"\"_method\"",[137,356,357],{"class":143}," value",[137,359,315],{"class":304},[137,361,362],{"class":147},"\"PUT\"",[137,364,365],{"class":304}," \u002F>\n",[137,367,369],{"class":139,"line":368},3,[137,370,372],{"class":371},"sJ8bj","  \u003C!--- my form goes here --->\n",[137,374,376,379,381],{"class":139,"line":375},4,[137,377,378],{"class":304},"\u003C\u002F",[137,380,309],{"class":308},[137,382,329],{"class":304},[10,384,385,386,389,390,393,394,396,397,399,400,402],{},"Since HTML forms only support ",[33,387,388],{},"GET"," and ",[33,391,392],{},"POST",", I opted to send the form data via ",[33,395,392],{}," to hide the data in the request payload (as opposed to in the URL, which is kinda ugly). Then adding a hidden input to my form which passed ",[33,398,286],{}," causes ColdBox to execute my ",[33,401,258],{}," route, and as easy as that I'm done.",[25,404,406],{"id":405},"conclusion","Conclusion",[10,408,409,410,415],{},"I learned some cool ColdBox tips this session. If you missed the live-stream, you can catch up with ",[14,411,414],{"href":412,"rel":413},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=71uxK3mRYhg",[18],"the recording on YouTube"," or simply ask me on Twitter. 😄",[417,418,419],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":133,"searchDepth":332,"depth":332,"links":421},[422,423,424,425],{"id":27,"depth":332,"text":28},{"id":157,"depth":332,"text":158},{"id":242,"depth":332,"text":243},{"id":405,"depth":332,"text":406},"2019-12-18T16:13:57-04:00","Last night I did another live-stream where I finished the first draft of a URL shortener I'm calling \"cfShorty\". During live-streams I typically end up searching the ColdBox docs for help, but this time Gavin Pickin watched and commented with some cool tips, most of which I'd never used before.",false,"md",{},true,"\u002Fposts\u002Fthree-coldbox-learnings",{"title":5,"description":427},"posts\u002Fthree-coldbox-learnings",[436,437,144],"cfml","coldfusion","G_XYfhzzapL1yTQbCN4OnOMP1MD-InC_Nz6CsZTCSmA",1790471527457]