If Nancy is inspired by Sinatra I thought I'd have a little fun a create an abstract class that created modules that kind of mimic the behaviour of Rails controllers. Code first, ask questions later...
public abstract class RailslikeControllerFor<TEntity> : NancyModule where TEntity : class
{
public RailslikeControllerFor() : base("/" + typeof(TEntity).Name + "s")
{
Get[@"/"] = Index;
Get[@"/new"] = New;
Post[@"/"] = Create;
Get[@"/(?<id>[\d])"] = Show;
Get[@"/(?<id>[\d])/edit"] = Edit;
Put[@"/(?<id>[\d])"] = Update;
Delete[@"/(?<id>[\d])"] = Destroy;
}
protected virtual Nancy.Response Index(dynamic context) { return 404; }
protected virtual Nancy.Response New(dynamic context) { return 404; }
protected virtual Nancy.Response Create(dynamic context) { return 404; }
protected virtual Nancy.Response Show(dynamic context) { return 404; }
protected virtual Nancy.Response Edit(dynamic context) { return 404; }
protected virtual Nancy.Response Update(dynamic context) { return 404; }
protected virtual Nancy.Response Destroy(dynamic context) { return 404; }
protected Nancy.Response AsView(object model = null)
{
string method = new StackTrace().GetFrame(1).GetMethod().Name;
string entity = typeof(TEntity).Name;
return View[string.Format("{0}/{1}", entity, method), model];
}
}
To use it you just subclass the class and override the necessary methods. Like so.
public class QuestionModule : RailslikeControllerFor<Question>
{
IQuestionsRepository questions;
public QuestionModule(IQuestionsRepository questions)
: base() { this.questions = questions; }
protected override Response Index(dynamic context)
{
return AsView(questions.GetAll());
}
}
What the base class does is create the necessary CRUDdy urls with a base route starting with the name of the entity you pass in, pluralised in the easiest way possible. In this case /questions
. The rules match what you wold get for a controller in Rails.
Verb | Path | Action | |
---|---|---|---|
GET | /questions | index | display a list of all questions |
GET | /questions/new | new | return an HTML form for creating a new question |
POST | /questions | create | create a new question |
GET | /questions/:id | show | display a specific question |
GET | /questions/:id/edit | edit | return an HTML form for editing a question |
PUT | /questions/:id | update | update a specific question |
DELETE | /questions/:id | destroy | delete a specific question |
There is a teeny-tiny bit of sugar in the AsView
method that will look up the corresponding view. So the module above would resolve its Index
method to questions/index
and the view engine would find the correct file (eg. for Razor - questions/index.cshtml
).
I've already said it's a bit of fun but I have actually used this at least once - there is probably more that could be added but it'll do for a first spike at least. Any use to anyone?