HTTP is not just for serving up web pages. It’s also a powerful platform for building APIs that expose services and data. HTTP is simple, flexible, and ubiquitous. Almost any platform that you can think of has an HTTP library, so HTTP services can reach a broad range of clients, including browsers, mobile devices, and traditional desktop apps.
In this tutorial, you’ll build a simple web API for managing a list of "to-do" items. You won’t build any UI in this tutorial.
Previous versions of ASP.NET included the Web API framework for creating web APIs. In ASP.NET 5, this functionality has been merged into the MVC 6 framework. Unifying the two frameworks makes it simpler to build apps that include both UI (HTML) and APIs, because now they share the same code base and pipeline.
The following diagram show the basic design of the app.
..image:: first-web-api/_static/architecture.png
- The client is whatever consumes the web API (browser, mobile app, and so forth). We aren’t writing a client in this tutorial.
- A *model* is an object that represents the data in your application. In this case, the only model is a to-do item. Models are represented as simple C# classes (POCOs).
- A *controller* is an object that handles HTTP requests and creates the HTTP response. This app will have a single controller.
- To keep the tutorial simple and focused on MVC 6, the app doesn’t use a database. Instead, it just keeps to-do items in memory. But we’ll still include a (trivial) data access layer, to illustrate the separation between the web API and the data layer. For a tutorial that uses a database, see :doc:`../tutorials/mvc-with-entity-framework`.
Because we're not building a client, we need a way to call the API. In this tutorial, I’ll show that by using `Fiddler <http://www.fiddler2.com/fiddler2/>`__. Fiddler which is a web debugging tool that lets you compose HTTP requests and view the raw HTTP responses. That lets use make direct HTTP requests to the API as we develop the app.
Select the **ASP.NET Web Application** project template. It appears under **Installed** > **Templates** > **Visual C#** > **Web**. Name the project ``TodoApi`` and click **OK**.
First, add a folder named "Models". In Solution Explorer, right-click the project. (The project appears under the "src" folder.) Select **Add** > **New Folder**. Name the folder *Models*.
A *repository* is an object that encapsulates the data layer, and contains logic for retrieving data and mapping it to an entity model. Even though the example app doesn’t use a database, it’s useful to see how you can inject a repository into your controllers.
By defining a repository interface, we can decouple the repository class from the MVC controller that uses it. Instead of newing up a ``TodoRepository`` inside the controller, we will inject an ``ITodoRepository``, using the ASP.NET 5 dependency injection (DI) container.
This approach makes it easier to unit test your controllers. Unit tests should inject a mock or stub version of ``ITodoRepository``. That way, the test narrowly targets the controller logic and not the data access layer.
In order to inject the repository into the controller, we need to register it with the DI container. Open the *Startup.cs* file. Add the following using directive:
In Solution Explorer, right-click the *Controllers* folder. Select **Add** > **New Item**. In the **Add New Item** dialog, select the **Web API Controller Class** template. Name the class ``TodoController``.
This defines an empty controller class. In the next sections, we'll add methods to implement the API. The `[FromServices] <https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.Core/FromServicesAttribute.cs>`_ attribute tells MVC to inject the ``ITodoRepository`` that we registered earlier.
The `[HttpGet] <https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.Core/HttpGetAttribute.cs>`_ attribute specifies that these are HTTP GET methods. The URL path for each method is constructed as follows:
For the ``GetById`` method, "{id}" is a placeholder variable. In the actual HTTP request, the client will use the ID of the ``todo`` item. At runtime, when MVC invokes ``GetById``, it assigns the value of "{id}" in the URL the method's ``id`` parameter.
Open the *src\\TodoApi\\Properties\\launchSettings.json* file and replace the ``launchUrl`` value to use the ``todo`` controller. That change will cause IIS Express to call the ``todo`` controller when the project is started.
The ``GetAll`` method returns a CLR object. MVC automatically serializes the object to JSON and writes the JSON into the body of the response message. The response code for this method is 200, assuming there are no unhandled exceptions. (Unhandled exceptions are translated into 5xx errors.)
In contrast, the ``GetById`` method returns an ``IActionResult`` type, which represents a generic result type. That’s because ``GetById`` has two expected return values:
- Otherwise, the method returns 200 with a JSON response body. This is done by returning an `ObjectResult <https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.Core/ObjectResult.cs>`_.
In Visual Studio, press F5 to start debugging the app. Visual Studio launches a browser and navigates to ``http://localhost:port/api/todo``, where *port* is a randomly chosen port number. If you're using Chrome, the *todo* data will be displayed. If you're using IE, IE will prompt to you open or save the *todo.json* file.
Launch Fiddler. From the **File** menu, uncheck the **Capture Traffic** option. This turns off capturing HTTP traffic.
..image:: first-web-api/_static/fiddler1.png
Select the **Composer** page. In the **Parsed** tab, type ``http://localhost:port/api/todo``, where *port* is the port number. Click **Execute** to send the request.
..image:: first-web-api/_static/fiddler2.png
The result appears in the sessions list. The response code should be 200. Use the **Inspectors** tab to view the content of the response, including the response body.
..image:: first-web-api/_static/fiddler3.png
Implement the other CRUD operations
------------------------------------
The last step is to add ``Create``, ``Update``, and ``Delete`` methods to the controller. These methods are variations on a theme, so I'll just show the code and highlight the main differences.
This is an HTTP POST method, indicated by the `[HttpPost] <https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.Core/HttpPostAttribute.cs>`_ attribute. The `[FromBody] <https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.Core/FromBodyAttribute.cs>`_ attribute tells MVC to get the value of the to-do item from the body of the HTTP request.
The `CreatedAtRoute <https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.Extensions/Controller.cs#L854-L900>`_ method returns a 201 response, which is the standard response for an HTTP POST method that creates a new resource on the server. ``CreateAtRoute`` also adds a Location header to the response. The Location header specifies the URI of the newly created to-do item. See `10.2.2 201 Created <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>`_.
#. In the request headers text box, add a Content-Type header with the value ``application/json``. Fiddler automatically adds the Content-Length header.
#. In the request body text box, type the following: ``{"Name":"<your to-do item>"}``
According to the HTTP spec, a PUT request requires the client to send the entire updated entity, not just the deltas. To support partial updates, use HTTP PATCH.
The void return type returns a 204 (No Content) response. That means the client receives a 204 even if the item has already been deleted, or never existed. There are two ways to think about a request to delete a non-existent resource:
- "Delete" means "delete an existing item", and the item doesn’t exist, so return 404.
- "Delete" means "ensure the item is not in the collection." The item is already not in the collection, so return a 204.
Either approach is reasonable. If you return 404, the client will need to handle that case.
Next steps
----------
To learn about creating a backend for a native mobile app, see :doc:`../tutorials/native-mobile-backend`.
For information about deploying your API, see :ref:`Publishing and Deployment <aspnet:publishing-and-deployment>`.