Each HTTP route in Gadget has two parts: a URL pattern and a handler function.
URL patterns
The URL pattern for a route in Gadget is defined by the route file's path within the routes/ directory. The name of the file should start with an HTTP verb, then have a dash, then have a valid URL segment. Requests made with that HTTP verb and segment will invoke the route handler in that file.
For example, if your gadget app is my-app.gadget.app and you have a source file at routes/test/GET-data.js, someone accessing https://my-app.gadget.app/test/data in the browser would run the handler in that source file.
Example filename patterns
Route filename
Matched requests
routes/GET.js
GET /
routes/GET-foo.js
GET /foo or GET /foo/, but not GET /bar or POST /foo
routes/GET-[id].js
GET /foo, GET /bar, GET /1 but not POST /foo or GET /foo/bar
routes/blogs/GET-[id].js
GET /blogs/1, GET /blogs/welcome-to-gadget
routes/blogs/POST.js
POST /blogs, but not POST /blogs/1
routes/category/[category]/blogs/GET-[id].js
GET /category/cooking/blogs/1 or GET /category/baking/blogs/5
routes/repos/GET-[...].js
GET /repos/foo or GET /repos/foo/bar/baz
Dynamic segments
If you have a segment in your URL that isn't static, such as an id to or a slug, you can capture a variable by adding a segment wrapped in square brackets. For example, routes/blog/post/GET-[id].js would capture id=5 when accessing /blog/post/5. You can then access these captured segments in request.params when writing a route handler.
You can also capture part of a path segment, as long as it's separated by a dash. For example, routes/blog/[id]/GET-post-[postId] would capture id=3, postId=10 when accessing /blog/3/post-10.
If you need more flexibility in how parts of the path are captured, you can manually register a route through a route plugin.
All JS/TS files in the routes/ directory must be prefixed with an HTTP verb for route handlers, or prefixed with a + for route
plugins. Any other filename under the routes/ directory will throw an error.
Wildcard segments
If you have a portion of your URL that should match any valid URL segment, including slashes, you can capture it with a wildcard segment using [...]. For example, routes/blog/post/GET-[...].js will match any request to /blog/post/foo, or /blog/post/foo/bar, or any longer segment as well. Wildcards are useful for catchall redirects, 404 pages, or routing schemes that include slashes. You can access the captured wildcard value in request.params['*'] when writing a route handler.
5await reply.code(404).send("Unknown post URL: "+ request.params["*"]);
6}
7}
Root URLs
If you want to register a route for the root of your application, or a route at the root of a folder, name the file after just the HTTP verb. For example, routes/GET.js will match requests to /, or routes/foo/bar/POST.js will match routes to /foo/bar.
Available HTTP methods
Route handler functions can listen to any of the standard HTTP methods (also known as verbs) by using that HTTP method as the first part of the file name:
GET, like GET-list.js
POST, like POST-create.js
PUT, like PUT-update.js
PATCH, like PATCH-update.js
DELETE
HEAD
OPTIONS
Route handlers can also be prefixed with ANY to respond to any HTTP method, like ANY-data.js. To know which HTTP method was used to make a request, you can utilize the request.method property.
Route plugins are files that customize your app for the associated routes. You add a route plugin by creating a file starting with a + sign in a particular folder of routes, to which then modifies the Fastify server powering your app for all the routes in that folder (or subfolders of it). Route plugins in one folder don't modify routes in sibling folders -- only that folder and its subfolders.
Decorate requests with a logged-in user for authentication
Redirect anonymous users to a login page
Checking user credentials for permissions to access a set of routes
Conditionally registering routes in loops or if statements with server.get, ...
Route plugins are a function that looks like a regular Fastify plugin. Plugin files should export a single function that receives a Fastify server instance as an argument.
Register point-of-view for HTML rendering
JavaScript
1// in routes/+views.js
2importFastifyViewfrom"point-of-view";
3exportdefaultasyncfunction(server){
4await server.register(FastifyView,{
5engine:{
6eta:require("eta"),// an example view engine, see https://eta.js.org/
Route plugins are applied to all routes in the same folder as the plugin, and all subfolders of that folder. For example, if you have a plugin in routes/admin/+auth.js, it will affect all routes in routes/admin and all subfolders of routes/admin, such as routes/admin/users and routes/admin/posts. It will not affect routes in other folders, such as routes/public or routes/blog.
1routes/
2 +plugins.js // will affect all routes in any folder
3 admin/
4 +auth.js // will only affect routes in the admin folder
5 GET.js
6 GET-posts.js
7 users/
8 +customizations.js // will only affect the one route below, and nothing in the routes/admin folder
9 GET.js
10 posts/
11 +images.js // will only affect these posts routes in routes/posts
12 GET.js
13 GET-[id].js
Boot plugins
Boot plugins are server customizations that affect the whole server instead of just a part. They are registered before any other route plugins or the routes themselves. Boot plugins live in the root boot/ folder. The primary use case is to register some global state, such as creating an API client of an external service. It isn't necessary to export anything from a boot plugin, but the only export supported is a function that will take a server instance.
Boot plugins can also be used for setting up other global server-side objects, like error handlers or persistent connections to third-party services.
Deprecated route filename syntax
Gadget supported a previous version of the route filename syntax that isn't compatible with Windows users as it uses filenames with illegal characters on Windows. This route syntax still works, but we recommend moving to the new square-bracket based syntax.
Each old route filename has a corresponding new syntax:
Name
Old syntax
New syntax
Old example
New Example
Single dynamic segment
:name
[name]
routes/GET-:foo.js
routes/GET-[foo].js
Optional dynamic segment
:name?
[[name]]
routes/GET-:foo?.js
routes/GET-[[foo]].js
Folder dynamic segment
:name
[name]
routes/:foo/GET-bar.js
routes/[foo]/GET-bar.js
Wildcard dynamic segment
*
[...]
routes/foo/GET-*.js
routes/foo/GET-[...].js
If you encounter any errors with the square bracket based syntax, please get in touch with the Gadget staff on Discord.