Close

Sign up to Gadget

Start for free

Announcing HTTP Routes

Harry Brundage
February 4, 2022

So much of what we do as developers can be patternized into something higher level – like GraphQL. Gadget’s autogenerated GraphQL API provides a secure, performant, re-usable API for accessing data from your backend that just works for the majority of use cases.

Sometimes however – you need to escape the high level patterns because you just want to render some g’dang HTML. Or, an image, a PDF, a redirect, a React website, or whatever! Gadget applications are not limited to only using the high level pieces – instead, developers intermix the autogenerated parts of Gadget with their own lower level HTTP path handlers that do whatever stuff doesn’t fit the pattern. HTTP Routes are powered by the same scalable serverless backend infrastructure that powers your GraphQL API, so there’s no extra setup involved, and your application can respond to whatever changing load it needs to.

HTTP Routes run in a similar context to a Gadget Action, which means they have access to all the same conveniences, like an `api` object for manipulating data in the database, a `connections` object for making API calls to Shopify or other third parties, a rich `logger` object, and the application’s `config`. Like any other serverless function you can do anything you want in your route, including fetching data from the database or rendering a specific kind of content. Unlike other serverless functions though, Gadget HTTP routes don’t require setting up your own database, managing connection pooling, prewarming, and use plain old node.js instead of a custom runtime with missing features.

A great example of an HTTP route is generating content that doesn’t fit nicely into the JSON response of a GraphQL API. For example, we might generate an image on demand and serve it right to the user with the correct headers:


// in routes/GET-image.js
const { generateImage } = require('js-image-generator');
 
const handler = async (_request, reply) => {
   generateImage(800, 600, 80, function(err, image) {
       if (err) throw err;
       reply.header("content-type", "image/jpeg");
       reply.send(image.data);
   });
}
 
export default handler;

Gadget HTTP routes are built on top of fastify, which is an excellent web server for node.js. Fastify has an incredibly rich ecosystem of high quality plugins that you can use to extend the base level functionality of your application as well.

For example, we can use fastify-static and fastify-basic-auth to serve password protected static files from a Gadget application:


// in routes/+files.js
const path = require('path');
 
const plugin = async (server) => {
 // add fastify hooks to authenticate requests before they reach the file server
 server.register(require('fastify-basic-auth'), {
   validate: async (username, password) => {
     if (username != 'example' || password != "example") {
       throw new Error("Invalid username or password")
     }
   }, authenticate: {
     realm: "Example"
   }
 })
 
 // serve any file out of the `public` directory of this app at the `/files` URL path
 server.register(require('fastify-static'), {
   root: path.join(__dirname, '..', 'public'),
   prefix: '/files',
 })
};
 
export default plugin;

HTTP routes in Gadget represent a really important principle for Gadget as a platform: we want developers to go fast so we offer easy to use, high level building blocks like a GraphQL API, but we don’t presume these pieces will solve every use case. Throughout Gadget, we’ve added escape hatches like HTTP routes that let developers take full control over their application when the high level tool doesn’t quite fit.

We’re so excited to see what you can build with HTTP routes, and if you want to nerd out on anything Gadget, please join us in our Discord here.

For more examples on what you can build using the Shopify Connection, check out these additional blog posts:

Keep reading to learn about how it's built

Under the hood

We're on Discord, drop in and say hi!
Join Discord
Bouncing Arrow