Customize the Rest API

The Weavy REST API is more than just a set of predefined endpoints. You are free to modify existing methods as well as add your own logic.

The controllers that are shipped with the Server SDK are designed for the most common CRUD scenarios and to provide you with examples on how to organize your API, but there are often situations where you would want to perform custom actions or expose additional data in the responses.

A guiding principle has been that it is often more effective to write a custom endpoint that performs a number of actions, instead of making individual calls to a number of different endpoints, each with its own overhead in terms of network latency, parsing etc. The later approach is also more error prone and more complicated to recover from if an error occurs.

Built-in API methods

The code that make up the REST API is located in the Areas\Api folder. API methods are defined in Web API controllers under the Areas\Api\Controllers folder. Each controller class serves and performs actions that relates to a distinct entity type (e.g. user, space, app).

You are free to modify and/or add API methods to serve your needs. Just keep in mind that this will add some complexity when you merge in changes from weavy-sln repo.

Adding custom API methods

Start by setting up the Weavy SDK on your developer machine.

When creating custom api methods you should do the following:

  • Create a class extending the Weavy.Web.Api.Controllers.WeavyApiController
  • Add and implement methods and decorate them with the appropriate [HttpVerb] and [Route] attributes.

Controllers and Actions

Your first step is to create a class extending Weavy.Web.Api.Controllers.WeavyApiController. A good convention is to place the file in the Areas\Api\Controllers folder. In this example we are adding a controller with an action method that creates some resources and then returns the result.

using System.Linq;
using System.Web.Http;
using System.Web.Http.Description;
using Weavy.Areas.Api.Models;
using Weavy.Core.Models;
using Weavy.Core.Services;
using Weavy.Web.Api.Controllers;

namespace Weavy.Areas.Api.Controllers {

    [RoutePrefix("api")]
    public class ExampleController : WeavyApiController {

        [HttpPost]
        [Route("example/configure")]
        [ResponseType(typeof(ConfigurationResult))]
        public IHttpActionResult Configure(Configuration model) {

            // get or create the user
            User user = UserService.GetByEmail(model.Email);
            if (user == null) {
                user = new User() { Email = model.Email, Username = UserService.MakeUniqueUsername(model.Email) };
                user.Profile.Name = model.Name;
                user = UserService.Insert(user);
            }

            // get or create the space
            Space space = SpaceService.GetByKey(model.SpaceKey);
            if (space == null) {
                space = SpaceService.Insert(new Space() { Key = model.SpaceKey, Name = model.SpaceKey });              
            }

            // add the user to the space if not member
            if (!space.MemberIds.Any(x => x == user.Id)) {                
                SpaceService.AddMember(space.Id, user.Id);
            }

            // get or create the files app in the space
            var app = AppService.GetApps<Files>(space.Id).FirstOrDefault();
            if (app == null) {
                app = AppService.Insert(new Files() { Name = "Files" }, space);
            }

            var result = new ConfigurationResult() {
                App = app,
                Space = space,
                User = user
            };

            return Ok(result);
        }
    }
}

Attributes

Each action method typically has the following attributes:

Optionally, you can decorate the controller class with the [RoutePrefix] attribute. This will make sure the routing prefix is prepended to all actions within the controller. We recommended that you use api.

To prevent route collisions we also recommend that your route attributes starts with the controller name. In the example above our controller is called ExampleController and we started our route with example.

In the example above the [RoutePrefix] and [Route] attributes are combined to form the final route api/example/configure.

Models

There are two models used in this example; the Configuration and the ConfigurationResult classes. These are used as input to, and output from, the action and are placed in the Areas\Api\Models folder.

using System.ComponentModel.DataAnnotations;

namespace Weavy.Areas.Api.Models {

    public class Configuration {

        [Required]
        [EmailAddress(ErrorMessage = "Invalid Email Address")]
        public string Email { get; set; }
        
        public string Name { get; set; }

        [Required]
        public string SpaceKey { get; set; }        
    }
}

Configuration.cs

using Weavy.Core.Models;

namespace Weavy.Areas.Api.Models {

    public class ConfigurationResult {

        public User User { get; set; }

        public App App { get; set; }

        public Space Space { get; set; }       
    }
}

ConfigurationResult.cs

Testing

You can test your api method by first retriving an access token from the /api/auth endpoint as described in the Authentication article and then issuing a request to your api method:

POST /api/example/configure
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3Mi...

{
  "email": "test@example.com",
  "name": "Test Testsson",
  "space_key": "e6469f67-a2a0-41f5-9efb-5991cf49ed4e"
}

Setting up Postman or a similar API client is recommended for testing scenarios.

Documentation

By default your custom api controllers and methods will be self documented on https://{your-weavy-url}/docs/[controller-name]. To opt-out of documentation, decorate your class or individual methods with the ApiExplorerSettingsAttribute attribute:

[ApiExplorerSettings(IgnoreApi = true)]

Troubleshooting

Because of the way .NET Web API is organized all controllers must have a unique class name within the solution. It does not help that their namespace makes them unique.

When adding usings in the top of the classes, take care not to add the MVC namespace version. Some of the types have an Web API and an MVC version. Make sure to add the namespace that starts with System.Web.Http and not System.Web.Mvc.