DEV Community

Jan Dvorak
Jan Dvorak

Posted on • Edited on

Simple server side router for Meteor

Or how I modernized Picker router, but first some background on what is going on in Meteor on the server side when it comes to routing.

I'm using React with react-router without SSR. Recently I decided that I wanted to add RSS for my blogs and I wanted it to be generated on the server. So I needed some way to establish a route on the server and have it execute my function.

Now, going back in history this is relatively easy with Meteor centric routers like iron:router or flow:router where we could set server routes. Under the hood Meteor uses connect so there was already an infrastructure to get server requests and is accessible via meteor/webapp.

import { WebApp, WebAppInternals } from 'meteor/webapp'
Enter fullscreen mode Exit fullscreen mode

In my case my previous use was to manually set browser policy headers without any package (but that is for another article). Now you can easily get server requests and intercept static routes as we see in connect documentation (here adjusted for Meteor):

WebApp.rawConnectHandlers.use('/foo', function fooMiddleware(req, res, next) {
  // req.url starts with "/foo"
  next()
})
Enter fullscreen mode Exit fullscreen mode

Now if you want to add params into the route you are out of luck. Connect is a minimalist library and doesn't do param resolution. Now there are quiet a few routers for node, most famously express. But that is an overkill since we already have the basics and integrating any of them would most likely break your Meteor app. So what are you to do if you don't want to build it yourself. Thankfully there already is a solution.

After few hours I found an old project meteorhacks:picker which provides a server side router for Meteor (it is the part that handles server side routing for flow:router) and plays nice with anything else you might have setup.

Now the problem is that meteorhacks:picker is 5 years old! Probably not something you want to add to a new project. Well, worry not! I have done the work of modernizing the package and right now I'm lobbying for it to be moved to Meteor Community Packages so that we can update the package without having to create a new namespace on Atmosphere. So for now you can go to my repository and download the code into your packages folder.

Use Picker

After that you can install picker (it will pick your local version):

meteor add storyteller:picker
Enter fullscreen mode Exit fullscreen mode

Now on your server you can import Picker:

import { Picker } from 'meteor/storyteller:picker'
Enter fullscreen mode Exit fullscreen mode

For my RSS I want to only handle GET requests so I create a filter:

const rssRoutes = Picker.filter(function(req, res) {
  return req.method === "GET"
})
Enter fullscreen mode Exit fullscreen mode

After that I can now create my routes to handle building the RSS:

rssRoutes.route('/blog/:userId/rss', (params, req, res) => {
  if (!params.userId) return return404(res)
  const data = articlesData(BLOG_TYPES.USER, params.userId)
  if (!data) return return404(res)
  res.setHeader('content-type', 'application/rss+xml')
  res.writeHead(200)
  res.end(buildRss(data))
})
Enter fullscreen mode Exit fullscreen mode

Simple, isn't it? params passes in the params you have defined in the route and under params.query you will get an object with search parameters from routes like /blog/storyteller/rss?output=xml.

Where to get this?

UPDATE: My version of Picker has become part of Meteor Community Packages and you can get it from Atmosphere.

So where is this available? Currently you can download the code from my repository to your local packages.

Not ideal, I know. I have opened an issue on the original Picker to move it to Meteor Community Packages, but given that Arunoda has not been responsive we will most likely have to take my codebase and publish it under MCP namespace. But hopefully in few weeks I will have an update here.


If you like my work, please consider supporting me on GitHub Sponsors ❤️.

Top comments (1)

Collapse
 
bratelefant profile image
bratelefant

Hi! How can I add middleware only to certain routes, is there a fancy way to do that?