Skip to content

Siesta: Painless REST via ASP.NET MVC

August 10, 2009

Zen uses quite a few open source libraries, and I feel a sense of responsibility to contribute back where I can. To that end, I’m releasing the basic infrastructure that powers the Zen API under the name Siesta.

Siesta is a simple and flexible REST system driven by ASP.NET MVC. While you can take the Siesta bits and use them directly in your app, it’s intended more as an example of how to implement your own system.

The basic idea behind Siesta is to communicate only using models within your application, and allow the infrastructure to handle the serialization and de-serialization, similar to how a view engine manipulates ViewModels or ViewData. Models are just POCOs, and serialization is controlled the [DataContract] and [DataMember] attributes in System.Runtime.Serialization (so yes, this requires .NET 3.5).

Siesta also uses the (sweet-with-extra-awesomesauce) JSON.NET library from James Newton-King. There’s a DataContractJsonSerializer in the BCL now, but as far as I could tell, it doesn’t support indentation. JSON.NET supports both, so it’s a great fit. I’ve also been using it forever, so I’m just used to it – if you deal with JSON formatting, it’s definitely worth a look.

The wire (serialization) format is based on MIME types, and Siesta comes with XML and JSON built-in. However, it’s also extensible by implementing a new IModelSerializer. Speaking of which, if someone wants to implement one for YAML, it would be greatly appreciated. ;)

As described in the Zen API documentation, the wire format is determined by the Content-Type and Accept headers. Content-Type is preferred for incoming data, and Accept is preferred for outgoing data. If a header is missing, the system will fail over to the other one.

Here’s an example of an entity that can be serialized via REST:

[DataContract(Name = "user", Namespace = "")]
public class User : IEntity
{
  [DataMember(Name = "id")]
  public int Id { get; set; }

  [DataMember(Name = "username")]
  public string UserName { get; set; }

  [DataMember(Name = "name")]
  public string Name { get; set; }

  [DataMember(Name = "email")]
  public string Email { get; set; }
}

And its matching controller:

public class UserController : SiestaControllerBase
{
  public IRepository<User> UserRepository { get; private set; }

  public UserController(IRepository<User> userRepository)
  {
    UserRepository = userRepository;
  }

  public ModelResult<User> Get(GetRequest request)
  {
    User user = UserRepository.Get(request.Id);

    if (user == null)
      throw NotFound();

    return Model(user, request.Formatting);
  }

  //...
}

Don’t worry, SiestaControllerBase is just a simple base controller which provides the Model() method shortcut. This (and the IEntity interface you might have noticed on User) are entirely optional, and are actually part of the Siesta.Example assembly rather than the main Siesta assembly. As long as the types you want to communicate with are serializable, they’ll work with Siesta.

In contrast to the Siesta example, in Zen, we actually have separate models (which act as DTOs, and are serialized to/from a wire format) and entities (which are persisted to the database). The example doesn’t show this because it requires a whole separate mapping step, which can get tricky. I would highly recommend that if you use this in a real-world app, you create a separate type hierarchy and map between them.

Anyhow, you can grab the Siesta bits on GitHub, including the full version of this (simple) example. If you have feedback, by all means let me know! There’s actually quite a bit of stuff in Zen that I’d like to release as OSS – it’s just a matter of getting the time to split the code off the product and wrap it up.

About these ads

From → Uncategorized

18 Comments
  1. Thanks for sharing this with the community, Nate! I have not yet written or worked with REST systems, so please pardon my ignorance. How do you differentiate this UserController with the UserController that your main MVC application uses (if there is one)? Thanks! :)

  2. @Steven: Typically you’d have a separate controller, if you already have a UserController in your core application. For example, Zen has a ProjectController and a ProjectApiController.

  3. @Nate: That makes sense. Thanks!

  4. Hi Nate, apart from unit testing, did you use any firefox plugins or tools to interact/play with the REST interface? Because in the sample I couldn’t think of an easy way to PUT, POST, DELETE etc..

    Cheers for releasing this :)
    Jake

  5. @Jake: Actually, yeah, in the past I’ve used Poster to tinker with REST endpoints. (There’s also a Firefox 3.5-compatible version available here.)

  6. Hi Nate,

    Thanks, this is a great start! (I think the closer we can get to Rails’ notion of RESTful resources, the better.)

    As part of .NET 3.5 SP1, can’t we serialize objects without using the Data* / Serializable attributes? http://www.pluralsight.com/community/blogs/aaron/archive/2008/05/13/50934.aspx

    Is the case difference (name vs. Name) why you chose to make them explicit?

  7. @Eddie: Yep, you can safely omit the attributes and the serializers will just use the property names as defined on the type. I like making everything lowercase on the wire, but that’s just personal preference.

  8. Traveller permalink

    If you have 2 controllers, one for the views and one for the api, wouldn’t that
    force you to repeat the same code just for returning a different ActionResult?

    For example, in a get user by id request, wouldn’t you have to repeat the same UserRepository.Get(id)
    with all the additional null-checking and what-not in both controllers? (it could be doing a lot more work than that ofc)

    On the other hand, I realize the ViewModel maybe somewhat different from the api model. Since I haven’t had any experience building a restful site before, I have no idea how you manage to stay
    DRY given the above problem. Thanks for your answer in advance.

  9. This is great! Thanks for posting it!

Trackbacks & Pingbacks

  1. DotNetKicks.com
  2. Twitted by holsee
  3. DotNetBurner - ASP.net MVC
  4. Dew Drop – August 11, 2009 | Alvin Ashcraft's Morning Dew
  5. DotNetShoutout
  6. Reflective Perspective - Chris Alcock » The Morning Brew #410
  7. Siesta: Painless REST via ASP.NET MVC — Discord&Rhyme
  8. Siesta: Painless REST via ASP.NET MVC — Discord&Rhyme | Webmaster Tools
  9. RESTify – Extending ASP.NET MVC | I love .NET!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: