5. REST API

In this tutorial, you will create a REST API and learn about configuration and web service packaging.

To complete this tutorial download previous solution from here or jump to the previous tutorial.

Define a Service Interface

Until now you've created business services for internal use. By internal we mean that they are supposed to be consumed by your applications only. You can always publish your business services directly to outside but this would be hard for you to maintain and refactor your business code. For this reason, you will create a web service package out of your business services.

First we will define which services to expose. To do this, create a folder named Service in TaskManagement module and to this folder create an interface named ITaskService as shown below;

This interface is a service interface and it will contain the methods of Task class that you want to share with the outside world.

Now modify ITaskService service interface to include following method;

public interface ITaskService { void Complete(); }

Service interfaces are not only for persistent objects. Naming convention for adding service interfaces is I[ClassName]Service.

Following this convention ITaskManagerService and ITasksService would be correct names to create service interfaces for TaskManager and Tasks classes respectively.

Now go to Task.cs file and make your Task class implement ITaskService interface as shown below;

public class Task : ITaskService { ... } ...

Notice that you don't have to implement Complete method, since it is already implemented within Task class.

Create a Web Service Package

To create a web service package go to Configuration.Service project and add a class named TaskService as shown below;

And add below code to TaskService class;

public class TaskService : ICodingStyleConfiguration { public void Configure(ConventionBasedCodingStyle codingStyle, IKernel kernel) { codingStyle.AddTypes(v => v.WebService("Task", t => t .Methods.Add(c => c.Proxy<ITaskService>().TargetByParameter<Task>()) )); } }

With this configuration, you've created a virtual web service class -which we call web service package- and added all methods in ITaskService class to this virtual class.

Now build and run AppHost.Service project.

As you can see, there is a new group called Api. Under this group you will see a new service package named I Task Service. You can see that this service package is marked as Virtual and Web Service. Under this package there are two services. One is Complete and the other is Ping.

Ping services are created automatically for testing purposes.

Test your first REST API

Now build and run both AppHost.Service and AppHost.Rest projects.

AppHost.Rest is an application that acts as a gateway to your internal business services. It only allows access to the services under Api group.

Now your api is in this url;

POST http://localhost:63048/tasks/{id}/complete

63048 is the port number if you downloaded the empty solution from here. If you created your own solution manually, check properties of AppHost.Rest project to see its port number.

Try your API by making an HTTP request to this URL, and make sure you use an id value from your test database in place of {id}.

We used Postman for this test, and the result is shown below;

URL breakdown

Your api consists of 3 parts;

  1. Resource name in plural - tasks
  2. Id of the resource - 6
  3. Operation/method name - complete

Resource name is in plural because you named your web service package after a persistent class.

Improve your Web Service Package

Now modify ITaskService.cs file as shown below;

public interface ITaskService { void Complete(); } public interface ITasksService { ITaskInfo GetTask(int taskId); List<ITaskInfo> GetTasks(bool completed); } public interface ITaskManagerService { ITaskInfo CreateTask(string name); } public interface ITaskInfo { int Id { get; } string Name { get; } bool Completed { get; } }

There are 3 new interfaces in your service definition;

  1. ITasksService to include services from Tasks query class.
  2. ITaskManagerService to include services from TaskManager manager class.
  3. ITaskInfo to include properties of Task class in responses.

Implement your new interfaces as shown below;

Task class

public class Task : ITaskService, ITaskInfo { ... }

Tasks class

public class Tasks : Query<Task>, ITasksService { ... #region Service Mappings ITaskInfo ITasksService.GetTask(int taskId) { return SingleById(taskId); } List<ITaskInfo> ITasksService.GetTasks(bool completed) { return ByCompleted(completed).Cast<ITaskInfo>().ToList(); } #endregion }

TaskManager class

public class TaskManager : ITaskManagerService { ... #region Service Mappings ITaskInfo ITaskManagerService.CreateTask(string name) { return CreateTask(name); } #endregion }

Notice that we make use of Explicit Interface Implementation to map interface methods to class methods. This is required for methods of service interfaces where return type in service interface is different than the return type in implementing class. e.g. CreateTask method returns Task in TaskManager class, but it returns ITaskInfo in ITaskManagerService interface.

And finally add new interfaces to your web service package;

public class TaskService : ICodingStyleConfiguration { public void Configure(ConventionBasedCodingStyle codingStyle, IKernel kernel) { codingStyle.AddTypes(v => v.WebService("Task", t => t .Methods.Add(c => c.Proxy<ITaskService>().TargetByParameter<Task>()) .Methods.Add(c => c.Proxy<ITasksService>().TargetBySingleton(kernel)) .Methods.Add(c => c.Proxy<ITaskManagerService>().TargetBySingleton(kernel)) )); } }

Now rebuild and run both AppHost.Service and AppHost.Rest projects.

You now have 4 endpoints to test;

  1. POST /tasks/{id}/complete mapped to ITaskService.Complete
  2. GET /tasks or GET /tasks?completed={bool} mapped to ITasksService.GetTasks
  3. GET /tasks/{id} mapped to ITasksService.GetTask
  4. POST /tasks mapped to ITaskManagerService.CreateTask

To test 4. endpoint you have to include a JSON request body like below. This is because CreateTask method accepts a parameter named name.

{ "name":"task name goes here" }

Summary

In this section you've learned how to create a RESTful service endpoint out of your business services.

Now try to create new persistent objects to enhance your to-do application.

Additionally you can move to next page to download a complete todo application.


You can download complete source code for this tutorial here