I have a situation where the only API offered to me returns many items and I want to make a derived request that will only return one item. Here's what my attempt looks like:
[Route("/v3/quotes/{stockTicker}")]
[DataContract]
public class Quotes_Request : BaseRequest<Quotes_Response, List<Quote>>
{
[DataMember(Name = "stockTicker")]
public string Symbol { get; init; }
//Properties
[DataMember(Name = "order")]
public virtual SortOrder? Order { get; init; } = SortOrder.asc;
[DataMember(Name = "limit")]
public virtual int? Limit { get; init; } = 50_000;
public Quotes_Request(string symbol) => Symbol = symbol;
}
public class Quote_Request : Quotes_Request
{
[DataMember(Name = "order")]
public override SortOrder? Order => SortOrder.desc;
[DataMember(Name = "limit")]
public override int? Limit => 1;
public Quote_Request(string symbol, DateTime dateTime) : base(symbol)
{
TimestampLessThanOrEqual = dateTime;
}
}
Returning the list of quotes using Quotes_Request
works perfectly and
I would have thought that my goal of returning a single quote with Quote_Request
would work too, but there seems to be a problem because I get this error:
None of the given rest routes matches 'Quote_Request' request: /v3/quotes/{stockTicker}: Variable 'stockTicker' does not match any property.
To address the error, if I change the route on the parent class Quotes_Request
to this:
[Route("/v3/quotes/{Symbol}")]
[DataContract]
public class Quotes_Request : BaseRequest<Quotes_Response, List<Quote>>
{
[DataMember(Name = "stockTicker")]
public string Symbol { get; init; }
//truncated
The code runs but it's not correct because it's not using any of the DataMember
attributes to name the query parameters, its using the property names. Which is actually the same thing it did with the Route
. Unfortunately, I can't use the property names even if I wanted to because some of the DataMember
s actually have a period in the name.
I did try one other thing, that was I tried making the Symbol
property virtual
so that I could override it in the Derived Quote_Request
class like this:
public class Quote_Request : Quotes_Request
{
[DataMember(Name = "stockTicker")]
public override string Symbol { get; init; }
//truncated
But that didn't work either. I got the same error as in the first place:
None of the given rest routes matches 'Quote_Request' request: /v3/quotes/{stockTicker}: Variable 'stockTicker' does not match any property.
I'm kinda surprised that it didn't pick up the DataMember
name even when it was overriden but if that would have worked I would have just overriden all the properties.
Is there anything else I can try? Did I miss something? Or is this something that will need to be fixed in ServiceStack?
Request DTOs must be unique and can only implement a single API.
To share code amongst Request DTOs you can have them implement the same abstract base class.
However we'd typically recommend to avoid using inheritance in Request DTOs since they represent declarative definition of your Service Contract and using inheritance hides their intent.