using System; using System.Collections.Generic; using FluentValidation; using Nancy; using NzbDrone.Api.Extensions; using System.Linq; namespace NzbDrone.Api.REST { public abstract class RestModule : NancyModule where TResource : RestResource, new() { private const string ROOT_ROUTE = "/"; private const string ID_ROUTE = @"/(?[\d]{1,7})"; private Action _deleteResource; private Func _getResourceById; private Func> _getResourceAll; private Func _getResourceSingle; private Func _createResource; private Func _updateResource; protected ResourceValidator PostValidator { get; private set; } protected ResourceValidator PutValidator { get; private set; } protected ResourceValidator SharedValidator { get; private set; } protected RestModule(string modulePath) : base(modulePath) { PostValidator = new ResourceValidator(); PutValidator = new ResourceValidator(); SharedValidator = new ResourceValidator(); } protected Action DeleteResource { private get { return _deleteResource; } set { _deleteResource = value; Delete[ID_ROUTE] = options => { DeleteResource((int)options.Id); return new Response { StatusCode = HttpStatusCode.OK }; }; } } protected Func GetResourceById { private get { return _getResourceById; } set { _getResourceById = value; Get[ID_ROUTE] = options => { int id; if (!Int32.TryParse(options.Id, out id)) { throw new NotImplementedException(); } var resource = GetResourceById((int)options.Id); return resource.AsResponse(); }; } } protected Func> GetResourceAll { private get { return _getResourceAll; } set { _getResourceAll = value; Get[ROOT_ROUTE] = options => { var resource = GetResourceAll(); return resource.AsResponse(); }; } } protected Func GetResourceSingle { private get { return _getResourceSingle; } set { _getResourceSingle = value; Get[ROOT_ROUTE] = options => { var resource = GetResourceSingle(); return resource.AsResponse(); }; } } protected Func CreateResource { private get { return _createResource; } set { _createResource = value; Post[ROOT_ROUTE] = options => { var resource = CreateResource(ReadFromRequest()); return resource.AsResponse(HttpStatusCode.Created); }; } } protected Func UpdateResource { private get { return _updateResource; } set { _updateResource = value; Put[ROOT_ROUTE] = options => { var resource = UpdateResource(ReadFromRequest()); return resource.AsResponse(HttpStatusCode.Accepted); }; } } private TResource ReadFromRequest() { var resource = Request.Body.FromJson(); var errors = SharedValidator.Validate(resource).Errors.ToList(); if (Request.Method.Equals("POST", StringComparison.InvariantCultureIgnoreCase)) { errors.AddRange(PostValidator.Validate(resource).Errors); } else if (Request.Method.Equals("PUT", StringComparison.InvariantCultureIgnoreCase)) { errors.AddRange(PutValidator.Validate(resource).Errors); } if (errors.Any()) { throw new ValidationException(errors); } return resource; } } }