Jaa


#retosMSDN: Solución al Reto 1 de Navidad - Creando una API Rest de Sudokus con Visual Studio

En este primer #retosMSDN de Navidad se os retaba a crear una API REST que sea capaz de decir si un sudoku tiene solución o no. Este reto formaba parte de otros dos retos donde se iba a utilizar esa API.

¿Qué hay que saber para solucionar el reto?

¿Qué es un Sudoku?

Un Sudoku es un juego matemático en que se tiene que rellenar un tablero de 9 x 9 que a su vez está subdividido en 9 de 3 x 3, que son llamado cajas o regiones. Cada una de estas regiones tiene que contener los número del 1 al 9, sin excepción. La única restricción del juego es que en la casilla que se coloque un número este número no podrá ser repetido en la misma fila o columna en el tablero de 9 x 9.

clip_image001

¿Qué es una API REST?

Son las siglas de Represntational State Transfer. Es un estilo de diseño de API para aplicaciones Web que siguen unas guías sobre cómo crear un servicio web para que pueda ser consumida de manera muy cómoda para diferentes tipos de dispositivos. Utiliza HTTP como transporte para enviar la información, los verbos HTTP (GET, POST, PUT, DELETE, ect) para designar las operaciones que se quiere hacer en la invocación. El recurso al que se quiere acceder va siempre codificado en la URL y se utiliza el query string para agregar parámetros extra. Las respuestas suelen ser en XML o JSON dependiendo de lo que el cliente que invoca el servicio especifica que con la cabecera accept.

Solución

En la especificación del reto se especifica que hay que crear una API REST que permita saber si un sudoku tiene solución. Así que siguiendo un poco las guías anteriores tenemos que crear una URI que represente el recurso que se quiere crear.

https://microsoftsudokuweb.azurewebsites.net/api/sudoku/isvalidgame

En esta url se puede observar cómo se quiere acceder a la API del sitio web, además de la entidad sudoku y luego a la operación isvalidgame. Este será el punto final donde se creará la operación.

Parametros y número del sudoku

Hasta ahora solamente se ha especificado la operación donde se validará si el sudoku está bien formado. El siguiente paso es definir como se enviará los números de los sudokus. Ya que se está definiendo una API REST, lo ideal es que se utilizase el verbo POST. De esa manera como parte de la petición se puede especificar un cuerpo donde esté serializado en Xml o Json los números del Sudoku.

La entidad que se va a utilizar en el servidor para definir un tablero es esta:

clip_image002

Es una clase que tiene una matriz bidimensional con los valores del sudoku a trabajar. De esta manera se define un contrato de datos para los parámetros y será el usuario que invoque la API el responsable de especificar si lo hace con XML o Json.

WebAPI

Para la solución del reto se ha propuesto utilizar ASP.NET MVC WebAPI que es el framework para crear API RESTFul que está encima de ASP.NET. De esta manera mucha de la funcionalidad existente se puede reaprovechar para crear la API y no tener que crear todo desde cero.

Para empezar a crear un proyecto de WebAPI hay que abrir Visual Studio 2013 y desde el menú de nuevo proyecto se puede pulsar en C# -> Web

clip_image004

El proceso de creación de un proyecto Web se ha simplificado en una única plantilla de proyecto donde a partir de ese proyecto se puede seleccionar que tecnología se desea.

clip_image006

Es en este cuadro de dialogo donde se puede seleccionar que plantilla se desea usar de una manera más cómoda.

En el reto que se propone lo que se desea es usar Web API, así que es la opción elegida. Además en este mismo cuadro de dialogo se puede seleccionar el valor de alojar en la nube usando Microsoft Azure, que provisiona directamente un sitio web gratuito y se descarga el archivo de publicación del sitio web.

Otra de las opciones que se puede activar a la hora de crear el proyecto, es crear un proyecto de testing para poder hacer testing unitario de todos los controladores del sitio web.

Añadiendo un controlador al proyecto

Una vez que se ha creado el proyecto en Visual Studio, se tiene una estructura de carpetas que representan todos los recursos necesarios para ejecutar el sitio web.

clip_image007

En la carpeta controller se puede crear todos los controladores del sitio web, ya sean de una web en concreto o un controlador de la API Web. Para crear un nuevo controlador de API Web hay que pulsar sobre la carpeta Controllers y luego en este cuadro de dialogo seleccionar controlador WebAPI.

clip_image009

Al crear el controlador este es el código que se ha generado.

 using System;
using System.Collections.Generic;
using System.Web.Http;

 
public class ValuesController1 : ApiController
{
    // GET api/<controller>
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/<controller>/5
    public string Get(int id)
    {
        return "value";
    }

    // POST api/<controller>
    public void Post([FromBody]string value)
    {
    }

    // PUT api/<controller>/5
    public void Put(int id, [FromBody]string value)
    {
    }

    // DELETE api/<controller>/5
    public void Delete(int id)
    {
    }
}

Como se comenta al principio del artículo una API Rest, es aquella que utiliza la URL como recurso para acceder a la entidad y luego utiliza los verbos de HTTP para asociar acciones CRUD de esas entidades. En el código se puede ver perfectamente como los nombres de los métodos corresponden con los verbos de HTTP. Esto también se puede especificar con atributos sobre los métodos para asociar el verbo.

SudokuController

Para la resolución del reto se ha creado un controlador llamado SudokuController que contiene la única operación que hay que hacer, verificar si el sudoku tiene solución o no.

 namespace Microsoft.Sudoku.Web.Controllers
{
    using System;
    using System.Web.Http;
    using Microsoft.Sudoku.Web.SudokuEngines;

    public class SudokuController : ApiController
    {
        private ISudokuGame sudokuEngine;

        public SudokuController(ISudokuGame value)
        {
            sudokuEngine = value;
        }

        [HttpPost]
        public bool IsValidGame(Board body)
        {
            bool result = false;
            try
            {
                result = sudokuEngine.IsValidGame(body);
            }
            catch (Exception)
            {
            }

            return result;
        }
    }
}

En el constructor de la clase se ha puesto como requisito una interfaz llamada ISudokuGame que es el contrato de la resolución del juego, de esta manera se está invierto el control del objeto (IoC) además de utilizar inyección de dependencias usando Unity.

Resolución de los Sudokus

Para la verificación en sí de los sudokus se está usando una librería de nuget llamada Sudoku Solver, https://www.nuget.org/packages/Golden.Man.Sudoku.Solver

Configurando inyección de dependencias para WebAPI.

Para que WebAPI pueda activar correctamente todas las dependencias necesarias para crear el controlador, en este caso ISudokuGame, hay que conectarlo con un framework. Para hacer esa integración hay que implementar la interfaz IDependencyResolver y conectarlo con Unity.

 using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;
using Microsoft.Practices.Unity;
 
public class WebApiUnityResolver : IDependencyResolver
{
    protected IUnityContainer container;

    public WebApiUnityResolver(IUnityContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return container.Resolve(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        try
        {
            return container.ResolveAll(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return new List<object>();
        }
    }

    public IDependencyScope BeginScope()
    {
        var child = container.CreateChildContainer();
        return new WebApiUnityResolver(child);
    }

    public void Dispose()
    {
        container.Dispose();
    }
}

Una vez que esta clase está hecha el siguiente paso es conectarla con el runtime de WebAPI para que la utilice en la resolución de los servicios de los que dependen los controladores.

Eso se hace normalmente en la clase llamada WebApiConfig que el proyecto de Visual Studio crea automáticamente como parte de la creación del proyecto. En esa clase está la configuración de las rutas de WebApi.

 public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        // Web API routes
        config.MapHttpAttributeRoutes();

        var container = UnityConfig.GetConfiguredContainer();
        config.DependencyResolver = new WebApiUnityResolver(container);
        

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

Probando la llamada a la API

Para ello se va a utilizar una extensión de Firefox llamada RESTClient que permite hacer peticiones a API Rest de una manera muy cómoda.

La url es: https://microsoftsudokuweb.azurewebsites.net/api/sudoku/IsValidGame

Y el cuerpo de la petición es un objeto Json que contiene el parámetro que la operación espera:

 "{\"Values\":[[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0]]}"

El código completo lo puedes encontrar en esta solución de Visual Studio 2013 que puedes descargarte de GitHub. Y si tienes cualquier duda sobre la solución, no dudes en ponerte en contacto con nosotros en esmsdn@microsoft.com.

Luis Guerrero

Technical Evangelist Microsoft Azure

@guerrerotook