<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Build Times</title>
    <description>A web development periodical by Eduardo Bouças</description>
    <link>https://eduardoboucas.com/</link>
    <atom:link href="https://eduardoboucas.com/feeds/rss.xml" rel="self" type="application/rss+xml"/>
    <pubDate></pubDate>
    <lastBuildDate></lastBuildDate>
    <generator>11ty</generator>
    
      <item>
        <title>AI and the creator's funnel</title>
        <description><p>Software generated entirely by AI is not an hypothetical future — it's <a href="https://arstechnica.com/ai/2024/10/google-ceo-says-over-25-of-new-google-code-is-generated-by-ai/">a reality today</a>. I don't think it's an overstatement to say that this is the largest shift in the history of this industry, unravelling before our eyes at an astonishing pace.</p>
<p>As a professional software engineer, I've been closely watching this change and taking my time to gather my thoughts on what this means for my profession and for the world. This is my first shot at putting those into words.<!--more--></p>
<h2 id="a-question-of-identity"><a class="heading-anchor" href="#a-question-of-identity">¶</a> A question of identity</h2>
<p>Over 20 years ago, before my personality and view of the world were even fully formed, I came across something that would change my life forever: I started writing code. For the 13-year old me, programming had absolutely nothing to do with career aspirations or entrepreneurship — it was the raw joy of solving a puzzle, of pushing myself to learn something new, of bending a machine to my will and make it materialise an idea that didn't exist anywhere in the universe other than in my own imagination.</p>
<p>Since that day, I've been on an incessant journey to master this <em>thing</em> that feels equal parts science, art and witchcraft. I went to school and university for it; I made it my profession; I travelled the world and moved countries because of it; it gave me countless friends and memories that I cherish.</p>
<p>More than something I do, writing code is a big part of who I am.</p>
<h2 id="preemptive-nostalgia"><a class="heading-anchor" href="#preemptive-nostalgia">¶</a> Preemptive nostalgia</h2>
<p>I take joy from different aspects of writing code on a daily basis: writing some tests and seeing them pass for the first time, dissecting the root cause of a gnarly bug, or coming up with an elegant solution for a seemingly impossible problem (and always patting myself on the back for it).</p>
<p>The realisation that computers can now perform these tasks in a fraction of the time it takes me is unsettling. It's impossible not to ask: will AI replace me?</p>
<p>Unlike the 13-year-old me, I no longer view programming as just a puzzle. As I honed the craft of being a software engineer, I developed other skills. I learned how to connect with people from different disciplines and translate their needs into technical requirements; how to solve problems in alignment with the vision and strategy of an organisation; how to balance competing priorities and adapt plans accordingly; and how to coach team members while promoting a culture of growth and knowledge sharing.</p>
<blockquote>
<p>The emotional part of me feels a deep sense of preemptive nostalgia about something dear that is about to change forever</p>
</blockquote>
<p>My work reflects the sum of every problem I've solved as a human throughout my life, and I don't think AI will replace that just yet.</p>
<p>But there are aspects of my job that will likely change forever. As computers start writing more of the code, I expect the moments of joy I mentioned earlier to become few and far between.</p>
<p>The emotional part of me feels a deep sense of preemptive nostalgia about something dear that is about to change forever, whereas my rational side sees this shift as a normal cycle of evolution and adaptation — and trusts that I'll be able to find that joy in new places.</p>
<h2 id="looking-at-the-bigger-picture"><a class="heading-anchor" href="#looking-at-the-bigger-picture">¶</a> Looking at the bigger picture</h2>
<p>As I let those feelings simmer, I wanted to take a step back and look at software as more than just something that I enjoy creating; it can also be a force for good with a profound impact on people’s lives.</p>
<p>Case in point: software that helps patients with chronic diseases. Healthy bodies have an incredibly powerful device — the pancreas — that takes care of continuously producing the right amount of a hormone called insulin, which converts sugars from food into the energy that powers the body. It’s a vital process.</p>
<p>People with type 1 diabetes saw their pancreas failing abruptly and unexpectedly at some point in their lives. To stay alive, they must take on the role that their pancreas once had and administer that insulin themselves. It's hard to overstate how difficult it is to figure out the right amount of insulin to take and when to take it, multiple times a day, every single day.</p>
<p>Technology can't solve this, but it sure can help. <a href="https://github.com/nightscout/cgm-remote-monitor">Nightscout</a> is a web-based Continuous Glucose Monitor (CGM). It's open-source software that allows patients and their caregivers to view glucose data in real time, and to receive alarms for abnormally high or low blood sugar values. These alarms save lives.</p>
<p>The <a href="https://openaps.org/">Open Artificial Pancreas System</a> (OpenAPS) is an open-source project that connects a small computer to a CGM and an insulin pump, automating the delivery of insulin to patients, mimicking to some degree what the pancreas would normally do. One third of people using OpenAPS are children, for whom managing blood sugar levels is especially challenging.</p>
<p>These are just a couple of examples of how community-built software can make a real, positive impact in people's lives. There are many other examples like this that apply to different conditions and situations — this is the story that hits closest to home for me, because as a type 1 diabetes patient I've experienced this impact firsthand.</p>
<p>As I zoomed out from my own experience and focused on programming as a means to achieve a larger goal, I began to ask myself how AI might push that even further.</p>
<h2 id="the-creator-s-funnel"><a class="heading-anchor" href="#the-creator-s-funnel">¶</a> The creator's funnel</h2>
<p>I kept thinking about these amazing projects and started wondering how they came to life; how the seed of an idea actually materialised into something positive for the world. Every project is different, but I think the process can be broadly broken down into the following phases:</p>
<ol>
<li><strong>Identify</strong>: Identify a problem worth solving or an opportunity worth chasing</li>
<li><strong>Conceptualise</strong>: Plan and shape a viable solution to address the problem</li>
<li><strong>Build</strong>: Execute the plan and turn the idea into something real and functional</li>
<li><strong>Distribute</strong>: Get it into people's hands</li>
</ol>
<p>For example, you might <em>identify</em> the pain of managing type 1 diabetes, <em>conceptualise</em> an interface that lets patients access glucose data with ease, <em>build</em> an application that shows that data in real time and provides alerts on abnormal values and, finally, <em>distribute</em> it as a web application.</p>
<p>But these phases don't form a linear path that every creator follows in the same way; they're more like a funnel, where fewer and fewer ideas reach the next stage of the journey. Not everyone who can identify a problem is able to conceptualise a solution; not everyone who can conceptualise a solution has the skills or the means to build it; and not everyone who manages to build a product knows how to distribute it.</p>
<figure
  class="figure figure--caption "
>
  <img
    alt="Fig 1. Illustration of the creator's funnel"
    class="figure__image"
    loading="lazy"
    onload="this.parentElement.classList += ' figure--loaded'"
    src="/posts/2025-04-07-ai-creators-funnel/creators-funnel.png"
    width=""
  />
  <figcaption class="figure__caption">Fig 1. Illustration of the creator's funnel</figcaption>
</figure>
<p>This means that the amazing projects we see today don't represent all the creators, the ideas, or the potential out there — they're just the ones that made it through the creator's funnel. A classic case of <a href="https://en.wikipedia.org/wiki/Survivorship_bias">survivorship bias</a>.</p>
<blockquote>
<p>By reducing the distance from idea to reality, we have a unique opportunity to harness more human ingenuity than ever before.</p>
</blockquote>
<p>What if AI can completely disrupt this? It's now possible to generate a fully working application simply by describing what it should look like and what it should do. No technical background, no budget, no need to assemble a cross-disciplinary team just to prove an idea. Within minutes — not days, weeks, or months — anyone can prompt their idea into existence.</p>
<p>AI has the power to transform this funnel into a portal that everyone can walk through, democratising access to resources that were once completely unattainable for millions of creators with life-changing ideas waiting to be uncovered. By reducing the distance from idea to reality, we have a unique opportunity to harness more human ingenuity than ever before.</p>
<h2 id="parting-thoughts"><a class="heading-anchor" href="#parting-thoughts">¶</a> Parting thoughts</h2>
<p>We're collectively embarking on a journey with no clear idea of where it leads. Yes, my job will change in ways I still do not fully understand and some parts of it that I've grown to love may not be around for long.</p>
<p>But I realised that by focusing on the small pleasures of writing code, I was missing the forest for the trees.</p>
<p>I've been working in the developer tooling space for over a decade. I fell in love with the idea of building for developers, of lowering the barrier of entry for tools and technologies that empower them to do their best work.</p>
<p>What better example of that than enabling millions of creators to add their voices to the conversation?</p>
<p>Computer scientists, hackers, tinkerers, and vibe coders: it doesn't matter where you come from, I'm just excited to see what you build.<!--tomb--></p>
</description>
        <pubDate>Mon Apr 07 2025 00:00:00 GMT+0000 (Coordinated Universal Time)</pubDate>
        <link>https://eduardoboucas.com/posts/2025-04-07-ai-creators-funnel/</link>
        <guid isPermaLink="true">https://eduardoboucas.com/posts/2025-04-07-ai-creators-funnel/</guid>
        
        
      </item>
    
      <item>
        <title>You should know this before choosing Next.js</title>
        <description><p>Picking the technology stack for a project is an important and consequential decision. In the enterprise space in particular, it often involves a multi-year commitment with long-lasting implications on the roadmap of the project, the pace of its development, the quality of the deliverables, and even the ability to assemble and maintain a happy team.</p>
<p>The open-source software model is a fundamental answer to this.<!--more--> By using software that is developed in the open, anyone is free to extend it or modify it in whatever way fits their use case. More crucially, the portability of open-source software gives developers and organisations the freedom to move their infrastructure between different providers without fear of getting locked in to a specific vendor.</p>
<p>This is the expectation with Next.js, an open-source web development framework created and <a href="https://nextjs.org/governance">governed by Vercel</a>, a cloud provider that offers managed hosting of Next.js as a service.</p>
<p>There is nothing wrong with a company profiting from an open-source software it created, especially when that helps fund the development of the project. In fact, there are plenty of examples of that model working successfully in our industry.</p>
<p>But I think that can only work sustainably if the boundaries between the company and the open-source project are abundantly clear, with well-defined expectations between the maintainers, the hosting providers and the users about how and where each feature of the framework can be used.</p>
<p>I want to explain why I don't think this transparency exists today.</p>
<p>My goal is not to stop anyone from using Next.js, but to lay out as much information as possible so developers and businesses can make an informed decision about their technology stack.</p>
<h2 id="declaration-of-interest"><a class="heading-anchor" href="#declaration-of-interest">¶</a> Declaration of interest</h2>
<p>Let me lead with a declaration of interest:</p>
<ul>
<li>I work at <a href="https://www.netlify.com/">Netlify</a> and have done so for over four years</li>
<li>Netlify is a frontend cloud platform that supports Next.js and other web frameworks as part of its product offering</li>
<li>Netlify and Vercel are direct competitors</li>
</ul>
<p>It's important for me to establish this for a few reasons.</p>
<p>My job involves building the infrastructure and tooling needed to support the full feature set of Next.js on Netlify, which has exposed me to the internals of the framework in a way that most people won't see. Over the years, I have seen concerning patterns of tight coupling between the open-source framework and the infrastructure of the company that builds it.</p>
<p>My employment is also the reason why I have always been very wary of voicing these concerns in public. As a Netlify employee, I don't really get to voice an objective concern about Next.js without people dismissing my claims as Netlify unleashing one of its minions to spread <a href="https://en.wikipedia.org/wiki/Fear,_uncertainty,_and_doubt">FUD</a> about a competitor.</p>
<p>I'm not keen on exposing myself and the company to that type of debate, so I have always chosen to work behind the scenes in supporting the developers who decide to deploy their sites on Netlify and shield them from all the complexity that goes into making that possible.</p>
<p>But then something happened.</p>
<p>Last weekend, Vercel disclosed a critical security vulnerability with Next.js. This type of issue is normal, but the way Vercel chose to handle it was so poor, reckless and disrespectful to the community that it has exacerbated my concerns about the governance of the project.</p>
<p>For me, things change once your decisions put other people at risk, so I felt the urge to speak up.</p>
<h2 id="openness-and-governance"><a class="heading-anchor" href="#openness-and-governance">¶</a> Openness and governance</h2>
<p>I'll come back to this incident later, but before that I want to back up a little and give you a peek behind the curtain. My history of reservations about the openness and governance of Next.js stem from a series of decisions made by Vercel over the years that make it incredibly challenging for other providers to support the full feature set of the framework.</p>
<p>I'll cover these by laying out a series of facts about how Next.js is built. I'll then add some of my own considerations about how those facts live up to the expectations of an open, interoperable, enterprise-grade software product.</p>
<h3 id="fact-1-no-adapters"><a class="heading-anchor" href="#fact-1-no-adapters">¶</a> Fact #1: No adapters</h3>
<p>Most modern web development frameworks use the concept of adapters to configure the output of the framework to a specific deployment target: <a href="https://remix.run/docs/en/main/discussion/runtimes">Remix</a>, <a href="https://docs.astro.build/en/reference/adapter-reference/">Astro</a>, <a href="https://nitro.build/deploy/custom-presets">Nuxt</a>, <a href="https://kit.svelte.dev/docs/adapters">SvelteKit</a> and <a href="https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/adapters/">Gatsby</a> are just a few examples. This pattern allows developers to keep the core of their applications untouched, and simply swap the adapter if they decide to start deploying to a different provider.</p>
<p>These adapters can be maintained by framework authors, by the hosting providers, by the community, or all of the above. Frameworks are typically structured in such a way that it’s possible for anyone to build their own adapter in case one isn’t available for the provider of their choice.</p>
<p>Next.js does not have the concept of adapters and they have <a href="https://archive.leerob.io/blog/using-nextjs#open-source-and-framework-boundaries">stated in the past</a> that they would not support them. The output of a Next.js build has a proprietary and undocumented format that is used in Vercel deployments to provision the infrastructure needed to power the application.</p>
<p>Vercel's alternative to this was the Build Output API, a documented specification for the output format of frameworks who wish to deploy to Vercel.</p>
<p>This is not an adapter interface for Next.js, and in fact has nothing to do with Next.js. The <a href="https://vercel.com/blog/build-output-api">announcement blog post</a> said that Next.js supports this format, but as of today that isn’t true.</p>
<p>In November 2023, the <a href="https://github.com/vercel/next.js/commit/958dcbc7e35dac5b84dd5a3bd3f4bb7f5ba0bf1a">Next.js documentation has been updated</a> to say that Next.js would adopt the Build Output API in the following major version of the framework (which would be version 15):</p>
<blockquote>
<blockquote>
<p>Next.js produces a standard deployment output used by managed and self-hosted Next.js. This ensures all features are supported across both methods of deployment. In the next major version, we will be transforming this output into our <a href="https://vercel.com/docs/build-output-api/v3?utm_source=next-site&amp;utm_medium=docs&amp;utm_campaign=next-website">Build Output API specification</a>.</p>
</blockquote>
</blockquote>
<p>Next.js 15.0.0 was <a href="https://nextjs.org/blog/next-15">released in October 2024</a> without support for the Build Output API.</p>
<p>Vercel have built the Build Output API because they wanted their customers to leverage the rich ecosystem of frameworks in the space, but their own framework doesn't support it to this day.</p>
<p>This means that any hosting providers other than Vercel must build on top of undocumented APIs that can introduce unannounced breaking changes in minor or patch releases. (And they have.)</p>
<p>Late last year, <a href="https://blog.cloudflare.com/builder-day-2024-announcements/#cloudflare-joins-opennext">Cloudflare</a> and <a href="https://www.netlify.com/blog/netlify-joins-opennext/">Netlify</a> have joined <a href="https://opennext.js.org/">OpenNext</a>, a movement of different cloud providers that collaborate on open-source adapters for Next.js. Shortly after, Vercel have engaged with the movement and committed to building support for adapters. They haven't made any timeline commitments, but have <a href="https://x.com/feedthejim/status/1903837444648382758?s=46">recently said they are actively working on it</a>.</p>
<p>It's important to remember that it's been almost three years since the launch of the Build Output API, and to this day the framework still isn't portable. I'm cautiously optimistic about that actually changing this time.</p>
<h3 id="fact-2-no-official-serverless-support"><a class="heading-anchor" href="#fact-2-no-official-serverless-support">¶</a> Fact #2: No official serverless support</h3>
<p>The official methods for <a href="https://nextjs.org/docs/pages/building-your-application/deploying#self-hosting">self-hosting Next.js</a> require running the application in a stateful way, as long-running servers. While technically possible, this is very hard to operate in any real-world production environment where a single instance isn’t sufficient.</p>
<p>The setup needs to be able to dynamically scale up very quickly in order to handle sudden bursts of traffic, while at the same time being able to scale down to zero in order to be cost-effective. This last part is essential when working with <a href="https://nextjs.org/docs/app/building-your-application/rendering/server-components">server components</a>, for example, where the deep tangling between client and server code <a href="https://x.com/youyuxi/status/1804331313421521101">can break older clients</a> unless every version of the server code ever deployed is available indefinitely.</p>
<p>One obvious answer to these requirements is serverless computing, as attested by official Next.js documentation that <a href="https://nextjs.org/blog/next-8#serverless-nextjs">confirms the benefits of this model</a>:</p>
<blockquote>
<blockquote>
<p>Serverless allows for distributed points of failure, infinite scalability, and is incredibly affordable with a &quot;pay for what you use&quot; model.</p>
</blockquote>
</blockquote>
<p>This clearly advantageous computing paradigm is precisely how Vercel has run Next.js sites in their own infrastructure for years. Given that Next.js is an open framework, it is reasonable to expect that you'd be able to use that same model in any serverless provider of your choice. But it's not that simple.</p>
<p>Next.js once had <a href="https://nextjs.org/blog/next-8#serverless-nextjs">a serverless mode</a> that you could enable with a configuration property, but it was <a href="https://github.com/vercel/next.js/pull/41495">removed without further explanation in October 2022</a>. No equivalent mode was ever introduced.</p>
<p>The official React documentation, which <a href="https://github.com/vercel/next.js/pull/41495">the Next.js team help maintain</a>, says that Next.js can be <a href="https://react.dev/learn/creating-a-react-app#nextjs-app-router">deployed to <em>«any serverless hosting»</em></a>, but there is no official documentation whatsoever for this.</p>
<p>This means that any providers who want to offer support for Next.js with the same computing model that the framework itself promotes must reverse-engineer their way to a custom implementation.</p>
<h3 id="fact-3-vercel-specific-code-paths"><a class="heading-anchor" href="#fact-3-vercel-specific-code-paths">¶</a> Fact #3: Vercel-specific code paths</h3>
<p>Next.js has <a href="https://github.com/search?q=repo%3Avercel%2Fnext.js+NEXT_MINIMAL+path%3A%2F%5Epackages%5C%2Fnext%5C%2F%2F&amp;type=code">code paths</a> that are only ever executed for sites deployed to Vercel. An example of this is a private flag called <a href="https://github.com/vercel/next.js/discussions/29801"><em>minimal mode</em></a>, which allows Vercel to shift work away from the framework and run it on their edge infrastructure.</p>
<p>Here's an example of why that matters. <a href="https://nextjs.org/blog/next-12#introducing-middleware">Next 12 introduced middleware</a>, a way to address use cases such as feature flags, A/B tests and advanced routing. What's common in all of these use cases is the need to run logic on the hot path, behind the cache, with very low latency.</p>
<p>The announcement included this:</p>
<blockquote>
<blockquote>
<p>This works out of the box using <code>next start</code>, as well as on Edge platforms like Vercel, which use Edge Middleware.</p>
</blockquote>
</blockquote>
<p>In practice, this means that you have two options: use <code>next start</code> and run middleware alongside the rest of your application in your <em>origin</em> server (which is typically running in a single region, after the cache), or use one of the «<em>Edge platforms like Vercel</em>» to run middleware at the edge, before the cache, unlocking all the incredible use cases that <a href="https://vercel.com/resources/edge-middleware-experiments-personalization-performance">Vercel boasted in the resources linked in the announcement</a>.</p>
<p>The phrase «<em>Edge platforms like Vercel</em>» surely means that there are many alternatives out there because other providers were given the option to also implement middleware at the edge, right? No.</p>
<p>This secret minimal mode is what allowed Vercel to break out middleware from the rest of the application so they could run it at the edge, but only Vercel has access to it.</p>
<p>Netlify does support running middleware at the edge, but we've done it at the expense of having a full team of engineers dedicated to reverse-engineering the framework and building our own edge middleware implementation on top of undocumented APIs. This type of commitment is just impossible for smaller companies that simply do not have the resources to fight this battle, which makes most of them <a href="https://www.stormkit.io/blog/why-we-are-dropping-support-for-next-js">stop trying</a>.</p>
<p>As far as I know, Netlify is the only cloud provider to support the full feature set of Next.js outside of Vercel, which doesn't make sense to me. With Next.js having such a sizeable share of the market, I would expect a lot more hosting options, which would foster competition and innovation across the board, ultimately benefitting users and the web.</p>
<p>So why is there a hidden door in Next.js for which only Vercel holds the key? I think it's expected that the framework maintainers regularly experiment with features before they're launched, but minimal mode isn't that. We're talking about an entirely different operation mode for the framework, which has been in the code base for many years and which unlocks capabilities that are reserved for the for-profit company that owns the framework.</p>
<p>If WordPress had a privileged code path that was only accessible to sites deployed to Automattic properties, would it be trusted as a truly open project and would it have the dominance it has today?</p>
<h2 id="security-posture"><a class="heading-anchor" href="#security-posture">¶</a> Security posture</h2>
<p>Let's go back to the security incident. On Friday, March 21st at 10:17 AM (UTC), Vercel published <a href="https://github.com/advisories/GHSA-f82v-jwr5-mffw">a CVE for a critical security incident</a>, ranked with a severity of 9.1 out of 10.</p>
<p>In essence, it was possible for anyone to completely bypass Next.js middleware by sending a specific header in the request. This is important because <a href="https://nextjs.org/blog/next-12#introducing-middleware">authentication was one of the flagship use cases of middleware</a>, and this exploit meant that anyone could bypass the authentication layer and gain access to protected resources.</p>
<p>As the incident unravelled, a few things became apparent. First of all, the vulnerability was <a href="https://nextjs.org/blog/cve-2025-29927#timeline">reported to the Next.js team on February 27th</a>, but it wasn't until March 14th that the team started looking into it. Once they did, they started pushing fixes for <a href="https://github.com/vercel/next.js/commit/5fd3ae8f8542677c6294f32d18022731eab6fe48">Next 14</a> and <a href="https://github.com/vercel/next.js/commit/52a078da3884efe6501613c7834a3d02a91676d2">Next 15</a> within a couple of hours.</p>
<p>So by March 14th (at the latest), Vercel knew they had a serious incident on their hands. The responsible thing to do at that point would be to immediately disclose the vulnerability to other providers, so that they could assess the impact to their own customers and take any necessary actions to protect them as quickly as possible. At times like these, our duty to protect users should rise above any competition between companies.</p>
<p>That is not what happened. It took Vercel 8 (eight) days to reach out to Netlify. In that time, they managed to push patches to Next.js, cut two releases, and even write a blog post that framed the incident as something that Vercel's firewall had <em>«proactively protected»</em> their customers from (even though <a href="https://x.com/cramforce/status/1903648110863343871?s=46">their CTO later said</a> that their firewall had nothing to do with it).</p>
<p>I think it's incredibly disingenuous to spin a critical security vulnerability in your open-source project as a strength of your product, with absolutely no consideration for whether users in other providers were also affected and what they should do to mitigate. In fact, they wouldn't even know this, because they hadn't even reached out to us at this point.</p>
<p>After <a href="https://bsky.app/profile/eduardoboucas.com/post/3lky5uuo5os2o">being called out on social media</a>, Vercel have rewritten the blog post to remove any mention of their firewall and clarify which providers had been affected and whether their customers had to take any action.</p>
<p><span id="update-1"></span></p>
<p>Vercel has then <a href="https://vercel.com/blog/postmortem-on-next-js-middleware-bypass#2025-03-21">released a postmortem</a> where they said — for the first time — that on March 21st they were able to «<em>verify Netlify and Cloudflare Workers were not impacted</em>». This is directly contradicted by their staff <a href="https://x.com/eduardoboucas/status/1904672921206865935">reaching out to Netlify on March 22nd</a> offering help to «<em>get a patch up</em>». If we were not impacted, what was there to patch?</p>
<p>This lack of consideration for any users outside of Vercel has created unnecessary anxiety and confusion for a lot of people, leaving some providers scrambling to <a href="https://x.com/elithrar/status/1903411980070797691">find a solution</a> and then having to <a href="https://x.com/elithrar/status/1903526240847331362">partially roll it back</a>, others <a href="https://x.com/ClerkDev/status/1903497002828120426">announcing that they were not vulnerable</a> when in reality <a href="https://x.com/n2d4wastaken/status/1903748178874360024?s=46">they were</a>, etc.</p>
<p>As you read this, it's impossible for anyone to know how many sites out there are still vulnerable to this exploit, many of which would've been safe if things were handled differently.</p>
<p>And at the height of all this mess, Vercel's leadership had... <a href="https://x.com/rauchg/status/1903528305002762387">a different focus</a>.</p>
<h2 id="but-vercel-owns-next-js"><a class="heading-anchor" href="#but-vercel-owns-next-js">¶</a> But Vercel owns Next.js</h2>
<p>They do. And they have every right to make a business out of the framework that they've put so much work, talent, time and energy into building and growing. I'm not disputing that.</p>
<p>But that growth holds them to a high bar of standards that, in my opinion, they have repeatedly failed to meet.</p>
<p><em>«If Vercel own Next.js, what incentive do they have to open it up to other providers?»</em> is <a href="https://x.com/jamonholmgren/status/1904174718779072575">a question I sometimes see</a> and which I find intriguing. What incentives does Redis have for opening up their software when they own Redis Cloud? Why make Grafana open when Grafana Cloud is owned by the same company? Or WordPress, ClickHouse and many others?</p>
<p>The incentive is that they <em>have</em> to do those things if they choose to publish their software as open-source and not as a closed, proprietary solution. Their success is intrinsically associated with their users having the guarantee that they are free to choose whatever provider offers the service that meets their needs at any given time.</p>
<h2 id="wrapping-up"><a class="heading-anchor" href="#wrapping-up">¶</a> Wrapping up</h2>
<p>It's not my business to say which framework you should use. If you like Next.js and you still think it's the best tool for the problem you need to solve, you should absolutely use it. But I hope that this information helps you feel more confident about your decision, whichever way you're leaning.</p>
<p>As for me, I'll keep doing my job to help support the developers who chose to deploy their sites to Netlify, whatever their framework of choice is. And competition aside, I'm genuinely looking forward to help Vercel make Next.js more open and interoperable through the OpenNext movement.<!--tomb--></p>
<p><em>Update (2025-03-26):</em> Added <a href="#update-1">a note</a> about Vercel's most recent postmortem.</p>
<p><em>Update (2025-03-28):</em> Vercel <a href="https://x.com/feedthejim/status/1905741233907245315">have committed</a> <em>«to not introduce any new privileged code paths and to either remove or fully document the ones that exist today, such as minimal mode»</em>. As for timelines, they are <em><a href="https://x.com/feedthejim/status/1905777468835074095">«hoping to get it done this year»</a></em>.</p>
<p><em>Update (2025-04-23):</em> I have <a href="https://github.com/reactjs/react.dev/pull/7771">submitted a PR</a> to fix incorrect information about Next.js deployment options in the React documentation.</p>
<p><em>Update (2026-03-26):</em> Next.js 16.2 added a <a href="https://nextjs.org/blog/nextjs-across-platforms">stable Adapter API</a>.</p>
</description>
        <pubDate>Tue Mar 25 2025 00:00:00 GMT+0000 (Coordinated Universal Time)</pubDate>
        <link>https://eduardoboucas.com/posts/2025-03-25-you-should-know-this-before-choosing-nextjs/</link>
        <guid isPermaLink="true">https://eduardoboucas.com/posts/2025-03-25-you-should-know-this-before-choosing-nextjs/</guid>
        
        
      </item>
    
      <item>
        <title>Publishing Deno modules on Netlify</title>
        <description><p>Runtimes like Node.js rely on a package manager and a registry to install and distribute modules, but Deno has a different spin. It allows developers to import modules directly from a URL, which can be hosted on a CDN, your own server, or really anywhere on the web.</p>
<p>This level of flexibility brings infinite options, so I started looking for the best workflow to release modules in this new paradigm. This article describes the solution I landed on — one that works for solo open-source developers or large development teams in the enterprise world.<!--more--></p>
<p>Here's the gist of it:</p>
<ul>
<li>The source code lives in a <a href="https://github.com/">GitHub</a> repository</li>
<li>Releases are automated using a combination of <a href="https://www.conventionalcommits.org/en/v1.0.0/">Conventional Commits</a> and <a href="https://github.com/googleapis/release-please">Release Please</a></li>
<li>The repository is connected to a <a href="https://www.netlify.com/">Netlify</a> site, which is responsible for serving the modules in version-locked URLs, protecting private modules, serving documentation pages, and a few other niceties</li>
</ul>
<p>Let's get started.</p>
<h2 id="setting-up"><a class="heading-anchor" href="#setting-up">¶</a> Setting up</h2>
<p>The first step is to create a GitHub repository with a few things:</p>
<ul>
<li>A JavaScript or TypeScript <a href="https://github.com/eduardoboucas/deno-module-template/blob/044583aadf14e2842e098669fdc230fd139710dc/src/mod.ts">entry point</a> for the module. This is the file that people will import into their applications.</li>
<li>A <a href="https://github.com/eduardoboucas/deno-module-template/blob/044583aadf14e2842e098669fdc230fd139710dc/.github/workflows/release-please.yml">workflow file</a> for Release Please, which will automate the release process using GitHub Actions.</li>
<li>A <a href="https://github.com/eduardoboucas/netlify-changelog-redirects">Netlify Build Plugin</a> for generating redirects to version-locked URLs.</li>
<li>A Netlify <a href="https://github.com/eduardoboucas/deno-module-template/blob/044583aadf14e2842e098669fdc230fd139710dc/netlify.toml">configuration file</a>, setting the right directories, build command, and response headers.</li>
</ul>
<p>Next, we <a href="https://docs.netlify.com/welcome/add-new-site/">connect the repository to Netlify</a>.</p>
<p>Alternatively, you can use the button below to create everything with one click.</p>
<p><a href="https://app.netlify.com/start/deploy?repository=https://github.com/eduardoboucas/deno-module-template"><img src="https://www.netlify.com/img/deploy/button.svg" alt="Deploy to Netlify"></a></p>
<p>Finally, we can change the site name to something a bit more memorable. You can do this by going to <em>Site settings</em> &gt; <em>General</em> &gt; <em>Change site_name</em>. I picked <code>deno-greeter</code>.</p>
<p>We're now ready to use the module in a Deno program.</p>
<pre class="language-shell"><code class="language-shell"><div class="highlight-line">$ deno repl --eval <span class="token string">"import { greet } from 'https://deno-greeter.netlify.app/mod.ts'"</span></div><div class="highlight-line">Download https://deno-greeter.netlify.app/mod.ts</div><div class="highlight-line">Download https://deno-greeter.netlify.app/greetings.ts</div><div class="highlight-line">Deno 1.24.3</div><div class="highlight-line"><span class="token keyword">exit</span> using ctrl+d or close<span class="token punctuation">(</span><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token operator">></span> greet<span class="token punctuation">(</span><span class="token string">"Jane"</span><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token string">"Good morning, Jane!"</span></div><div class="highlight-line"><span class="token operator">></span></div></code></pre>
<h2 id="versioning"><a class="heading-anchor" href="#versioning">¶</a> Versioning</h2>
<p>We could start using our module as is, but we're missing an important part: versioning.</p>
<p>If we want to release a new version that introduces breaking changes, consumers should be able to decide whether and when to update their code.</p>
<p>Unlike Node.js, Deno does not use a <code>package.json</code> file to pin dependencies to specific versions. Instead, the import URLs themselves are expected to point to an immutable version of the module. When the code changes, the URL must also change.</p>
<p>We can achieve this pretty easily with Netlify, as you can configure your site to create a new deploy when a new Git tag is published. If we then configure Release Please to create a new tag for every release, we'll get distinct URLs for each new version of the module.</p>
<p>To do this, open the Netlify dashboard and navigate to <em>Site settings</em> &gt; <em>Build &amp; deploy</em> &gt; <em>Branches</em> and select <em>All</em>.</p>
<figure
  class="figure figure--caption figure--frame"
>
  <img
    alt="Configuration of branch deploys in Netlify"
    class="figure__image"
    loading="lazy"
    onload="this.parentElement.classList += ' figure--loaded'"
    src="/posts/2022-11-07-publishing-deno-modules/deploy-configuration.png"
    width=""
  />
  <figcaption class="figure__caption">Configuration of branch deploys in Netlify</figcaption>
</figure>
<p>To test the release flow, make some changes to the module code, push a commit using the <code>feat:</code> prefix, and open a pull request. Once you merge it, Release Please will create <a href="https://github.com/eduardoboucas/deno-greeter/pull/1">a release pull request</a> automatically. Merging it will complete the release.</p>
<p>If you go to the <em>Deploys</em> page of the Netlify dashboard, you'll see a new deploy in progress. Once it finishes, you'll see that <code>deno-greeter</code> is available at <a href="https://deno-greeter.netlify.app/1.0.0/mod.ts">https://deno-greeter.netlify.app/1.0.0/mod.ts</a> — this is an immutable URL that points to version 1.0.0 of the module, and will be unaffected by future versions.</p>
<p>This process will happen automatically for every new pull request that you merge. New versions of the module will respect <a href="https://semver.org/">Semantic Versioning</a> and will be inferred automatically from the Conventional Commits convention prefixes used in your commits:</p>
<ul>
<li><code>fix:</code> will generate a patch version</li>
<li><code>feat:</code> will trigger a minor version</li>
<li><code>feat!:</code> signals a major version with breaking changes</li>
</ul>
<h2 id="private-modules"><a class="heading-anchor" href="#private-modules">¶</a> Private modules</h2>
<p>The current setup works great for public modules, but you might want to restrict access to our module to people with the right credentials. This is a very common scenario in an enterprise setting, where teams of developers want to share common pieces of proprietary code without making it accessible to the outside world.</p>
<p>To do this, we can leverage Netlify's <a href="https://docs.netlify.com/visitor-access/password-protection">password protection feature</a>. We start by creating a <code>_headers</code> file in the <code>src</code> directory with the following contents.</p>
<pre class="language-text"><code class="language-text"><div class="highlight-line">/*</div><div class="highlight-line">  Basic-Auth: janedoe:supersecret123</div></code></pre>
<p>This protects your site with a username and password combination, leveraing <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme">basic HTTP authentication</a>.</p>
<p>To use the module in their applications, consumers must set a <code>DENO_AUTH_TOKENS</code> environment variable with the right credentials when running Deno CLI commands.</p>
<pre class="language-text"><code class="language-text"><div class="highlight-line">DENO_AUTH_TOKENS=janedoe:supersecret123@deno-greeter.netlify.app</div></code></pre>
<p>You can read more about <a href="https://deno.land/manual@v1.27.1/linking_to_external_code/private">private modules in Deno</a> and explore <a href="https://docs.netlify.com/visitor-access/role-based-access-control/">more advanced authentication mechanisms</a> offered by Netlify.</p>
<h2 id="documentation-site"><a class="heading-anchor" href="#documentation-site">¶</a> Documentation site</h2>
<p>Using a full-fledged website deployment platform to host your modules comes with a few extra perks. For example, if you want to create a documentation site for your project, you don't need any additional configuration or tooling. You can place the HTML files in the <code>src</code> directory and Netlify will serve them on the same URL.</p>
<p>If you want to something like <a href="https://docusaurus.io/">Docusaurus</a> to build your docs, or even a full-fledged web framework like Gatsby or Next.js, you totally can.</p>
<p>And because the site is deployed alongside the module's code, they will be versioned together. So if someone is using version 1.0.0 of your module, they can find the documentation for that specific version at <a href="https://deno-greeter.netlify.app/1.0.0">https://deno-greeter.netlify.app/1.0.0</a>.</p>
<h2 id="hosted-version"><a class="heading-anchor" href="#hosted-version">¶</a> Hosted version</h2>
<p>Because we're using a Netlify site, we have a series of primitives at our disposal, including <a href="https://docs.netlify.com/edge-functions/overview/">Edge Functions</a>.</p>
<p>Edge functions are themselves based on Deno, so we can easily write one that imports our module and uses it to produce a response to an HTTP call. This lets us create a hosted version of our module, which applications can interact with by issuing an HTTP request rather than an in-memory import.</p>
<p>This can work as an alternative interface for applications that are using another JavaScript runtime or a different programming language entirely.</p>
<pre class="language-typescript"><code class="language-typescript"><div class="highlight-line"><span class="token keyword">import</span> <span class="token punctuation">{</span> greet <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"../../src/mod.ts"</span><span class="token punctuation">;</span></div><div class="highlight-line"></div><div class="highlight-line"><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>req<span class="token punctuation">:</span> Request<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></div><div class="highlight-line">  <span class="token keyword">const</span> url <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URL</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span></div><div class="highlight-line">  <span class="token keyword">const</span> name <span class="token operator">=</span> url<span class="token punctuation">.</span>searchParams<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></div><div class="highlight-line">  <span class="token keyword">const</span> greeting <span class="token operator">=</span> <span class="token function">greet</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span></div><div class="highlight-line"></div><div class="highlight-line">  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Response</span><span class="token punctuation">(</span>greeting<span class="token punctuation">)</span><span class="token punctuation">;</span></div><div class="highlight-line"><span class="token punctuation">}</span></div></code></pre>
<p>By deploying this edge function, <code>deno-greeter</code> can be accessed at <a href="https://deno-greeter.netlify.app/api?name=Jane">https://deno-greeter.netlify.app/api?name=Jane</a>.</p>
<h2 id="parting-thoughts"><a class="heading-anchor" href="#parting-thoughts">¶</a> Parting thoughts</h2>
<p>This is admittedly not be the most impartial technical piece ever, since <a href="/about">I work at Netlify</a>. I did honestly start from the premise of finding the best workflow for <em>me</em>, which I decided to share. So while there are many options out there, I struggled to find one that packs this much functionality with such simplicity.</p>
<p>With the <em>«this is not a Netlify marketing piece»</em> caveat out of the way, I would love to hear about the workflow that works for you. If you end up using the same as mine, definitely <a href="https://twitter.com/eduardoboucas">hit me up</a>!<!--tomb--></p>
</description>
        <pubDate>Mon Nov 07 2022 00:00:00 GMT+0000 (Coordinated Universal Time)</pubDate>
        <link>https://eduardoboucas.com/posts/2022-11-07-publishing-deno-modules/</link>
        <guid isPermaLink="true">https://eduardoboucas.com/posts/2022-11-07-publishing-deno-modules/</guid>
        
        
      </item>
    
      <item>
        <title>Shipping Node.js projects at Netlify</title>
        <description><p>At Netlify, we use a diverse set of technologies, languages and paradigms to build our product. Along with Ruby, Go, Rust and others, we write quite a bit of JavaScript. All flavors of it.</p>
<p>My team is responsible for several mission-critical Node.js services: the <a href="https://github.com/netlify/cli">Netlify CLI</a>, the <a href="https://github.com/netlify/build">build system</a> and the <a href="https://github.com/netlify/zip-it-and-ship-it">serverless function bundler</a> are just a few examples. Despite the sheer number of repositories we maintain, and especially considering that some of them are open-source projects with daily contributions from the community, you might be surprised to learn that our team is relatively small.</p>
<p>I lifted the curtain on the tools and processes that we rely on to make this happen.<!--more--></p>
</description>
        <pubDate>Wed Mar 03 2021 00:00:00 GMT+0000 (Coordinated Universal Time)</pubDate>
        <link>https://eduardoboucas.com/posts/2021-03-03-shipping-nodejs-at-netlify/</link>
        <guid isPermaLink="true">https://eduardoboucas.com/posts/2021-03-03-shipping-nodejs-at-netlify/</guid>
        
        
      </item>
    
      <item>
        <title>Running Staticman on Netlify Functions</title>
        <description><p>In 2016, I started working on a tool to fill the gap in user-generated content on (what is now called) the Jamstack: <a href="https://staticman.net">Staticman</a>. Since then, the entire ecosystem has grown by leaps and bounds, offering developers a set of tools and primitives that were mostly unreachable just four years ago.<!--more--></p>
<p>In this post, we'll use one of those primitives – serverless functions – to deploy Staticman without having to get anywhere near infrastructure configuration. In particular, I'll show you how to deploy an <a href="https://www.11ty.dev/">Eleventy</a> blog with Staticman-powered comments with just a few clicks.</p>
<h2 id="tl-dr"><a class="heading-anchor" href="#tl-dr">¶</a> TL;DR</h2>
<p>Head to the <a href="https://github.com/eduardoboucas/eleventy-blog-staticman">Eleventy blog template</a> and click <a href="https://app.netlify.com/start/deploy?repository=https://github.com/eduardoboucas/eleventy-blog-staticman">Deploy to Netlify</a>.</p>
<h2 id="a-brief-history"><a class="heading-anchor" href="#a-brief-history">¶</a> A brief history</h2>
<p>When Staticman was first released, it consisted of a Node application with an included web server. There was a free public instance available for anyone to use, but that wasn't a sustainable proposition for an open-source project (because money), so eventually people had to venture into deploying the application themselves.</p>
<p>As much as services like <a href="https://www.heroku.com/">Heroku</a> absorb much of the complexity involved in this, it's still by no means a straightforward process, especially for less technical folks.</p>
<p>With serverless computing power getting more accessible and more intrinsically connected to the Jamstack paradigm, it makes perfect sense to rethink the way Staticman is deployed. Rather than relying on a centralised, multi-tenant service, we can wrap Staticman as a serverless function that lives alongside – and gets deployed with – our site.</p>
<h3 id="prior-art"><a class="heading-anchor" href="#prior-art">¶</a> Prior art</h3>
<p>Before anything else, I want to point out that I was not the first one to explore this approach. Folks like <a href="https://github.com/bashlk/staticman-netlify-function">Prabashwara Seneviratne</a> and <a href="https://www.jpatters.com/2020/12/static-comments-with-serverless-staticman-1/">Jordan Patterson</a> have done a tremendous job at creating content and tooling around the idea of a serverless Staticman.</p>
<p>I've simply restructured the application to make this use case more convenient and performant.</p>
<h2 id="going-serverless"><a class="heading-anchor" href="#going-serverless">¶</a> Going serverless</h2>
<p>While it's still possible to run Staticman as a regular Node server, the core application has been isolated and is now published as <a href="https://www.npmjs.com/package/@staticman/core">a separate module</a>, which can be easily included as part of a serverless function without the unnecessary weight of the unnecessary server-related logic.</p>
<p>Staticman was initially built as a multi-tenant service, where one instance could serve an unknown set of repositories. The ability to run one Staticman instance for each site allows for some interesting optimisations.</p>
<p>For one, we can store site-specific configurations within the application, for in-memory access – this saves us a round-trip to the Git provider to retrieve the configuration data.</p>
<p>Secondly, we avoid all the complexity around asymmetric key encryption, which was the only way to guarantee a secure communication between the server and any number of guest sites. Now, any sensitive information can be stored in environment variables that will be exposed to the serverless function.</p>
<h2 id="see-it-in-action"><a class="heading-anchor" href="#see-it-in-action">¶</a> See it in action</h2>
<p>I've forked the <a href="https://github.com/11ty/eleventy-base-blog">Base Blog</a> starter for the <a href="https://11ty.dev">Eleventy</a> static site generator and added a commenting system powered by Staticman.</p>
<figure
  class="figure figure--caption "
>
  <img
    alt="Eleventy blog with comments"
    class="figure__image"
    loading="lazy"
    onload="this.parentElement.classList += ' figure--loaded'"
    src="/posts/2020-12-23-staticman-netlify-functions/blog.png"
    width=""
  />
  <figcaption class="figure__caption">Eleventy blog with comments</figcaption>
</figure>
<p>You can deploy it to a free <a href="https://netlify.com">Netlify</a> site with just a few clicks, with all the Staticman configuration being taken care of automatically for you. Here's how:</p>
<ol>
<li>
<p>Go to <a href="https://github.com/eduardoboucas/eleventy-blog-staticman">https://github.com/eduardoboucas/eleventy-blog-staticman</a> and click on <a href="https://app.netlify.com/start/deploy?repository=https://github.com/eduardoboucas/eleventy-blog-staticman">Deploy to Netlify</a></p>
</li>
<li>
<p>You'll be redirected to Netlify, where you can connect your GitHub account if you haven't done so before</p>
</li>
<li>
<p>Fill in the following details:</p>
<ul>
<li>
<p><strong>GitHub access token</strong>: A GitHub Personal Access Token used by Staticman to push new comments to your repository on your behalf. See <a href="https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token">this guide</a> on how to create one.</p>
</li>
<li>
<p><strong>Repository name</strong>: The name of your GitHub repository, including your username or organization (e.g. <code>eduardoboucas/eleventy-blog-staticman</code>).</p>
</li>
<li>
<p><strong>reCAPTCHA site key</strong> and <strong>reCAPTCHA site secret</strong>: If you want to use <a href="https://www.google.com/recaptcha/about/">reCAPTCHA</a> to protect your form against spam attacks, you should insert your site key and secret, which you can obtain <a href="https://www.google.com/recaptcha/admin">here</a>. If you don't want to use reCAPTCHA, you can leave these blank.</p>
</li>
</ul>
</li>
<li>
<p>Done! 🎉</p>
</li>
</ol>
<figure
  class="figure figure--caption "
>
  <img
    alt="Netlify setup screen"
    class="figure__image"
    loading="lazy"
    onload="this.parentElement.classList += ' figure--loaded'"
    src="/posts/2020-12-23-staticman-netlify-functions/netlify-setup.png"
    width=""
  />
  <figcaption class="figure__caption">Netlify setup screen</figcaption>
</figure>
<p>Every time you submit a comment, a new file will be pushed to the repository, which will trigger a Netlify build with the updated content.</p>
<h2 id="configuration"><a class="heading-anchor" href="#configuration">¶</a> Configuration</h2>
<p>You can tweak the Staticman instance by changing the <a href="https://github.com/eduardoboucas/eleventy-blog-staticman/blob/master/functions/staticman.js#L19-L33">configuration object</a>.</p>
<p>For example, if you'd like new entries to generate a pull request for your approval, as opposed to a direct commit to your main branch, you can set <code>moderation: true</code>. This is also where you'd configure which fields are allowed and whether some of them are required.</p>
<p>To see all possible configuration options, check the <a href="https://github.com/eduardoboucas/eleventy-blog-staticman/blob/master/functions/staticman.js#L19-L33">Staticman documentation</a>.</p>
<h2 id="parting-words"><a class="heading-anchor" href="#parting-words">¶</a> Parting words</h2>
<p>I sincerely hope that this simplified setup flow lowers the barrier of entry for Staticman, allowing many more developers to build amazing projects with pure Git-based user-generated content (like Dave's <a href="https://daviddarnes.github.io/splashed/liked/">Splashed</a>).</p>
<p>The features described in this post still have fresh paint – if you run into any issues, or if you have any feedback whatsoever, <a href="https://twitter.com/eduardoboucas">let me know</a>. <!--tomb--></p>
</description>
        <pubDate>Wed Dec 23 2020 00:00:00 GMT+0000 (Coordinated Universal Time)</pubDate>
        <link>https://eduardoboucas.com/posts/2020-12-23-staticman-netlify-functions/</link>
        <guid isPermaLink="true">https://eduardoboucas.com/posts/2020-12-23-staticman-netlify-functions/</guid>
        
        
      </item>
    
      <item>
        <title>Smashing Podcast Episode #11</title>
        <description><p>I was a guest on episode #11 of Smashing Magazine's podcast. I had the opportunity to chat with Drew McLellan about <a href="https://github.com/stackbithq/sourcebit">Sourcebit</a> and how it can help developers connect any datasource to their JAMstack sites. Have a listen!<!--more--></p>
</description>
        <pubDate>Wed Mar 18 2020 00:00:00 GMT+0000 (Coordinated Universal Time)</pubDate>
        <link>https://eduardoboucas.com/posts/2020-03-18-sourcebit-smashing-podcast/</link>
        <guid isPermaLink="true">https://eduardoboucas.com/posts/2020-03-18-sourcebit-smashing-podcast/</guid>
        
        
      </item>
    
      <item>
        <title>Building a web-connected traffic light</title>
        <description><p>Our lives are constantly flooded with information destined from the digital world: the sound of a Slack message on the laptop, a WhatsApp message popping up on the watch, or the email push notifications making our phones buzz incessantly. The screens we surround ourselves with are little black holes that are constantly teasing us with a snippet of information, knowing that we can't avoid getting sucked in to see more.<!--more--></p>
<p>For a while, I've been toying with the idea of building a physical device that could sit peacefully in my living space and convey important information about a select part of my digital life in a minimalistic, non-obtrusive way. Something with a visual language so simple that I would be able to process a message immediately, without having to stop what I'm doing to parse and make sense of pixels on a screen.</p>
<p>A few years back, I completely fell in love with the <a href="https://papersignals.withgoogle.com/">Paper Signals</a> experiment from Google. A cute little arrow pointing up or down, or an umbrella opening and closing is exactly the kind of simplicity I wanted.</p>
<p>This idea stayed at the back of my mind for a long time, and a few months ago I decided to build my own Internet-connected physical device.</p>
<figure
  class="figure figure--caption figure--frame"
>
  <video autoplay class="figure__video" loop>
    <source src="/posts/2020-02-06-web-connected-traffic-light/paper-signal.mp4" type="video/mp4" />
    Your browser does not support the video tag.
  </video>
  <figcaption class="figure__caption">Google Paper Signals experiment</figcaption>
</figure>
<h2 id="a-traffic-light"><a class="heading-anchor" href="#a-traffic-light">¶</a> A traffic light</h2>
<p>I created a list of ideas and possible formats, based on capabilities and hardware requirements. In the end, the winner was... a traffic light.</p>
<p>For one, it communicates in a language that is pretty much universal (albeit with some <a href="https://en.wikipedia.org/wiki/Traffic_light#Variations">regional variations</a>). And, most notably, the language is much more flexible than we give it credit for – the lights are usually associated with road traffic, but the different colours can convey an infinite number of meanings when placed in different contexts.</p>
<h2 id="shopping-and-assembling"><a class="heading-anchor" href="#shopping-and-assembling">¶</a> Shopping and assembling</h2>
<p>I started doing some research into electronics and hardware. My traffic light would consist of a <a href="https://www.adafruit.com/product/3400">Raspberry Pi Zero W</a>, a $10 computer not much larger than a ping-pong ball, and three LED lights.</p>
<p>As for the enclosure, I <a href="https://github.com/eduardoboucas/signally-case">designed it</a> in a vector graphics editor and had it 3D-printed and shipped to me. That was a nerve-racking process, because I didn't know if I had messed something up until I ordered a print and waited a few days for it to arrive at my doorstep. (It's like not being able to test your code until you deploy it to production. <em>Yikes!</em>)</p>
<p>After a failed enclosure design, after reading up on Ohm's law, LEDs and resistors, and after ruining a soldering iron (don't ask), I finally managed to piece everything together and assemble my traffic light. Yay!</p>
<figure
  class="figure figure--caption figure--frame"
>
  <img
    alt="The LEDs, the Raspberry Pi Zero and the finished enclosure"
    class="figure__image"
    loading="lazy"
    onload="this.parentElement.classList += ' figure--loaded'"
    src="/posts/2020-02-06-web-connected-traffic-light/traffic-light.jpg"
    width=""
  />
  <figcaption class="figure__caption">The LEDs, the Raspberry Pi Zero and the finished enclosure</figcaption>
</figure>
<h2 id="writing-the-software"><a class="heading-anchor" href="#writing-the-software">¶</a> Writing the software</h2>
<p>With the hardware in place, it was time to write the software for remote-controlling the state of the lights.</p>
<p>I wanted the device to be connected to the web and controllable via HTTP calls to a public URL. This way, I could easily integrate the device with any platform that supports webhooks.</p>
<p>The Raspberry Pi Zero W has built-in Wi-Fi, which made it a breeze to connect it to my home network and to the Internet, but exposing a public web server is a whole other story. I wanted to be able to plug it into <em>any</em> network and not have to worry about redirecting ports on the router, creating firewall rules and that sort of thing.</p>
<p>Eventually, I decided to create a Node.js app (the client) that I would install on the device, and a central API that I would host on the cloud. This API would then communicate with the client via WebSocket, which uses a single TCP connection for two-way communication and eliminates the issue of being behind a router or firewall.</p>
<figure
  class="figure figure--caption "
>
  <img
    alt="Diagram of API/client communication"
    class="figure__image"
    loading="lazy"
    onload="this.parentElement.classList += ' figure--loaded'"
    src="/posts/2020-02-06-web-connected-traffic-light/diagram.png"
    width=""
  />
  <figcaption class="figure__caption">Diagram of API/client communication</figcaption>
</figure>
<p>I've open-sourced the code for the <a href="https://github.com/eduardoboucas/signally-server">API</a> and <a href="https://github.com/eduardoboucas/signally-client">client</a>, in case you're interested in having a look.</p>
<h2 id="integration-with-netlify"><a class="heading-anchor" href="#integration-with-netlify">¶</a> Integration with Netlify</h2>
<p>At this point, I had a public URL that I could ping to set the state of the lights. Now, the sky was the limit!</p>
<p>I'm interested in monitoring the builds on my site, which is hosted on Netlify. Luckily, they have support for webhooks in their <a href="https://docs.netlify.com/site-deploys/notifications/">Deploy notifications</a>, which lets you configure a set of URLs to hit when a build starts, succeeds or fails.</p>
<p>You can see the device in action in the video below. As soon as I start a build, the amber light turns on; it'll then turn green if the build succeeds or red if it fails.</p>
<div class="post-video-container">
  <div class="post-video">
    <div class="post-video__inner" style="padding-bottom: 56.25%">
      <iframe width="560" height="315" src="https://www.youtube.com/embed/9o1FkDqEUCU?controls=1&autoplay=1&loop=1&modestbranding=1" frameborder="0" allowfullscreen></iframe>
    </div>
  </div>
</div>
<p>Netlify is just one of a million possible integrations. I had it hooked up to <a href="https://travis-ci.com/">Travis CI</a> for a while, tracking the build state of a project. You could integrate it with your email provider or Slack account, showing you information about unread emails or direct messages. Maybe you could plug it into your Google Calendar account, to give you an idea of how busy you are for the day.</p>
<p>The possibilities are endless.</p>
<h2 id="wrapping-up"><a class="heading-anchor" href="#wrapping-up">¶</a> Wrapping up</h2>
<p>This was a super exciting weekend project and I actually had bigger plans for it. The idea was to improve the software and create an open-source ecosystem of devices, designed and produced by independent makers. People would be able to build integrations, submit designs and order devices online.</p>
<p>Unfortunately, I never got around to working on it, but I still ended up with a pretty neat little device that I can integrate with anything on the web. That's cool.<!--tomb--></p>
</description>
        <pubDate>Thu Feb 06 2020 00:00:00 GMT+0000 (Coordinated Universal Time)</pubDate>
        <link>https://eduardoboucas.com/posts/2020-02-06-web-connected-traffic-light/</link>
        <guid isPermaLink="true">https://eduardoboucas.com/posts/2020-02-06-web-connected-traffic-light/</guid>
        
        
      </item>
    
      <item>
        <title>Custom JSON (de)serialisation in JavaScript</title>
        <description><p>If you write JavaScript applications, you probably find yourself having to read and write data structures to local files or remote APIs, which means you're probably good friends with <code>JSON.stringify</code> and <code>JSON.parse</code>. We should really get to know our friends, so let's talk about something these methods do that you may not be familiar with.<!--more--></p>
<p>Writing an object to disk or sending it over the network involves converting it to a sequence of characters such that it can be converted back to its original format and restore all its properties when needed. This is called <strong>serialisation</strong> and <strong>deserialisation</strong>.</p>
<p>You can choose any format you like for serialising and deserialising JavaScript objects, but JSON (JavaScript Object Notation) is a likely candidate since support for it is baked into the language – <code>JSON.stringify()</code> for serialisation and <code>JSON.parse()</code> for deserialisation.</p>
<p>So, let's look at a simple JavaScript object and run a simple test: we'll serialise it into a variable, deserialise that variable and then check that the resulting value contains the same structure and properties as the original object.</p>
<pre class="language-js"><code class="language-js"><div class="highlight-line"><span class="token keyword">var</span> original <span class="token operator">=</span> <span class="token punctuation">{</span></div><div class="highlight-line">  name<span class="token punctuation">:</span> <span class="token string">'John Doe'</span><span class="token punctuation">,</span></div><div class="highlight-line">  yearOfBirth<span class="token punctuation">:</span> <span class="token number">1988</span></div><div class="highlight-line"><span class="token punctuation">}</span></div><div class="highlight-line"><span class="token keyword">var</span> serialized <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>original<span class="token punctuation">)</span></div><div class="highlight-line"><span class="token keyword">var</span> deserialized <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>serialized<span class="token punctuation">)</span></div><div class="highlight-line"></div><div class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span></div><div class="highlight-line">  original<span class="token punctuation">.</span>name <span class="token operator">===</span> deserialized<span class="token punctuation">.</span>name <span class="token operator">&amp;&amp;</span></div><div class="highlight-line">  original<span class="token punctuation">.</span>yearOfBirth <span class="token operator">===</span> deserialized<span class="token punctuation">.</span>yearOfBirth</div><div class="highlight-line"><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token comment">// > true</span></div></code></pre>
<p>Sure enough, it works. But what if we add more exotic values to the mix?</p>
<p>JSON has support for 6 data types: strings, numbers, booleans, <code>null</code>, objects and arrays. What happens if we try to serialise a value of a different type, say a regular expression?</p>
<pre class="language-js"><code class="language-js"><div class="highlight-line"><span class="token keyword">var</span> original <span class="token operator">=</span> <span class="token punctuation">{</span></div><div class="highlight-line">  email<span class="token punctuation">:</span> <span class="token regex">/^j(ohn){0,1}(\.){0,1}doe@example.com$/</span><span class="token punctuation">,</span></div><div class="highlight-line">  name<span class="token punctuation">:</span> <span class="token string">'John Doe'</span><span class="token punctuation">,</span></div><div class="highlight-line">  yearOfBirth<span class="token punctuation">:</span> <span class="token number">1988</span></div><div class="highlight-line"><span class="token punctuation">}</span></div><div class="highlight-line"></div><div class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>original<span class="token punctuation">.</span>email<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'john.doe@example.com'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token comment">// > true</span></div><div class="highlight-line"></div><div class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>original<span class="token punctuation">.</span>email<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'jdoe@example.com'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token comment">// > true</span></div><div class="highlight-line"></div><div class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>original<span class="token punctuation">.</span>email<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'jdoe@example.org'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token comment">// > false</span></div><div class="highlight-line"></div><div class="highlight-line"><span class="token keyword">var</span> serialized <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>original<span class="token punctuation">)</span></div><div class="highlight-line"><span class="token keyword">var</span> deserialized <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>serialized<span class="token punctuation">)</span></div><div class="highlight-line"></div><div class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>deserialized<span class="token punctuation">.</span>email<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'john.doe@example.com'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token comment">// > "TypeError: deserialized.email.test is not a function</span></div><div class="highlight-line"></div><div class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>deserialized<span class="token punctuation">.</span>email<span class="token punctuation">)</span></div><div class="highlight-line"><span class="token comment">// > {}</span></div></code></pre>
<p>What happened here?</p>
<p>You see, <code>JSON.stringify</code> doesn't know how to serialise a regular expression, so it writes it as an empty object. When we run the serialised value through <code>JSON.parse</code>, the <code>email</code> property will contain an empty object without any reference to the regular expression that existed in the original object. That's why calling the <code>.test()</code> method on it will throw an error.</p>
<h2 id="custom-de-serialisation-method"><a class="heading-anchor" href="#custom-de-serialisation-method">¶</a> Custom (de)serialisation method</h2>
<p><code>JSON.stringify</code> allows us to supply a custom serialisation method, which specifies the format and shape with which a value is serialised. We can write a method that checks for regular expressions and encodes them in our own custom representation, as long as that representation is made up of built-in JSON types only.</p>
<p>For example, let's represent the regular expression <code>/foo/i</code> as <code>[&quot;&lt;&lt;REGEX&quot;, &quot;/foo/i&quot;, &quot;REGEX&gt;&gt;&quot;]</code> – this is an array of strings, so we're now only using types that can be natively serialised to JSON.</p>
<p>This only works if we make the deserialisation method aware of this notation. It needs to be on the lookout for arrays with 3 elements that begin and end with those special strings we came up with. When it finds one, it knows it represents a regular expression so it can extract the expression from it.</p>
<p>Here's the final code:</p>
<pre class="language-js"><code class="language-js"><div class="highlight-line"><span class="token keyword">function</span> <span class="token function">deserialize</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span></div><div class="highlight-line">  <span class="token keyword">if</span> <span class="token punctuation">(</span></div><div class="highlight-line">    Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span></div><div class="highlight-line">    value<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">3</span> <span class="token operator">&amp;&amp;</span></div><div class="highlight-line">    value<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'&lt;&lt;REGEXP'</span> <span class="token operator">&amp;&amp;</span></div><div class="highlight-line">    value<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'REGEXP>>'</span></div><div class="highlight-line">  <span class="token punctuation">)</span> <span class="token punctuation">{</span></div><div class="highlight-line">    <span class="token keyword">let</span> <span class="token punctuation">[</span><span class="token punctuation">,</span> exp<span class="token punctuation">,</span> flags<span class="token punctuation">]</span> <span class="token operator">=</span> value<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token regex">/\/(.*)\/(.*)?/</span><span class="token punctuation">)</span></div><div class="highlight-line"></div><div class="highlight-line">    <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">RegExp</span><span class="token punctuation">(</span>exp<span class="token punctuation">,</span> flags <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">)</span></div><div class="highlight-line">  <span class="token punctuation">}</span></div><div class="highlight-line"></div><div class="highlight-line">  <span class="token keyword">return</span> value</div><div class="highlight-line"><span class="token punctuation">}</span></div><div class="highlight-line"></div><div class="highlight-line"><span class="token keyword">function</span> <span class="token function">serializer</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span></div><div class="highlight-line">  <span class="token keyword">if</span> <span class="token punctuation">(</span>value <span class="token keyword">instanceof</span> <span class="token class-name">RegExp</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></div><div class="highlight-line">    <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string">'&lt;&lt;REGEXP'</span><span class="token punctuation">,</span> value<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'REGEXP>>'</span><span class="token punctuation">]</span></div><div class="highlight-line">  <span class="token punctuation">}</span></div><div class="highlight-line"></div><div class="highlight-line">  <span class="token keyword">return</span> value</div><div class="highlight-line"><span class="token punctuation">}</span></div><div class="highlight-line"></div><div class="highlight-line"><span class="token keyword">var</span> original <span class="token operator">=</span> <span class="token punctuation">{</span></div><div class="highlight-line">  email<span class="token punctuation">:</span> <span class="token regex">/^j(ohn){0,1}(\.){0,1}doe@example.com$/</span><span class="token punctuation">,</span></div><div class="highlight-line">  name<span class="token punctuation">:</span> <span class="token string">'John Doe'</span><span class="token punctuation">,</span></div><div class="highlight-line">  yearOfBirth<span class="token punctuation">:</span> <span class="token number">1988</span></div><div class="highlight-line"><span class="token punctuation">}</span></div><div class="highlight-line"></div><div class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>original<span class="token punctuation">.</span>email<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'john.doe@example.com'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token comment">// > true</span></div><div class="highlight-line"></div><div class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>original<span class="token punctuation">.</span>email<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'jdoe@example.com'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token comment">// > true</span></div><div class="highlight-line"></div><div class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>original<span class="token punctuation">.</span>email<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'jdoe@example.org'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token comment">// > false</span></div><div class="highlight-line"></div><div class="highlight-line"><span class="token keyword">var</span> serialized <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>original<span class="token punctuation">,</span> serializer<span class="token punctuation">)</span></div><div class="highlight-line"><span class="token keyword">var</span> deserialized <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>serialized<span class="token punctuation">,</span> deserialize<span class="token punctuation">)</span></div><div class="highlight-line"></div><div class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>deserialized<span class="token punctuation">.</span>email<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'john.doe@example.com'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token comment">// > true</span></div><div class="highlight-line"></div><div class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>deserialized<span class="token punctuation">.</span>email<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'jdoe@example.com'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token comment">// > true</span></div><div class="highlight-line"></div><div class="highlight-line">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>deserialized<span class="token punctuation">.</span>email<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'jdoe@example.org'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></div><div class="highlight-line"><span class="token comment">// > false</span></div></code></pre>
<p>You can use this method to serialise and deserialise any type you want, like functions or custom classes.<!--tomb--></p>
<p><em>Code is available on <a href="https://jsbin.com/nucenan/edit?js,console">JSbin</a></em></p>
</description>
        <pubDate>Tue Feb 04 2020 00:00:00 GMT+0000 (Coordinated Universal Time)</pubDate>
        <link>https://eduardoboucas.com/posts/2020-02-04-custom-json-serialisation-deserialisation/</link>
        <guid isPermaLink="true">https://eduardoboucas.com/posts/2020-02-04-custom-json-serialisation-deserialisation/</guid>
        
        
      </item>
    
      <item>
        <title>What is an API?</title>
        <description><p>Google Calendar API, Google Maps API, Twitter API, GitHub API, jQuery API, React API, the DOM API. Is everything an API? What <em>is</em> an API and how can it be such an ubiquitous concept, present in such a diverse range of platforms and technologies?<!--more--></p>
<p>Most applications and devices we use every day have some form of interface that is conceived for the interaction with humans. That may be in the form of graphical elements on a website or mobile app, conversational text on a chat bot or even the sound of a synthesised voice on a digital personal assistant. The common link between these is that they were all built and optimised for the human sensory system.</p>
<h2 id="human-vs-machine"><a class="heading-anchor" href="#human-vs-machine">¶</a> Human vs. machine</h2>
<p>But there is a different type of interface, one that is built for interaction with other programs or machines. That is an API – an Application Programming Interface (with <em>Programming</em> being the key word).</p>
<p>Some applications have an API as their only interface, when their sole purpose is to be used as building blocks by other programs – like the jQuery API, the React API or the DOM API. Others have an API in addition to a user interface, which is like a restaurant having a seating area for customers on foot and a drive-through window for people in cars – it’s the same application, generally handling the same content, but made available to different types of consumers in the way that is most convenient to them.</p>
<p>That’s why you open Google Calendar in your browser when you want to check what your diary looks like for tomorrow, but instead you use the Google Calendar API if you want to write a program that retrieves that information programmatically.</p>
<p>But isn't it be possible to create a program that is smart enough to interact with a standard user interface (one designed for humans) and avoid the hassle of building and maintaining a separate interface? Yes, it is, just like it’s technically possible for a pedestrian to order food from the drive-through window, and for a skillful motorist to drive right to their reserved table at the restaurant – it’s just not the best tool for the job.</p>
<p>It’s extremely difficult for a computer program to match a person’s ability to interact with an interface that was built for humans, and even more difficult is for it to adapt to change in the same way that a human does. This brings us to what I consider to be the two most important aspects of an API, and what sets them apart from a user interface: the format and the contract.</p>
<h2 id="the-format"><a class="heading-anchor" href="#the-format">¶</a> The format</h2>
<p>The format is the set of technologies and languages used by the application to interact with the consumer. Since the consumer is a machine, requests and responses must be formatted in a way that is optimised for machines – sign language, songs or poetry are interesting ways for humans to communicate with each other, but not so efficient when it comes to machines.</p>
<h2 id="the-contract"><a class="heading-anchor" href="#the-contract">¶</a> The contract</h2>
<p>The contract is what assures developers that an API will continue to respond to their application’s requests in a consistent way. You see, if on a graphical user interface a light green button on the top-left corner changes to a dark green button on the bottom-right corner, most people will instinctively adapt and continue using the application without any instructions or assistance.</p>
<p>Programs are a bit more strict. If an API changes the word <code>tomato</code> to <code>tomAto</code> without giving consumers the opportunity to update their code, entire applications can potentially break.</p>
<p>Contracts are a way for APIs to announce what exactly they produce and what they receive; as long as developers are following the rules that were established upfront, things will continue to work the same way.</p>
<h2 id="api-paradigms"><a class="heading-anchor" href="#api-paradigms">¶</a> API paradigms</h2>
<p>So how do you build an API? Is there a specific set of technologies and tools that you must use? Not really.</p>
<p>As long as you use an appropriate format and put a contract in place, you can use whatever programming paradigm, language and technology stack you want – even a static JSON file on a server can work as an API, if documented and published properly.</p>
<p>There are, however, some guidelines and specifications that apply to Web APIs, which are APIs that connect a server and a client over the web using the HTTP protocol. These are merely recommendations on things like naming conventions, what endpoints (URLs) to expose and how to convey success and error states.</p>
<h3 id="rpc"><a class="heading-anchor" href="#rpc">¶</a> RPC</h3>
<p>The earliest paradigm was RPC (Remote Procedure Call) which basically works as a function that is executed on a remote server. If you wanted to create an RPC API for adding, editing and removing articles, you’d have an endpoint at <code>/getArticles</code> for retrieving items, <code>/addArticle</code> for creating, etc. Like an in-memory function, each RPC endpoint can accept any number of arguments.</p>
<h3 id="rest"><a class="heading-anchor" href="#rest">¶</a> REST</h3>
<p>A more popular and flexible alternative is REST (REpresentational State Transfer) and it works by representing entities as resources. In our example from above, an article would be a resource, represented at <code>/articles</code>. To interact with this resource, the client is expected to use one of the available HTTP verbs to indicate the type of operation – <code>GET</code> for reading, <code>POST</code> for creating, <code>PATCH</code> for updating and <code>DELETE</code> for deleting.</p>
<p>REST is characterised by utilising HTTP features whenever possible, like verbs, headers and status codes.</p>
<h3 id="graph-ql"><a class="heading-anchor" href="#graph-ql">¶</a> GraphQL</h3>
<p>A more recent paradigm that has been gaining a lot of traction is GraphQL. Unlike RPC or REST, GraphQL exposes a single endpoint for all interactions, relying on a custom query language (akin to SQL) to tell the server exactly what data to get and in what structure. It’s possible for a single query to retrieve data from multiple collections of documents and automatically resolve the relationships between them.</p>
<p>GraphQL has a strong focus on performance, allowing consumers to receive only the fields they require (although this behaviour is sometimes falsely portrayed as exclusive to GraphQL, but <a href="https://jsonapi.org/format/#fetching-sparse-fieldsets">REST supports it too</a>).</p>
<h2 id="wrapping-up"><a class="heading-anchor" href="#wrapping-up">¶</a> Wrapping up</h2>
<p>We've established that an API is just another type of interface, but one with a specific <em>format</em> and a very strict structure (the <em>contract</em>). If you're thinking about building one, <a href="https://swagger.io/blog/api-development/how-to-build-an-api/">this article</a> by Nicole Sievers.<!--tomb--></p>
</description>
        <pubDate>Wed Jan 08 2020 00:00:00 GMT+0000 (Coordinated Universal Time)</pubDate>
        <link>https://eduardoboucas.com/posts/2020-01-08-what-is-an-api/</link>
        <guid isPermaLink="true">https://eduardoboucas.com/posts/2020-01-08-what-is-an-api/</guid>
        
        
      </item>
    
      <item>
        <title>GitHub Pages as a blogging platform</title>
        <description><p>There’s a huge number of platforms to choose from if you’re looking to build a blog. WordPress is a likely first candidate, as these days it powers over <a href="https://w3techs.com/technologies/history_overview/content_management/all">30% of the entire web</a>, but products like Medium, Blogger, or Wix, to name just a few, are also popular and powerful alternatives.<!--more--></p>
<p>All of these platforms are similar in what they achieve, but different in what they offer and how they work. Some of them are free, whilst others are paid or place advertising alongside your content; some of them take care of the hosting for you, others require you to run a piece of software in your own infrastructure; some allow you to use a custom domain name, while others charge a fee for that. It feels almost impossible to find a solution that ticks all the boxes.</p>
<p>There’s another alternative that might do just that, and it’s not a name that usually comes to mind when you think of a blogging platform: GitHub. With <a href="https://pages.github.com/">Pages</a>, any GitHub repository can be turned into a website associated with the easiest development workflow you can imagine. You don’t need to run any software or worry about setting up a server, and there’s no FTP, SSH or anything else getting in the way – you simply push your content to the repository and it goes live automatically.</p>
<p>Since GitHub offers a free tier with support for an unlimited number of repositories, this effectively means that you can host as many websites as you like, for free, with no advertising or setup required. Plus, it allows you to use your own domain name with HTTPS. That doesn’t sound like a bad deal, does it?</p>
<h2 id="compared-to-more-traditional-blogging-platforms"><a class="heading-anchor" href="#compared-to-more-traditional-blogging-platforms">¶</a> Compared to more traditional blogging platforms</h2>
<p>Before going any further, it’s important to point out a few key differences between GitHub Pages and the more traditional blogging platforms. Most of these platforms behave as opaque services, offering a set of visual interfaces from where you can manage your content. What happens between that and your site going live is not really under your control, particularly the how and where the content is actually stored. Will you be able to access it if the service suddenly shuts down? How easy is it to extract the content if you decide to migrate it to a different platform?</p>
<p>In that sense, GitHub Pages is a more transparent option. Because it uses the Git protocol, you can easily keep a copy of the repository in your local system, or even set up multiple remote mirrors using different providers (like Bitbucket and GitLab), so you’re not forced to put all eggs in one basket. Also, content is stored in flat files in the format of your choice. There’s no magical interface between you and the content – it’s just there.</p>
<p>However, this also makes GitHub Pages more of a barebones solution. It doesn’t come with a content management system right out of the box (even though you can one), and under the hood it represents a fundamentally different paradigms from the likes of WordPress. Rather than having a system that can dynamically fetch, generate and manipulate content on every request, GitHub Pages only lets you serve static files, which means your pages must be generated in advance.</p>
<p>This paradigm might not be the most obvious choice for certain applications, but a blog site is usually a great fit. Content is not expected to change every few seconds and it’s usually not automatically generated, so it’s perfectly reasonable to build a set of static pages every time you write a new post. Once those pages are generated, you can simply push the files to a repository and they will be live on your GitHub-powered blog within seconds.</p>
<h2 id="getting-started-with-git-hub-pages"><a class="heading-anchor" href="#getting-started-with-git-hub-pages">¶</a> Getting started with GitHub Pages</h2>
<p>To get started, the first thing you’ll need is a repository. To create one, head to <a href="https://github.com/new">https://github.com/new</a> and you’ll find a screen similar to the one below.</p>
<figure
  class="figure  "
>
  <img
    alt=""
    class="figure__image"
    loading="lazy"
    onload="this.parentElement.classList += ' figure--loaded'"
    src="/posts/2019-08-14-github-pages-blogging-platform/screen1.png"
    width=""
  />
  <figcaption class="figure__caption"></figcaption>
</figure>
<p>After choosing a name and description for the repository, proceed to Create repository. If all goes well, you should be taken to your new repository page. It’s not terribly interesting at this point, since we haven’t added any content, but it shows the repository address in the box highlighted in red. Make note of that, we’ll use it in a minute.</p>
<figure
  class="figure  "
>
  <img
    alt=""
    class="figure__image"
    loading="lazy"
    onload="this.parentElement.classList += ' figure--loaded'"
    src="/posts/2019-08-14-github-pages-blogging-platform/screen2.png"
    width=""
  />
  <figcaption class="figure__caption"></figcaption>
</figure>
<p>Next, let’s build our first page. Create a new directory and place a file called index.html inside it, with some simple HTML.</p>
<pre class="language-html"><code class="language-html"><div class="highlight-line"><span class="token doctype">&lt;!DOCTYPE html></span></div><div class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span><span class="token punctuation">></span></span></div><div class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span></div><div class="highlight-line">  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">></span></span>My new blog<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">></span></span></div><div class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span></div><div class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">></span></span></div><div class="highlight-line">  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>Welcome<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span></div><div class="highlight-line"></div><div class="highlight-line">  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>This is where it all begins!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span></div><div class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">></span></span></div><div class="highlight-line"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></div></code></pre>
<p>Now it’s time to publish. There are various ways in which you can interact with your repository. For this tutorial, we’re going with the plain old terminal, as we’ll use a very short and simple list of commands, but if you’d rather use a graphical interface like <a href="https://desktop.github.com/">GitHub Desktop</a>, that’s perfectly fine too.</p>
<p>Open a terminal window and navigate to the directory in which you saved the file (<code>cd /path/to/your/directory</code>). Once there, type the commands below:</p>
<pre class="language-shell"><code class="language-shell"><div class="highlight-line"><span class="token function">git</span> init</div><div class="highlight-line"><span class="token function">git</span> remote add origin git@github.com:eduardoboucas/stackbit-blog.git <span class="token punctuation">(</span>replace this with your repository address<span class="token punctuation">)</span></div><div class="highlight-line"><span class="token function">git</span> add index.html</div><div class="highlight-line"><span class="token function">git</span> commit -m <span class="token string">"Create first page"</span></div><div class="highlight-line"><span class="token function">git</span> push origin master</div></code></pre>
<p>What’s happening here? We’re starting a new Git repository in the directory we’ve created and then linking it to the GitHub repository. Then, we’re adding <code>index.html</code> to the list of files to be published, committing it with a message describing the operation, and finally pushing it to the remote repository.</p>
<p>If you refresh your repository page on GitHub, you should now see the file we’ve just uploaded.</p>
<figure
  class="figure  "
>
  <img
    alt=""
    class="figure__image"
    loading="lazy"
    onload="this.parentElement.classList += ' figure--loaded'"
    src="/posts/2019-08-14-github-pages-blogging-platform/screen2.png"
    width=""
  />
  <figcaption class="figure__caption"></figcaption>
</figure>
<p>Finally, we need to enable GitHub Pages for this repository. On the screen shown above, click on <em>Settings</em> and scroll down to the <em>GitHub Pages</em> section. In the <em>Source</em> selector, select <em>master</em> as the branch to build from and click <em>Save</em>.</p>
<p>After that, you should see a message confirming that your site is ready to be published and indicating its URL. If you navigate to it, you should be able to see your new website.</p>
<figure
  class="figure  "
>
  <img
    alt=""
    class="figure__image"
    loading="lazy"
    onload="this.parentElement.classList += ' figure--loaded'"
    src="/posts/2019-08-14-github-pages-blogging-platform/screen3.png"
    width=""
  />
  <figcaption class="figure__caption"></figcaption>
</figure>
<h2 id="adding-jekyll-to-the-mix"><a class="heading-anchor" href="#adding-jekyll-to-the-mix">¶</a> Adding Jekyll to the mix</h2>
<p>We have managed to create a functional solution, but in reality it’s not a very practical one. Whilst it’s fine to manually generate the HTML pages for this example site, it’s not a sustainable process for a reasonably-sized project.</p>
<p>For example, imagine that we want to create a landing page for our blog where all the posts are listed. For each entry, we want to display the title, an excerpt and a Read more button which, when clicked, takes people to another page where the full post is displayed. This means that creating or updating a post suddenly involves editing two files. Once we add things like pagination and category or tag aggregation pages, that number starts to grow and it becomes unmanageable.</p>
<p>Also, if you wanted to migrate your content to a different platform in the future, or perhaps reuse it across different channels, you’d want it to be in a format and structure that is as raw as possible, decoupled from any implementation or technology. Arguably, storing it in HTML files that are bloated with presentation markup is not the best way to do it.</p>
<p>This is where static site generators come in. A static site generator is a piece of software that takes content in various formats and generates HTML pages with it as per your requirements. This means taking a directory full of blog posts, in a format like Markdown, and generating landing pages, full post pages, pagination, tag and category aggregation pages, search and anything else you can think of. All you need to do is run a command (usually called a build step) and an entire site will be generated automatically for you.</p>
<p>There are <a href="https://www.staticgen.com/">hundreds of static site generators</a> to choose from, but in this article we’ll focus on one in particular: <a href="https://jekyllrb.com/">Jekyll</a>. The reason for this is that Jekyll has a special status with GitHub Pages. Whereas with any other static site generator you need to run the build step in your machine and push the resulting files to the repository, with Jekyll you can simply push the source files and GitHub Pages will run the build step for you, publishing the resulting files automatically.</p>
<p>To add Jekyll to our blog, first we must delete the <code>index.html</code> file we created previously. Then, install Jekyll and tell it the name of the directory where it should create the site. We should use the directory we’ve created previously, as it’s already linked to the GitHub repository.</p>
<pre class="language-shell"><code class="language-shell"><div class="highlight-line">gem <span class="token function">install</span> bundler jekyll</div><div class="highlight-line">jekyll new stackbit-blog</div></code></pre>
<p>To build the site on your system, run <code>jekyll serve</code>. It will generate all the HTML files and create a URL where the site will be available. Every time you modify a file, the site will be regenerated and the URL will reflect your changes.</p>
<p>If you’re using a github.io URL (e.g. <code>your-username.github.io/your-repository</code>), you must tell Jekyll that the base path is <code>/your-repository</code> instead of the root path. To do this, open the <code>_config.yml</code> file and set the baseurl property to <code>/your-repository</code> (in my case, this was <code>/stackbit-blog</code>).</p>
<p>When you’re ready to push your new Jekyll site live, you can run:</p>
<pre class="language-shell"><code class="language-shell"><div class="highlight-line"><span class="token function">git</span> add <span class="token keyword">.</span></div><div class="highlight-line"><span class="token function">git</span> commit -m “Add Jekyll”</div><div class="highlight-line"><span class="token function">git</span> push origin master</div></code></pre>
<p>In a few seconds, you’ll be able to refresh your GitHub URL and see your new Jekyll-powered site in action.</p>
<figure
  class="figure  "
>
  <img
    alt=""
    class="figure__image"
    loading="lazy"
    onload="this.parentElement.classList += ' figure--loaded'"
    src="/posts/2019-08-14-github-pages-blogging-platform/screen5.png"
    width=""
  />
  <figcaption class="figure__caption"></figcaption>
</figure>
<h2 id="choosing-a-theme-for-your-jekyll-site"><a class="heading-anchor" href="#choosing-a-theme-for-your-jekyll-site">¶</a> Choosing a theme for your Jekyll site</h2>
<p>To change the look and feel of your site, you can try different themes. A quick search for “jekyll themes” will lead you to thousands of themes to choose from, with different layouts and styles. When you find one that you like, you can enable it by <a href="https://jekyllrb.com/docs/themes/#installing-a-theme">adding it to the configuration file</a>.</p>
<p>Alternatively, GitHub makes a handful of themes available for you to install via their interface. To try it, go to <em>Settings</em>, scroll down to <em>GitHub Pages</em> and click on <em>Change theme</em>. You’ll see a preview of each theme available, and once you find one that you like, hit <em>Select theme</em> and your site will update accordingly.<!--tomb--></p>
</description>
        <pubDate>Wed Aug 14 2019 00:00:00 GMT+0000 (Coordinated Universal Time)</pubDate>
        <link>https://eduardoboucas.com/posts/2019-08-14-github-pages-blogging-platform/</link>
        <guid isPermaLink="true">https://eduardoboucas.com/posts/2019-08-14-github-pages-blogging-platform/</guid>
        
        
      </item>
    
  </channel>
</rss>