Is there a way to simplify when we have multiple required levels of routing fro each and every method?
I have a hypothetical WebAPI project that i'm using for a generic look at the problem. It gives us movies from some source.
public class MovieController : ApiController
{
// GET api/<controller>
public IEnumerable<Movie> Get()
{
return MoviesDB.All();
}
// GET api/<controller>/5
public Movie Get(int id)
{
return MoviesDB.ThisSpecificOne(id);
}
// POST api/<controller>
public void Post([FromBody]Movie value)
{
}
// PUT api/<controller>/5
public void Put(int id, [FromBody]Movie value)
{
}
// DELETE api/<controller>/5
public void Delete(int id)
{
}
}
But lets say for some stupid reason movies are stored by Genre. So you need genre + id combo.
I'm assuming this is how you would do it
config.Routes.MapHttpRoute(
name: "MoviesWithGenre",
routeTemplate: "api/{controller}/{genre}/{id}",
defaults: new { id = RouteParameter.Optional }
);
public class MovieController : ApiController
{
// GET api/<controller>/<genre>
public IEnumerable<Movie> Get(string genre)
{
return MoviesDB.All(genre);
}
// GET api/<controller>/<genre>/5
public Movie Get((string genre, int id)
{
return MoviesDB.ThisSpecificOne(string genre, id);
}
// POST api/<controller>/<genre>
public void Post(string genre, [FromBody]Movie value)
{
}
// PUT api/<controller>/<genre>/5
public void Put(string genre, int id, [FromBody]Movie value)
{
}
// DELETE api/<controller>/<genre>/5
public void Delete(string genre, int id)
{
}
}
So now MySite.Com/api/movie/horror/12345
might return a movie but I needed to add the optional parameter in every method. Now I find out they are stored by year as well.
config.Routes.MapHttpRoute(
name: "MoviesWithGenreAndYear",
routeTemplate: "api/{controller}/{genre}/{year}/{id}",
defaults: new { id = RouteParameter.Optional }
);
public class MovieController : ApiController
{
// GET api/<controller>/<genre>/<year>
public IEnumerable<Movie> Get(string genre, int year)
{
return MoviesDB.All(string genre, int year);
}
// GET api/<controller>/<genre>/<year>/5
public Movie Get(string genre, int year, int id)
{
return MoviesDB.ThisSpecificOne(string genre, int year, id);
}
// POST api/<controller>/<genre>/<year>
public void Post(string genre, int year, [FromBody]Movie value)
{
}
// PUT api/<controller>/<genre>/<year>/5
public void Put(string genre, int year, int id, [FromBody]Movie value)
{
}
// DELETE api/<controller>/<genre>/<year>/5
public void Delete(string genre, int year, int id)
{
}
}
This all works fine but with each new layer you would need to add a new parameter to each and every method. That doesn't feel very DRY
Could I inject these layers into the constructor instead of the methods themselves.
Perhaps I would like to initialize the controller differently based on these layers, so I would have a different repo based on genre and/or year or something like that.
Is there a solution for this?