I am a bit confused with ServiceStack 'old' and 'new' API and need some clarification and best practices, especially with Request / Response DTO's and routing. I watched some courses on Pluralsight and have the first three books listet on servicestack.net in my electronic bookshelf.
I like to 'restify' an existing application which is built using DDD patterns which means I have a high level of abstraction. The client is WPF and follows the MVVM pattern. I have 'client side service', 'server side service' and repository classes (and some aggregates too). I use NHibernate 4 (with fluent API and a code-first approach) as ORM. Only my repository classes know about the ORM. I have DTO's for all my Entity objects and in my WPF client I only work with those DTOs in the ViewModel classes. I heavily use AutoMapper to 'transfer' Entity objects to my DTO's and vice versa.
My confusion starts exactly with these DTO's and the Request / Response DTOs used in ServiceStack. Here is a very much simplified example of an Address Entity which illustrates the problem:
All my Entity Objects derive from EntityBase which contains basic properties used in all Entities:
public abstract class EntityBase : IEntity
{
public virtual Guid Id { get; protected set; }
public virtual DateTime CDate { get; set; } //creation date
public virtual string CUser { get; set; } //creation user
public virtual DateTime MDate { get; set; } //last modification date
public virtual string MUser { get; set; } //last modification user
//
// some operators and helper methods irrelevant for the question
// ....
}
public class Address : EntityBase
{
public string Street { get; private set; }
public string AdrInfo1 { get; private set; }
public string AdrInfo2 { get; private set; }
public string ZipCode { get; private set; }
public string City { get; private set; }
public string Country { get; private set; }
}
Of course there are collections and references to related objects which are ignored here as well as database mappers, naming conventions etc. The DTO I have looks like this:
public class AddressDto
{
public Guid Id { get; set; } // NHibernate GUID.comb, NO autoincrement ints!!
public DateTime CDate { get; set; }
public string CUser { get; set; }
public DateTime MDate { get; set; }
public string MUser { get; set; }
public string Street { get; private set; }
public string AdrInfo1 { get; private set; }
public string AdrInfo2 { get; private set; }
public string ZipCode { get; private set; }
public string City { get; private set; }
public string Country { get; private set; }
}
To use this with ServiceStack I need to support the following:
CRUD functionality
Filter / search functionality
So my 'Address service' should have the following methods:
GetAddresses (ALL, ById, ByZip, ByCountry, ByCity)
AddAddress (Complete AddressDTO without Id. CDate, CUser are filled automatically without user input)
UpdateAddress (Complete AddressDTO without CUser and CDate, MDate and MUser filled automatically without user input)
DeleteAddress (Just the Id)
For me it is pretty clear, that all Requests return either a single AddressDto or a List<AddressDto> as ResponseDTO except for the delete which should just return a status object.
But how to define all those RequestDTO's? Do I really have to define one DTO for EACH scenario?? In the books I only saw samples like:
[Route("/addresses", "GET")]
public class GetAddresses : IReturn<AddressesResponse> { }
[Route("/addresses/{Id}", "GET")]
public class GetAddressById : IReturn<AddressResponse>
{
public Guid Id { get; set; }
}
[Route("/addresses/{City}", "GET")]
public class GetAddressByCity : IReturn<AddressResponse>
{
public string City { get; set; }
}
// .... etc.
This is a lot of boilerplate code and remembers me a lot of old IDL compilers I used in C++ and CORBA.....
Especially for Create and Update I should be able to 'share' one DTO or even better reuse my existing DTO... For delete there is probably not much choice....
And then the filters. I have other DTOs with a lot more properties. A function approach like used in WCF, RPC etc is hell to code...
In my repositories I pass an entire DTO and use a predicate builder class which composes the LINQ where clause depending on the properties filled. This looks something like this:
List<AddressDto> addresses;
Expression<Func<Address, bool>> filter = PredicateBuilder.True<Address>();
if (!string.IsNullOrEmpty(address.Zip))
filter = filter.And(s => s.Zip == address.Zip);
// .... etc check all properties and dynamically build the filter
addresses = NhSession.Query<Address>()
.Where(filter)
.Select(a => new AddressDto
{
Id = a.Id,
CDate = a.CDate,
//.... etc
}).ToList();
Is there anything similar I could do with my RequestDTO and how should the routing be defined?
A lot of questions raised here have been covered in existing linked answers below. The Request / Response DTOs are what you use to define your Service Contract, i.e. instead of using RPC method signatures, you define your contract with messages that your Service accepts (Request DTO) and returns (Response DTO). This previous example also walks through guidelines on designing HTTP APIs with ServicesStack.
Use of well-defined DTOs have a very important role in Services:
You want to ensure all types your Services return are in DTOs since this, along with the base url of where your Services are hosted is all that's required for your Service Consumers to know in order to consume your Services. Which they can use with any of the .NET Service Clients to get an end-to-end Typed API without code-gen, tooling or any other artificial machinery.
DTOs are what defines your Services contract, keeping them isolated from any Server implementation is how your Service is able to encapsulate its capabilities (which can be of unbounded complexity) and make them available behind a remote facade. It separates what your Service provides from the complexity in how it realizes it. It defines the API for your Service and tells Service Consumers the minimum info they need to know to discover what functionality your Services provide and how to consume them (maintaining a similar role to Header files in C/C++ source code). Well-defined Service contracts decoupled from implementation, enforces interoperability ensuring that your Services don't mandate specific client implementations, ensuring they can be consumed by any HTTP Client on any platform. DTOs also define the shape and structure of your Services wire-format, ensuring they can be cleanly deserialized into native data structures, eliminating the effort in manually parsing Service Responses.
Auto Queryable Services
If you're doing a lot of data driven Services I recommend taking a look at AutoQuery which lets you define fully queryable Services without an implementation using just your Services Request DTO definition.
Related
I am creating a endpoint that accepts multiple parameters. I was wondering what the proper way of doing this in ServiceStack is, as I know that the routes can be defined like this:
[Route("/Cars/{EquipmentIds}/{ManufacturerIds}/{ColourIds}")]
But does not that mean that EquipmentIds has to be defined before ManufacturerIds and ColourIds, otherwise the API will interpret it incorrectly?
I would like to specify the parameters I use, and then not include the rest when they are not used.
A unclean url would then look like this ?EquipmentIds=1&ColourIds=1
I found the following solution, but this one was from 2011
Multiple Optional Parameters with ServiceStack.Net.
Is there a new solution for this, or is that still the proper way of doing things?
The URL should be a "resource identifier" where any Query String arguments are modifiers to that resource request.
So you shouldn't put complex types in the /path/info which are unlikely to form part of Resource Identifier for that route.
Your route should be self-describing as to what it's a resource identifier of. Stuffing a an anonymous bunch of ids in the URL doesn't make it a clean URL, it still needs to be semantically correct and self-describing at what the different path components contain.
It's hard to know the right Route to use when it's not clear what Service this is used for, but if this was a Car Search Service the appropriate URL would be something like:
/cars/search?EquipmentIds=1,2,3&ManufacturerIds=4,5,6&ColourIds=7,8,9
Just as when you use a Search Service like Google, they don't try to pack everything in the route, which is only used to identify you're making a search request. Everything else including the search query is added to the query string, e.g;
https://www.google.com/search?q=test
Which in ServiceStack would just be defined as:
[Route("/cars/search")]
public class SearchCars
{
public List<int> EquipmentIds { get; set; }
public List<int> ManufacturerIds { get; set; }
public List<int> ColourIds { get; set; }
}
Or it can be easily auto implemented in AutoQuery with:
[Route("/cars/search")]
public class SearchCars : QueryDb<Car>
{
public List<int> EquipmentIds { get; set; }
public List<int> ManufacturerIds { get; set; }
public List<int> ColourIds { get; set; }
}
This is a follow up regarding:
ServiceStack Request DTO design
In the above question the design was strictly regarding read operations. What about write operations? Say we wanted to add operations for creating a new booking limit, would reusing the noun be appropriate here?
[Route("/bookinglimits/","POST")]
public class CreateBookingLimit : IReturn<BookingLimit>
{
BookingLimit newBookingLimit
}
-OR- Would this be better design?
[Route("/bookinglimits/","POST")]
public class CreateBookingLimit : IReturn<BookingLimit>
{
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; } }
}
Also, if we wanted to add editing--should we have insert and edit share the same models and add the ID?
[Route("/bookinglimits/","POST")]
[Route("/bookinglimits/{Id}/","PUT")]
public class CreateBookingLimit : IReturn<BookingLimit>
{
public int Id { get; set; }
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; } }
}
I'm trying to wrap my head around when it makes the most sense to reuse POCOs and when it makes more sense to separate intentions.
Message-based API Design
There are a few things to bear in mind when designing the ideal message-based API where your Services effectively end up serving 2 masters: a Native Client API and a REST API. Native Clients just send and receive messages in their original form so they get a natural API for free modelled using C# Request and Response DTOs to capture what information is required for the Service to perform its Operation and what it should return.
Projecting messages into the ideal HTTP API
After designing your message-based API you'll then want to focus on how best to project the messages into a REST API by annotating Request DTOs with [Route] Attributes to define the Custom endpoints for your Services.
This previous answer on Designing a REST-ful service with ServiceStack provides examples on which routes different Request DTOs map to, in general you'll want to design your APIs around Resources where each operation "acts on a Resource" which will make defining your Custom Routes easier. The ideal HTTP API for Creating and Updating a Booking Limit would look like:
POST /bookinglimits (Create Booking Limit)
PUT /bookinglimits/{id} (Update Booking Limit)
General recommendations on good API Design
Whilst not specifically about Web Services this article on Ten Rules for Good API Design provides good recommendations on general (Code or Services) API design. As API Consumers are the intended audience of your APIs who'll primarily be deriving the most value from them, their design should be optimized so that they're self-descriptive, use consistent naming, are intuitive to use and can be evolved without breaking existing clients. Messages are naturally suited to versioning but you still need to be mindful when making changes to existing published APIs that any additional properties are optional with default fallback behavior if required.
For this reason whilst you can save some code by returning a naked BookingLimit, my preference is to instead return a specific Response DTO for each Service which allows the Service to return additional metadata without breaking existing clients whilst maintaining a consistent Request/Response pattern for all Services. Although this is just my preference - returning naked types is also fine.
ServiceStack Implementation
To implement this in ServiceStack I wouldn't use the same Request DTO to support multiple verbs. Since the Request DTO is called Create* that conveys that users should only send this Request DTO to Create Booking limits which is typically done using a POST request, e.g:
[Route("/bookinglimits", "POST")]
public class CreateBookingLimit : IReturn<CreateBookingLimitResponse>, IPost
{
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; }
}
public class CreateBookingLimitResponse
{
public BookingLimit Result { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
The IPut, IPost are Verb interface markers which lets both the User and Service Client know which Verb this message should be sent with which makes it possible to have all messages sent in a single Service Gateway method.
If your Service also supports updating a Booking Limit then I'd create a separate Service for it which would look like:
[Route("/bookinglimits/{Id}", "PUT")]
public class UpdateBookingLimit : IReturn<UpdateBookingLimitResponse>, IPut
{
public int Id { get; set; }
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; }
}
public class UpdateBookingLimitResponse
{
public BookingLimit Result { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
By using separate Operations you can ensure Request DTOs contains only the properties relevant to that operation, reducing the confusion for API consumers.
If it makes sense for your Service, e.g. the schemas for both operations remains the same I'll merge both Create/Update operations into a single Operation. When you do this you should use a consistent Verb that indicates when an operation does both, e.g. Store* or CreateOrUpdate*:
[Route("/bookinglimits", "POST")]
public class StoreBookingLimit : IReturn<StoreBookingLimitResponse>, IPost
{
public int Id { get; set; }
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; }
}
public class StoreBookingLimitResponse
{
public BookingLimit Result { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
In most cases where the Server generates the Id for the Resource you should use POST, in the rare case where the client specifies the Id, e.g. Slug or Guid you can use PUT which roughly translates to "PUT this resource at this location" which is possible when the client knows the url for the resource.
Message based API examples
Most of the time what messages should contain will be obvious based on the Service requirements and becomes intuitive and natural to create over time. For examples on a comprehensive message-based API you can have a look AWS Web Services who've effectively servicified their Web Services behind a message-based design that uses Service Clients to send messages to access all their APIs, e.g. AWS DynamoDB API Reference lists each Actions that's available as well as other DTO Types that the Services return, e.g here are DynamoDB APIs they have around Creating / Modifying and Querying Items:
Actions
BatchGetItem
BatchWriteItem
DeleteItem
GetItem
PutItem
Query
Scan
UpdateItem
Data Types
AttributeDefinition
AttributeValue
AttributeValueUpdate
Condition
...
In ServiceStack Actions are called Operations and what you'll use Request DTOs to define, whilst AWS Data Types are just called DTOs which I keep in a Types namespace to differentiate from Operations.
DynamoDb.ServiceModel (project)
/GetItem
/PutItem
/UpdateItem
/DeleteItem
/Query
/Scan
/Types
/AttributeDefinition
/AttributeValue
/AttributeValueUpdate
You typically wouldn't need additional explicit Services for Batch Requests as you can get that for free using ServiceStack's Auto Batched Requests. ServiceStack also includes a number of other benefits where it's able to generate richer DTOs containing Custom Attributes and interfaces in the Source DTOs to enable a richer and succinct end-to-end typed API requiring less boilerplate and generated code that lets you use the same Generic Service Client to call any ServiceStack Service offering both Sync and idiomatic Async APIs. The additional metadata also enables seamless higher-level functionality like Encrypted Messaging, Cache Aware Clients, Multiple Formats, Service Gateway, HTTP Verb Interface Markers, etc.
Otherwise AWS follows a very similar approach to ServiceStack for designing message-based APIs using generic Service Clients to send DTOs native in each language.
In my example I have the following database structure. Order has many OrderLine, which has one Product.
I am trying to return the following DTO:
public class OrderLineDto {
public int Id { get; set; }
public int Quantity { get; set; }
public string OrderType { get; set; }
public string ProductName { get; set; }
}
This should be possible by use of the following Query Route:
[Route("/orderlines")]
public class FindOrderLines : QueryBase<OrderLine, OrderLineDto>,
IJoin<OrderLine, Order>,
IJoin<OrderLine, Product>
{ }
What I am trying to do here is join OrderLine in both directions to bring in Type from Order, and Name from Product and return it in an OrderLineDto.
I am able to do these things individually by only using one IJoin, however AutoQuery appears only to use the first IJoin interface declaration, and does not perform the second join.
If I attempt to do a join like this: IJoin<OrderLine, Order, Product>
I get the following exception: Could not infer relationship between Order and Product
Is it possible to achieve what I am trying to do here with auto query or should I go back to writing standard REST services, abandoning AutoQuery?
I have submitted a pull request to ServiceStack which will now allow this behavior.
https://github.com/ServiceStack/ServiceStack/pull/955
I have a DTO that goes something like this:
public class Request {
public id ASpecificIdentifier { get; set; }
public string PreciseDescription { get; set; }
public string FirstPartOfSomeonesName { get; set; }
}
Whilst I'm happy accepting this as the official 'Input', I would also like to be able to bind them to multiple keys. The reason for this will be serialized to a client in an encrypted JSON object, so I would like to keep the length down.
For example they should also be able to pass:
{
"Id":1,
"Desc":"My Issue",
"Name":"Bob"
}
How can I achieve this? I have looked around at the Attributes supplied but non seem to be able to allow this behaviour?
You could create multiple DTOs for each scenario you allow (set of named parameters). Then in your service you would have to handle each DTO and translate them a common DTO to take action.
Or Another way would be to have a DTO that takes a generic key/value parameter. This will make your DTOs very flexible but you will lose some of the advantages of strong typing.
For Example:
public class Request {
Dictionary<string,string> Properties { get; set; }
}
BACKGROUND: I have a Person domain object. It is an aggregate root. I have included a portion of the class below.
I am exposing methods to perform the objects behaviors. For instance, to add a BankAccount I have the AddBankAccount() method. I have not included all the methods of the class but suffice to say that any public property must be updated using a method.
I am going to create an IPerson repository to handle the CRUD operations.
public interface IPersonRepository
{
void Save(Person p);
//...other methods
}
QUESTION: How do I tell the repository which fields need to be updated when we are updating an existing person? For example, If I add a bank account to an existing person how do I communicate this information to the repository when repository.Save() is called?
In the repository it is easy to determine when a new person is created, but when an existing person exists and you update fields on that person, i'm not sure how to communicate this to the repository.
I don't want to pollute my Person object with information about which fields are updated.
I could have separate methods on the repository like .UpdateEmail(), AddBankAccount() but that feels like overkill. I would like a simple .Save() method on the repository and it determines what needs to update in some manner.
How have others handled this situation?
I have searched the web and stackoverflow but haven't found anything. I must not be searching correctly because this seems like something simple when it comes to persistence within the DDD paradigm. I could also be way off on my understanding of DDD :-)
public class Person : DomainObject
{
public Person(int Id, string FirstName, string LastName,
string Name, string Email)
{
this.Id = Id;
this.CreditCards = new List<CreditCard>();
this.BankAccounts = new List<BankAccount>();
this.PhoneNumbers = new List<PhoneNumber>();
this.Sponsorships = new List<Sponsorship>();
}
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string Name{ get; private set; }
public string Email { get; private set; }
public string LoginName { get; private set; }
public ICollection<CreditCard> CreditCards { get; private set; }
public ICollection<BankAccount> BankAccounts { get; private set; }
public ICollection<PhoneNumber> PhoneNumbers { get; private set; }
public void AddBankAccount(BankAccount accountToAdd, IBankAccountValidator bankAccountValidator)
{
bankAccountValidator.Validate(accountToAdd);
this.BankAccounts.Add(accountToAdd);
}
public void AddCreditCard(CreditCard creditCardToAdd, ICreditCardValidator ccValidator)
{
ccValidator.Validate(creditCardToAdd);
this.CreditCards.Add(creditCardToAdd);
}
public void UpdateEmail(string NewEmail)
{
this.Email = NewEmail;
}
There is an example of Repository interface from S#arp Architecture project. It is similar to PoEAA Data Mapper because it used to CRUD operations also.
public interface IRepositoryWithTypedId<T, IdT>
{
T Get(IdT id);
IList<T> GetAll();
IList<T> FindAll(IDictionary<string, object> propertyValuePairs);
T FindOne(IDictionary<string, object> propertyValuePairs);
T SaveOrUpdate(T entity);
void Delete(T entity);
IDbContext DbContext { get; }
}
As you can see, there is no update method for specific properties of an entity. The whole entity is provided as an argument into the method SaveOrUpdate.
When properties of your domain entity are being updated you should tell your Unit of Work that entity is 'dirty' and should be saved into storage (e.g. database)
You should not pollute your Person object with information about updated fields but it is needed to track information if entity is updated.
There might be methods of the class DomainObject which tell 'Unit of Work' if entity is 'new', 'dirty' or 'deleted'. And then your UoW itself might invoke proper repository methods - 'SaveOrUpdate' or 'Delete'.
Despite the fact that modern ORM Frameworks like NHibernate or EntityFramework have their own implementations of 'Unit of Work', people tend to write their own wrappers/ abstractions for them.
What I'm doing to solve this problem, is adding an interface to my domain objects:
interface IDirtyTracker {
bool IsDirty {get;}
void MarkClean();
void MarkDirty();
}
The base DomainObject class could implement IDirtyTracker, and then repositories etc. could use IsDirty to check if it's dirty or clean.
In each setter that makes a change:
void SetValue() {
this._value = newValue;
this.MarkDirty();
}
This does not give you fine grain checking, but it's a simple way to avoid some unnecessary updates at the repository level.
To make this a little easier, a GetPropertiesToIncludeInDirtyCheck method could be added, which would retrieve a list of properties which need to be checked.
interface IDirtyTracker {
IENumerable<Object> GetPropertiesToIncludeInDirtyCheck();
}