Posting POCO JSON Directly To A Service

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?

As always, many thanks!

-Z

The Recommended API Structure and Simple Customer Demo should help here.

You shouldn’t re-use your DTO Types as a Request DTO, instead I’d have explicit Request DTOs for each operation, e.g:

[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.

1 Like

@mythz Thanks for your reply.

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.

Thanks, as usual, for your thoughtful reply.

-Z

1 Like

I prefer to think Request DTOs as declaration of your API contract instead of logic that should be DRY’ed.

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.

1 Like