I’m building a small application on ServiceStack using OrmLite and AutoQuery.
I’m trying to build the Json interfaces such that the front-end can POST JSON objects directly to the CRUD interface. I’m currently doing this:
POCO Object:
public class StationSetTopBoxMapping
{
[PrimaryKey]
public string StationGuid { get; set; }
public string DeviceId { get; set; }
public int OutputChannel { get; set; }
public string Codeset { get; set; }
}
Service Model (to support AutoQuery):
[Route("/mappings", "GET")]
[Route("/mappings/{StationGuid}", "GET")]
public class GetMappings : QueryDb<StationSetTopBoxMapping>
{
public String StationGuid { get; set; }
}
Service (to service Create/Update/Delete) Note: I’m not quite sure how to control the URLs for these services
public class MappingService : Service
{
public StationSetTopBoxMapping Post(StationSetTopBoxMapping newMap)
{
Db.Insert(newMap);
return Db.Single<StationSetTopBoxMapping>(q => q.StationGuid == newMap.StationGuid);
}
public StationSetTopBoxMapping Put(StationSetTopBoxMapping updateMap)
{
int rowsAffected = Db.Update<StationSetTopBoxMapping>(updateMap, q => q.StationGuid == updateMap.StationGuid);
return Db.Single<StationSetTopBoxMapping>(q => q.StationGuid == updateMap.StationGuid);
}
public StationSetTopBoxMapping Delete(StationSetTopBoxMapping deleteMap)
{
int numRowsAffected = Db.Delete<StationSetTopBoxMapping>(q => q.StationGuid == deleteMap.StationGuid);
return Db.Single<StationSetTopBoxMapping>(q => q.StationGuid == deleteMap.StationGuid);
}
}
My front-end developer likes the way this works because it allows him to POST the JSON object directly to the interface without having to wrap it in a “Request” object.
I like this because it allows me to use a pretty minimal amount of code, and the functionality is quite clear.
Is this the right way to accomplish this, or should I be putting more of this in the Service Model like this:
[Route("/mappings", "PUT")]
public class UpdateMappingRequest : IReturn<StationSetTopBoxMapping>
{
public StationSetTopBoxMapping mapping {get;set;}
}
Whats the right way to allow for simple CRUD against OrmLite POCO objects? Am I making a big mistake implementing CRUD like this?
[Route("/mappings", "POST")]
public class CreateStationSetTopBoxMapping : IReturn<StationSetTopBoxMapping>
{
public string StationGuid { get; set; }
public string DeviceId { get; set; }
public int OutputChannel { get; set; }
public string Codeset { get; set; }
}
[Route("/mappings/{StationGuid}", "PUT")]
public class UpdateStationSetTopBoxMapping : IReturn<StationSetTopBoxMapping>
{
public string StationGuid { get; set; }
public string DeviceId { get; set; }
public int OutputChannel { get; set; }
public string Codeset { get; set; }
}
[Route("/mappings/{StationGuid}", "DELETE")]
public class DeleteStationSetTopBoxMapping : IReturnVoid
{
public string StationGuid { get; set; }
}
Service Implementation
public class MappingService : Service
{
public object Post(CreateStationSetTopBoxMapping request)
{
var mapping = request.ConvertTo<StationSetTopBoxMapping>();
Db.Insert(mapping);
return mapping;
}
public object Put(UpdateStationSetTopBoxMapping request)
{
var mapping = request.ConvertTo<StationSetTopBoxMapping>();
Db.Update(mapping);
return mapping;
}
public void Delete(DeleteStationSetTopBoxMapping request)
{
Db.Delete<StationSetTopBoxMapping>(q => q.StationGuid == request.StationGuid);
}
}
Unless you absolutely need the POST/PUT Services to return the Inserted/Updated Entry I’d consider returning void there as well - you likely wont need it here since you’re not using an AutoIncrementing primary key.
I did read the SimpleCustomer demo, thank you for providing it.
I think the thing which didn’t standout to me was using .ConvertTo in order to map from the DTO to the base class. I think that solves any DB.Insert complexity on the Service side.
As for the Service Model, I was worried about having to maintain property lists in two places (in the object and the DTO), but I guess the benefit is a more maintainable API layer.
Also exposing your DB model to external model binding is a security risk, if you maintain a separate Request DTO it ensures that the only fields that can be populated are those you explicitly specify on your Request DTO contract.