ServiceStack versioning - how to customize the request deserialization based on versioning

212 views Asked by At

I am working on a new API where we have requirement for many to many versioning.

  • Old Client -> New Server
  • Old Server -> New client
  • and everything in between

I've read some of the other posts about defensive programming and having DTOs that evolve gracefully... and we are definitely going to use that pattern in most cases.

However, when we have a breaking change for CreateCustomer and require CreateCustomer2 DTO, I would like to be able to customize the way SS resolves the type that is used to deserialize, otherwise we will be forced to use routes like this:

/api/v1/createcustomer

/api/v2/createcustomer

Where I would much rather keep it /api/createcustomer and let the version number live in the Header / Querystring / whatever (not looking for a debate here :) ).

Are there any examples of how to resolve the deserialization type dynamically in ServiceStack, based on a parameter other than route + verb?

Many thanks in advance

1

There are 1 answers

4
mythz On BEST ANSWER

The recommended approach for versioning is to take advantage for the natural forwards compatibility of message-based services and extend existing services defensively so it can support multiple client versions and avoid create multiple versions of the same service.

If you still want to expose /api/v1 routes than I'd recommend doing it at the infrastructure level by using a reverse proxy to re-route /api/v1 and /api/v2 requests to different running instances of ServiceStack.

If you want to do the proxying in code you can use base.ResolveService<T>() or base.ExecuteRequest() to execute different Services in code and ServiceStack's built-in AutoMapping to populate different DTO's which could look something like:

[Route("/customers")]
public class CreateCustomers {
    public int Version { get; set; }
}

public class CreateCustomersV1 { ... }

public class CreateCustomersV2 { ... }

public class CustomerServices : Service
{
    public object Any(CreateCustomers request)
    {
        return request.Version == 1
            ? base.ExecuteRequest(request.ConvertTo<CreateCustomersV1>())
            : base.ExecuteRequest(request.ConvertTo<CreateCustomersV2>())
    }
}