Case insensitive query parameters with OpenRasta

Posted by ghay on September 8th, 2010 – 2 Comments

Our API currently accepts case insensitive query parameters e.g. pagesize == pageSize == PaGeSiZe. Unfortunately OpenRasta is a lot more strict. If we have a URI mapped:

ResourceSpace.Has.ResourcesOfType<ApiResponse>()
	.AtUri("artist/search?q={searchterm}&pagesize={pagesize}")

and we make a request for “artist/search?q=bob+marley&pageSize=10″, the page size query parameter is not processed correctly. To deal with this we wrote a Pipeline Contributor to lowercase the query parameters before the URI is matched.

public class QueryParamLowerCaser : IPipelineContributor {
	public void Initialize(IPipeline pipelineRunner) {
		pipelineRunner.Notify(LowerCaseQueryParams)
			.Before<KnownStages.IUriMatching>();
	}
 
	public PipelineContinuation LowerCaseQueryParams(ICommunicationContext context) {
		var uri = context.Request.Uri;
		var newQuery = LowerCaseQueryString(uri.Query);
 
		context.Request.Uri = new Uri(uri.GetLeftPart(UriPartial.Path) + newQuery);
 
		return PipelineContinuation.Continue;
	}
 
	private static string LowerCaseQueryString(string queryString) {
		var queryParams = HttpUtility.ParseQueryString(queryString);
		var lowerCasedParams = new List<string>();
 
		foreach (string queryParam in queryParams) {
			lowerCasedParams.Add(queryParam.ToLower() + '=' + queryParams[queryParam]);
		}
 
		var newQuery = "?" + string.Join("&", lowerCasedParams);
		return newQuery;
	}
}

This can be wired into the pipeline in your Configuration Source:

ResourceSpace.Uses.PipelineContributor<QueryParamLowerCaser>();

At the moment this affects every request, but it could easily be modified to be more selective.

UPDATE: Following a suggestion from Seb this has been converted into a (more lightweight) UriDecorator

	public class QueryParamLowerCaser : IUriDecorator
	{
		public bool Parse(Uri uri, out Uri processedUri)
		{
			processedUri = LowerCaseQueryString(uri);
			return true;
		}
 
		private static Uri LowerCaseQueryString(Uri uri)
		{
			var queryParams = HttpUtility.ParseQueryString(uri.Query);
 
			var lowerCasedParams = new List<string>();
			foreach (string queryParam in queryParams)
			{
				if (queryParam != null)
					lowerCasedParams.Add(queryParam.ToLower() + '=' + queryParams[queryParam]);
			}
 
			var newQuery = "?" + string.Join("&", lowerCasedParams);
 
			return new Uri(uri.GetLeftPart(UriPartial.Path) + newQuery);
		}
 
		public void Apply() { }
	}

Then you just need to register it with your DependencyResolver.

  1. Hey there!

    Is the parameter mapped to a parameter name in a method or a property on a DTO? If that’s the case, it shouldn’t be like that, we should probably make sure this doesn’t happen.

    There’s a bunch of patches coming up for the 2.0 RTM build around querystrings, may be worth sending an email on the mailing list and filling a bug report on youtrack.codebetter.com, and I’ll make sure the rules are more relaxed.

    Thanks for hte blog post!

    Seb

  2. ghay says:

    A parameter name in a method. I assumed it was by design, as URIs should be case-sensitive, but it would be a breaking change for us.

    We also have some problems with Optional parameters, but some of the pull requests should fix that (I hope).

    I’ll wait till the dust settles on 2.0 and see where we are. Thanks for the framework!

  1. There are no trackbacks for this post yet.

Leave a Reply

*