Why is DELETE not supported on to-many-association resources in Spring Data REST? - rest

I am using Spring Data REST. I am trying to unbind a collection association from an entity (item). i.e. - a property of the item is of List type. I want to remove all items from that List.
To do this, I am using the DELETE method:
curl -X DELETE …/categories/54ea0bcf27a2fb1b4641083a/fixedParentCategories
This gives me a 405 Method not allowed error code. But, it works for a single valued association (when it is not of List type). The documentation clearly lists DELETE as a supported method for associations. I'd like to know if there is a way around this. Also, I tried using PUT (Content-Type: text/uri-list) with an empty body, and it gives an error about missing request body. Other operations on this association are all working fine - I am able to add items to this collection, etc.
My entity looks like this:
#Document
public class Category {
#DBRef(lazy = true)
private List<Category> fixedParentCategories;
…
}

I just checked the code and you're right, we're actively rejecting DELETE requests for Maps and collections. The rationale is as follows:
An association that is of Map or collection must never be null in the domain model. Translating this into HTTP resources means that the resource will always be available and in the worst case return an empty representation (empty JSON array, or empty JSON object). Accepting a DELETE request would logically null the relationship in the domain model and thus lead to a state that contradicts the very first assumption.
We generally recommend to simply PUT an empty body with media type text/uri-list to the association resource to empty out the associations as that's semantically more correct. Consider it like the difference between truncating and dropping a database table.
If you think that should change and have good reasons that you can back your request with, feel free to open a ticket in our JIRA.

Related

New DTO or Field Selector for API?

I am working on new API, but I am stuck with the choice for enabling Projection support.
my Entity User contains some properties and have some relationships too.
What should be the preferred approach for API?
Approach1
myApi.com/User/Fields="Id,Name,Email"
it returns my UserDTO with just populating Id,Name,Email and rest properties are null (I can further ignore the null before serializing JSON to send over the wire)
Approach2
myApi.com/User/GetCustomPropertiesABC"
it returns my UserCustomABCDTO . This Model contains just three properties for Id, Name, Email.
My question
I personally feel Approach 1 gives more Reuse quotient to API, Every time new selector required in Approach 2 will need to create a New DTO, But what is standard as per REST principles?
well, you could use ODATA for this, it would be perfect for it actually : http://www.odata.org/
Or, you could create an endpoint which accepts a request like your Approach 1 and returns dynamic. This way you don't have to worry about creating DTOs, you just create a new dynamic object, add whatever properties are required and return just that.
This keeps the returned entity small as it avoids who knows how many null or empty properties which don't really add anything useful.

Entity Framework Include statements loading unexpected extra data

Here's a snippet of my repository code:
public IQueryable<Task> GetTasks()
{
return Entities.Tasks.Include("Categories")
.Include("Categories.Documents")
.Include("Categories.Documents.User");
}
In my model, User objects have a Documents navigation property which, you'll note, I'm not asking for here. Yet the object tree that results from this statement includes all the Documents collection on each User and, furthermore, all the Users on each of those Documents and so on, all the way down the rabbit hole.
Why am I getting all these unasked for properties, and is there anything I can do to stop them? I only actually need a single property on each User object, but AFAIK you can't "Include" or "Load" individual properties. I'm using DB first so, again AFAIK, there's no straightforward way of making this a one-way relationship (for my purposes only Document.User matters,not User.Document).

Creating a Breeze Entity including navigationproperties using manager.createEntity throws exception

Scenario:
I use breeze for querying in our SPA and raw http methods for POST PUT DELETE methods.
A POST method on a resource returns the created resource including it's created childobjects.
I want to attach this created resource to the beeze entity manager.
I've tried adding the entity using
manager.createEntity('Driver', data, breeze.EntityState.Unchanged);
where the data object contains the driver resource and an array of related child entities.
But get an exception: "Collection navigation properties may NOT be set."
Do I have to create the local entity by hand and attach the child entities or does breeze support this scenario?
The reason for this exception is that the 'createEntity' method creates the entity and then assigns your 'data' to it, but for any collection navigation properties the collection already exists and Breeze won't allow you to replace it. This was a deliberate choice for existing entities where other parts of the application might hold a reference to the collection, but is overkill in this case where you are the 'first' to access the collection. For now, the workaround is to update any navigation collections instead of replacing them.
So the simplest way to do this is to call the createEntity method without any collection data properties, and then push data into your collections
var driver = manager.createEntity('Driver', dataWithoutCollections, EntityState.Unchanged)
// then update collection properties by pushing into them.
trafficFines.forEach(function(trafficFine) {
driver.trafficFines.push(trafficFine); // or use push.apply
};
Note that adding to an entity's collection properties will not cause an EntityState change so this should be sufficient.
Based on this issue, I will add a feature request to suppress this exception in the case where you are calling the 'createEntity' method, since there is no danger that some other part of the application has already had access to the new entity.

Breeze JS Adding a static Lookup dictionary to Metadata

One of my domain models has an Enum property that I like to create a dropdown box for, but the EFContextProvide Metadata function doesn't automatically import the Enum Entity Type for me to access it, so I created a static dictionay of that I like to add to the Metadata Mapping, acting as a lookup table. How can I add Enum entity type, so I can call:
breeze.EntityManager.createEntity(myEnum,...)
right now, I get the following error:
Error: Unable to locate an 'Type' by the name: myEnum
Any suggestion?
UPDATE: (I just added the enumType info of the Metadata function call)
"enumType":{"name":"Plugins","isFlags":"false","underlyingType":"Int32","member":["name":"Custom","value":"0"},{"name":"PluginOfTypeA","value":"1"},{"name":"PluginOfTypeB","value":"2"}]}
Thanks #Jay for your response, I was set in the right direction. Here is what I can say about dealing with Enum:
I created a lookup list on the server that I can separately call, to populate the dropdown list. I have a regular array that I initialize on the success promise of the results, list this data.results[0].myEnumLookup and then on the Viewmodel, I access that property and set in to the ko.observableArray() so I can refer to it in my View. Make sure you set the value: property of the select tag, to the value of item.
But the problem with doing it this way was that at the Save time, it wasn't reading Enum value and it was treating it as just text, so it was failing, so
More robust solution:
In our application we happen to really benefit from having an Enum and their pre-compile value, since we are using those Enum Domain models in other POCO projects, so I ended creating an EF DbSet and proper table that will be populated with all of my Enums values and I can save them into the DB, so now we have the list of items in DB, and I created a single level of inheritance for Enums, so in my controller, I get a IQueryable method that will get all of those Enums, and in the breeze application, in my config file, I define the types of enums, and then I will populate lists of items based on different types in my config, so I can refer to it in my view and binding it to the ko.observableArray(). Also in my original class, I no longer refer to the Enum, I will create MyEnumId as well as virtual MyEnum property that will do the mapping automatically in my EF5 setup.
Lesson I learned, even though Enum in .NET4.5 & EF5 is possible to store and read back, but it's not very practical when it comes to SPA front-end technologies, so I prefer having the integer value, and just manage the enums outside of it.
Not entirely sure I understand the question. By 'Enum entity type' do you mean an 'EntityType' that only has a fixed number of possible instances? If so, you can simply query the entire collection of these entity/instances onto the client and add them directly into your static dictionary. Since, the collection is conceptually immutable, you can query this at the beginning of you session. Further, you should NEVER need to create an instance of any of these 'entity enums' because you can always extract them from your dictionary.
But maybe I'm not understanding your question.

wcf data service with Entity Framework

I am trying to create WCF Data service project using Entity Framework. ( I am new to both).
I created entities using DB.
Now, I created service operation, which returns the IQueryable<entity>.
My problem is
I do not want to return the entire set of columns in the entity. I cannot delete them from the entity as it is not null. How to avoid these?
I have few FK columns and I need other column details of the table. How to include columns from other table?
Why it is not possible to use POCO class to be returned from WCF Data service?
How do I format the response; i.e., add few more details to the response like page number etc, change the xml tags, remove few details like "link rel"?
I have tried a lot of things to achieve 1 and 2. But finally I realised that I can only use the entity as it is to make it work.
I have no idea about 4.
Any suggestions would be appreciated.
1. I do not want to return the entire set of columns in the entity.
2. I have few FK columns and I need other column details of the
table.
For this, you should define a new class that matches what you need / what you want your clients to see. That can be a straight POCO class - no special requirements. Assemble that class for each entity, leaving out the unwanted columns, and grabbing the extra field or two for the FK columns into that new class. Return an IQueryable<YourNewClass> instead of the entity class directly.
To avoid huge left-right-assignment statements just to fill the properties of the new class, you should have a look at AutoMapper which makes it really easy to copy around classes that are very similar to one another (e.g. missing or adding a few properties).
4. How do I format the response; i.e., add few more details to the
response like page number etc, change the xml tags, remove few details
like "link rel"?
That's not possible - the OData protocol very strictly defines what's going to be in the message, what links there are etc. If you can't live with that - you'll have to roll your own WCF REST service and drop the WCF Data Service stuff altogether.
Check out the WCF REST Developer Center on MSDN if you want to investigate that route more thoroughly.
Update: that link seems to have gone dead - try WCF Web Http Programming Overview instead.
Make sure you have an Id property or you specify either [Key] or [DataServiceKey("Your_Custom_ID_Property")]
For me this sorted out the issue