Skip to content

Instantly share code, notes, and snippets.

@gdpelican
Created March 13, 2015 01:30
Show Gist options
  • Save gdpelican/b8017c060c395a90d3df to your computer and use it in GitHub Desktop.
Save gdpelican/b8017c060c395a90d3df to your computer and use it in GitHub Desktop.
A rudimentary URL parser in javascript.
var route = function(format) {
var splitIntoParts = function(url) {
var urlString = url.match(/^[^\?]*/) || [""]
return urlString[0].split('/');
};
var formatParts = splitIntoParts(format); // Split the format into parts for easy reuse
var splitIntoQueryParams = function(url) {
var paramString = url.match(/\?.*$/) || [""];
return paramString[0].split('&');
};
var populateRouteParams = function(instanceParts, params) {
for(var i = 0; i < formatParts.length; i++) {
if (formatParts[i].match(/^:/)) // populate params if the current route part is a variable
params[formatParts[i].replace(/^:/, '')] = instanceParts[i]
else if (formatParts[i] != instanceParts[i]) // otherwise check for equality
throw 'Route does not match format: ' + format;
}
};
var populateQueryParams = function(queryParams, params) {
for(var i = 0; i < queryParams.length; i++) {
if (queryParams[i].length > 0) {
queryParam = queryParams[i].match(/([a-z]*)=([a-z]*)/i); // Split each param around the = sign
params[queryParam[1]] = queryParam[2]; // Set the 'key' value on params to the query param value.
}
}
};
return function(instance) {
var params = {};
try {
populateRouteParams(splitIntoParts(instance), params);
populateQueryParams(splitIntoQueryParams(instance), params);
}
catch(e) { // Log the error, then return an empty set of params
params = {};
console.log(e);
}
return params;
};
};
var apiRoute = route('/api/:version/:collection/:id');
var memberRoute = route('/groups/:groupId/users/:memberId/:action');
console.log(apiRoute('/api/v2/geese/5'));
console.log(apiRoute('/api/v1/mallards/1?color=green&gender=male'));
console.log(apiRoute('/groups/5/users/10/subscribe'))
console.log(memberRoute('/groups/5/users/10/subscribe'));
console.log(memberRoute('/groups/6/users/4/ban?reason=profanity'));
console.log(memberRoute('/api/v1/users/10'));
@gdpelican
Copy link
Author

A couple thoughts / potential area for improvement:

  • If I had a jQuery, I'd likely want to do something like return $.extend({}, populateRouteParams, populateQueryParams), so I didn't have to pass the params object around like that.
  • Right now the query params take precedence over the route params.. I'm not certain if that's right or not? (ie given route /users/:user_id, url /users/1?user_id=2 would return {user_id: 2})
  • Matching the query parameters right now (with this: (/([a-z]*)=([a-z]*)/i)) is pretty wrong, as it will only parse simple alphabetic words correctly (so, member_id, or my%20places would break). I'm sure there's a more complete regex out there, but it seemed out of scope for this.)

@gdpelican
Copy link
Author

Some output from running the above in a console:

Object {version: "v2", collection: "geese", id: "5"} Script snippet #1:53
Object {version: "v1", collection: "mallards", id: "1", color: "green", gender: "male"} Script snippet #1:54
Route does not match format: /api/:version/:collection/:id Script snippet #1:43
Object {} Script snippet #1:55
Object {groupId: "5", memberId: "10", action: "subscribe"} Script snippet #1:57
Object {groupId: "6", memberId: "4", action: "ban", reason: "profanity"} Script snippet #1:58
Route does not match format: /groups/:groupId/users/:memberId/:action Script snippet #1:43
Object {} 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment