I'm working with breeze labs AbstractRestDataServiceAdapter. In our data service adapter implementation's _createSaveRequest method our state.isModified branch emulates your oData adapters and only sends modified fields in the save request.
My issue is that our REST server returns a sparse response, i.e. input data and any fields on the entity that were updated. The result is that from a client perspective fields not returned in the saved entity are being wiped out.
I had seen merge logic in prior debugging sessions, so I initially thought I might be able to influence the save response processing via MergeStrategy, but it appears MergeStrategy doesn't apply in a save scenario. It appears AbstractRestDataServiceAdapter assumes the server is returning the full entity in a save response.
What options do we have for managing a sparse response from the server that preserves the state of fields not returned in the save response?
Is there a particular AbstractRestDataServiceAdapter method that we should override to manage merging the save response?
Take a look at the changeRequestSucceeded method of the breeze.labs.dataservice.abstractrest.js adapter which processes each entity-specific response in particular the lines at the top:
var saved = saveContext.adapter._getResponseData(response);
if (saved && typeof saved === 'object') {
// Have "saved entity" data; add its type (for JsonResultsAdapter) & KeyMapping
saved.$entityType = saveContext.originalEntities[index].entityType;
addKeyMapping();
} else {
...
}
saveContext.saveResult.entities.push(saved);
return saved;
Notice the references to saveContext.originalEntities[index].
Suppose you know that the data in the saved object represent just the specific properties that you need to merge into the entity in cache.
Well you're in excellent position here, in YOUR version of this method in YOUR concrete implementation of this adapter, to combine the property values of saved and the property values of saveContext.originalEntities[index] before pushing that merged result into saveContext.saveResult.entities.
There is no requirement to actually return entities from the server on a save. Both the breeze.dataService.odata and the breeze.dataservice.mongo adapter have this issue where the server only returns some or parts of the saved entites. The only requirement is that the dataService adapter saveChanges method return an object with two properties, i.e. something like
return { entities: entities, keyMappings: keyMappings };
If you actually have just the modified fields returned from the server then will have to manage the merge yourself, but this isn't really that complex. For each entity 'saved' simply locate it in the cache, set the changed properties and call acceptChanges and the return the 'located' entity in the result shown above.
Related
I'm currently writing a distributed application with a microservice architecture.
For that I am applying the CQRS pattern and event sourcing with the help of the axon framework. Therefore the data is eventual consistent.
Both, the write and the read side, are accessible over HTTP; REST specifically.
The initial problem:
After updating/creating an entity, the user [1] should be able to see the results. Because the events are handled asynchronously, the client/UI doesn't know when the entity is really updated (or created). So when the client fetches the data after sending the update-request but before the event is processed, the unchanged data is returned. Therefore the user could think, that the application is broken and/or sends a new request.
Solution attempt:
While looking for a solution for the read-after-write problem I came accross this blog entry.
There is proposed to return the new entity version in the write response. The client can then request the data with the expected entity version (as Expect header). If the actual version is equal or greater than the expected version, the data is returned. Or else an empty response with a Retry-After Header is returned.
The problem:
When the client sends an UpdateFoo request to the write side, the application sends a corresponding UpdateFooCommand over the CommandGateway. The Command is processed by the entity aggregate which publishes the FooUpdatedEvent. The read side receives this event and updates its entity view which can be accessed over the REST interface of the read side.
This is controlled by the axon framework. The handlers are annotated with #CommandHandler and #EventSourcingHandler respectively.
Now: How can I access the new version number of the affected entity in the CommandHandler, so that this number can be returned in the update response?
Thanks in advance
[1] Not only users. There can als be non human clients.
you can use AggregateLifecycle.getVersion() from within your aggregate. You can choose to return that value as part of your command's results and pass that information when doing a query. If the query doesn't have that version number of the aggregate's information, yet, you can (wait and) retry.
When updating a resource via REST, should one include in the body just the values to update, or the whole object (current values and values to update)?
If a User object looks like this
User (id, name, age, sex)
and I want to update only his name and age, should my request look like this:
PUT /users/1
{"name":"john","age":18}
or like this:
PUT /users/1
{"name":"john","age":18, "sex":"m"}
And what should that look like on the server side?
#RequestMapping(value = "/{userId}", method = PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> updateUser(#PathVariable final int userId, #RequestBody User u){
//fetch user by ID
user.setName(u.getName())
user.setAge(u.getAge())
user.setSex(u.getSex()) //this will be empty?
return new ResponseEntity<String>(gson.toJson(user), HttpStatus.OK);
}
Or alternatively I could find out which variables were not included in the request body and do something like this
if(u.getName()!=null){
user.setName(u.getName())
}
if(u.getAge()!=null){
user.setAge(u.getAge())
}
if(u.getSex()!=null){
user.setSex(u.getSex())
}
Is there a right/wrong way to achieve this, or is it a case of just doing what's easiest?
PUT requests must be idempotent and should provide as its payload a complete representation of the entity it is replacing. (https://www.rfc-editor.org/rfc/rfc7231#section-4.3.4)
The PUT method requests that the state of the target resource be
created or replaced with the state defined by the representation
enclosed in the request message payload.
A partial JSON object PUT request would be a PATCH with Content-Type: application/merge-patch+json (https://www.rfc-editor.org/rfc/rfc7396)
Things to think about. You might have multiple clients updating an entity at the same time, using a PUT could end up overwriting changes other clients have made.
In that case you might want to set a pre-condition to check if the object was updated between the time that the requesting client fetched the entity, made changes and submitted the PUT/PATCH request. For example the pre-condition could be a last updated timestamp, hash (Etag) or a version number; Or you could use a "last write wins" approach which is common in eventually consistent systems. It all depends on your system and the situation.
On the server side, if you support partial updates then as you have provided in your example, you would identify the set of properties included in the request and only set the specific ones that were provided.
I'm using Azure Mobile Apps and TableControllers in my project. Development has been going quite smoothly, until now. One of my tables relies on quite a bit of business logic in order to return the appropriate entities back to the client. To perform this business logic I need to get some parameters from the client (specifically, a date range).
I know I could use an APIController to return the data, but won't that break the entity syncing that's provided by the SyncTables in Xamarin?
My current logic in my GetAll is:
public IQueryable<WorkItemDTO> GetAllWorkItem()
{
//Return all the work items that the user owns or has been assigned as a resource.
var query = MappedDomainManager.QueryEntity().Where(x => x.OwnerId == UserProfileId || x.Resources.Where(r => r.AssignedResourceId == UserProfileId).Count() > 0);
return query.Project().To<WorkItemDTO>();
}
What I would like is to be able to somehow pass through a start and end date that I can then use to build up my list of WorkItemDTO objects. The main problem is that a WorkItem entity can actually spawn off multiple WorkItemDTO objects as a WorkItem can be set to be recurring. So for example say a WorkItem is recurring once a week, and the user wants to see a calendar for 1 month, that single WorkItem will spawn 4 separate concrete WorkItemDTO objects.
Then when a user modifies one of those WorkItemDTO objects on the client side, I want it to be sent back as a patch that creates its own WorkItem entity.
Does anyone know how I can get a TableController to receive parameters? Or how to get an APIController to work so that client syncing isn't affected?
Any help would be appreciated.
Thanks
Jacob
On the server, you can add a query parameter to the table controller get method easily, by adding a parameter with the right name and type.
For instance, you could add a dateFilter query parameter as follows:
public IQueryable<WorkItemDTO> GetAllWorkItem(string dateFilter)
This would be called by passing a dateFilter=value query parameter. You can use any data type that ASP.NET Web API supports in serialization. (Note that if you don't have a GetAll that takes no query parameters, you will get an Http 405 Method Not allowed if you do a Get without this query parameter.)
On the client, as noted by #JacobJoz, you just use the method IMobileServiceTableQuery.WithParameters to construct the query that is passed to PullAsync. If you have multiple incremental sync queries against the same table and they use different values for the parameters, you should make sure to include those in the queryId to pull.
That is, if you have one query with parameters foo=bar and another that is foo=baz for the same sync table, make sure you use two different query IDs, one that includes "bar" and one that includes "baz". Otherwise, the 2 incremental syncs can interfere with one another, as the queryId is used as a key to save the last updated timestamp for that sync table. See How offline synchronization works.
The part that is unfortunately hard is passing the query parameter as part of the offline sync pull. Offline sync only works with table controllers, FYI.
There is an overloaded extension method for PullAsync that takes a dictionary of parameters, but unfortunately it requires a string query rather than IMobileServiceTableQuery:
PullAsync(this IMobileServiceSyncTable table, string queryId, string query, IDictionary<string, string> parameters, CancellationToken cancellationToken)
(I've filed a bug to fix this: Add a generic PullAsync overload that accepts query parameters).
The problem is that there's no easy way to convert from IMobileServiceTableQuery to an OData query string, since you'd need to access internal SDK methods. (I filed another issue: Add extension method ToODataString for IMobileServiceTableQuery.)
I've looked through the source code for MobileServiceTableQuery on github. It looks like it exposes a method called WithParameters. I have chained that method call onto CreateQuery in order to generate the query to the server, and it seems to do what I want.
Here is the client code:
var parameters = new Dictionary<string, string>();
parameters.Add("v1", "hello");
var query = WorkItemTable.CreateQuery().WithParameters(parameters);
await WorkItemTable.PullAsync("RetrieveWorkItems", query);
On the server I have a GetAll implementation that looks like this:
public IQueryable<WorkItem> GetAllWorkItem(string v1)
{
//return IQueryable after processing business logic based on parameter
}
The parameterized version of the method gets called successfully. I'm just not entirely sure what the impacts are from an incremental pull perspective.
I'm writing a REST service which is dealing with SomeKindOfResource stored in a database.
Don't ask me why (don't!) but for some reasons, the corresponding underlying table has a variable number of columns. That's the way it is and I can't change it.
Therefore, when I issue a GET /SomeKindOfResources/{id}, my DTO (later on serialized to JSON) might then contain a variable number of "fields". I know how to handle the dynamic object / serialization parts. My question is more on the philosophy side of things.
Let's say my client wants to know what will be the list of fields returned by a call to GET /SomeKindOfResources/{id} because, for example, that list determines what can be used, later-on, to filter out a list of SomeKindOfResources. Basically, I need something resembling a "GetCapability".
How would you deal with such a scenario in a RESTful way?
If I understand your requirement correctly, you want to return a metadata like response for a specific object (i.e. by Id) that has dynamic fields, so your client knows the field types it will receive when requesting that object.
Just a word of caution: A dynamic DTO isn't RESTful. The point of a DTO is that it is an agreed contract. It shouldn't change and as such there isn't a RESTful rule to handle your use case.
If you were to implement this, these are three possible approaches.
Metadata Route:
Create a new route, in your service, as this scenario isn't covered by the standard ServiceStack MetadataFeature, as it only works with static DTOs. So create something like this:
[Route("/SomeKindOfResources/{Id}/metadata", "GET"]
Then you would want the response to that route to describe the fields to your client. This is where it gets cloudy. The MetaDataFeature uses XSD to describe your standard DTOs, you could write your action to produce an XSD response which would describe your fields, based on your database lookup of available fields. But then will your client know how to parse XSD? As your use isn't standard, and the client can't be expected to handle it in a RESTful way, so you may just want to use a simple response type, like a Dictionary<string,Type>() essentially just returning field name, and underlying type. This will work fine for simple built in types, like string, int, bool etc, but custom class scenarios will be harder to handle, such as List<MySpecialType>.
Pseudo client code:
var fieldMetaData = client.get("/SomeKindOfResources/123/metadata");
var result = client.get("/SomeKingOfResources/123");
Example XSD Metadata Response.
OPTIONS header:
However you may wish to consider using the OPTIONS verb instead of a GET request to another prepended with /metadata, as recommended by RFC2616 ยง9.
This method allows the client to determine the options and/or requirements associated with a resource ... without implying a resource action or initiating a resource retrieval.
Pseudo client code:
var fieldMetaData = client.options("/SomeKindOfResources/123");
var result = client.get("/SomeKindOfResources/123");
But remember OPTIONS in REST is typically used for setting up CORS.
ServiceStack JSON __type response:
When ServiceStack returns JSON, you can tell the ServiceStack.Text serializer to include the return type information in a property call __type. Although this may not be easy for your clients to interpret, and it also applies globally to all JSON responses, so wouldn't be limited to just that action. In your configure method add:
JsConfig.IncludeTypeInfo = true;
Pseudo client code:
var result = client.get("/SomeKingOfResources/123");
var typeInformation = result.__type;
Am bit stuck by these three questions:
1) I see that diff is calculated in AutoBeanUtils's diff method. I saw a tag called parentObject in the entity which is used in the comparison to calculate diff.
parent = proxyBean.getTag(Constants.PARENT_OBJECT); in AbstractRequestContext class.
Does that mean there are two copies for a given entity thats loaded on to the browser? If my entity actual size is say 1kb, actual data loaded will be 2kb (as two copies of entity are getting loaded onto the browser) ?
2) On the server side:
Suppose I have to fetch an entity from the database, the static find<EntityName> should be such that I have to make a db call every time, or is there a way where I can fine tune that behavior? [Sorry I did not understand the locator concept very well.]
3) What happens if there is a crash on the server side(for any reason which need not be current request specific) when a diff is sent from the client?
Thanks a lot.
when you .edit() a proxy, it makes a copy and stores the immutable proxy you passed as argument as the PARENT_OBJECT of the returned proxy.
you'd generally make a DB call every time the method is called (this is the same for a Locator's find() method), which will be no more than twice for each request. You can use some sort of cache if you need, but if you use JPA or JDO this is taken care of for you (you have to use a session-per-request pattern, aka OpenSessionInView)
If there's any error while decoding the request, a global error will be returned, that will be passed to onFailure of all Receivers for the failed RequestContext request.
See https://code.google.com/p/google-web-toolkit/wiki/RequestFactoryMovingParts#Flow