diegomvh / angular-odata

Client side OData typescript library for Angular
https://www.npmjs.com/package/angular-odata
MIT License
50 stars 14 forks source link

How to create such an endpoint `api/Student('dany')/Girlfriends` using `angular-odata`? #44

Closed icapri closed 3 years ago

icapri commented 3 years ago

Holà Diego!

In C# it is possible to write something like this:

var tripEvent = client
    .For<Person>()
    .Key("russellwhyte")
    .NavigateTo<Trip>()
    .Key(1003)
    .NavigateTo(x => x.PlanItems)
    .As<Event>()
    .Set(CreateEventDetails())
    .InsertEntryAsync();

I would like to know whether I have the posibility to create a new Girlfriend DTO for the Student called "dany".

Which means I want to send a POST request to .../api/Student('dany')/Girlfriends by using your package client-side.

Thank you very much in advance for your response!

Kind Regards,

Kapri

diegomvh commented 3 years ago

Hola @i-kapri

Assuming that the code in #C creates a new EventDetails and adds it to the collection of PlanItems

// Resource for alice
var alice = client.entitySet<Student>("Student").entity("alice");
// Resource for bob
var bob = client.entitySet<Student>("Student").entity("bob");
// Navigate to Girlfriends of bob and add alice as a new one :) asume than Girlfriends is a collection
bob.navigationProperty<Student>("Girlfriends")
  .reference()
  .add(alice)
  .toPromise();

There is an issue regarding relationships here #21

Hope this helps

Diego

icapri commented 3 years ago

Holà @diegomvh !

Gracias por su respuesta!

In my situation, it looks a bit different:

var alice = { Name : 'Alice' };
// Resource for bob
var bob = client.entitySet<Student>("Student").entity("bob");
// Navigate to Girlfriends of bob and add alice as a new one :) asume than Girlfriends is a collection
bob.navigationProperty<Student>("Girlfriends")
  .reference()
  .add(alice)
  .toPromise();

Is this possible with angular-odata ? In C# I can write the same/similar code with OData-Client:

this.ODataClient.For<Student>("Student")
               .Key("bob")
               .NavigateTo(s => s.Girlfriends)
               .Set(new Dictionary<string, object> {{ "Name", "Alice" }})
               .InsertEntryAsync()
               .Wait();

Gracias de antemano por su ayuda!

Muchos Saludos Kapri

diegomvh commented 3 years ago

Hi @i-kapri

Is it possible to modify an entity or a collection through a navigation property? https://github.com/OData/WebApi/issues/945#issuecomment-342227831

In the ODataClient examples the insertions are made on the entity sets https://github.com/simple-odata-client/Simple.OData.Client/wiki/Adding-entries

... After the entities are created they are eventually linked to each other (this is OData 3) https://github.com/simple-odata-client/Simple.OData.Client/wiki/Linking-and-unlinking-entries

Something equivalent to creating and adding to the collection using angular-odata is:

// Student EntitySet Resource
var students = client.entitySet<Student>("Student");
// Create Entity
 //if the prefer return=representation header is set the return of the post is de representation of alice in the backend
// https://github.com/diegomvh/angular-odata/blob/664a28306782588f26e059eaf6cc258963811c0f/projects/angular-odata/src/lib/types.ts#L34
var alice = await students.post({ Name : 'Alice' }).toPromise();
// Resource for bob
var bob = students.entity("bob");
// Navigate to Girlfriends of bob and add alice as a new one :) asume than Girlfriends is a collection
//  the add method needs a resource that point to alice
bob.navigationProperty<Student>("Girlfriends")
  .reference()
  .add(students.entity(alice.Name))
  .toPromise();

Each type of resource inherits from a base type that guarantees the possibility of performing the actions of get,post, patch,delete, etc but does not publish them except to build its own functionality according to my interpretation of the standard :)

For example, you can create and get entities from an entity set https://github.com/diegomvh/angular-odata/blob/664a28306782588f26e059eaf6cc258963811c0f/projects/angular-odata/src/lib/resources/types/entity-set.ts#L202 ... but it can only be get from a navigation property https://github.com/diegomvh/angular-odata/blob/664a28306782588f26e059eaf6cc258963811c0f/projects/angular-odata/src/lib/resources/types/navigation-property.ts#L263

As I discover a little more of the standard I try to incorporate shortcuts to resources according to their type, today the shortcuts are based on get more than post https://github.com/diegomvh/angular-odata/blob/664a28306782588f26e059eaf6cc258963811c0f/projects/angular-odata/src/lib/resources/types/navigation-property.ts#L271

Thanks for write in spanish :)

Saludos Diego

icapri commented 3 years ago

Hi Diego!

Check this out: https://www.odata.org/getting-started/advanced-tutorial/#createContain

The example in the article above shows that it is possible to create a trip for a person using the endpoint serviceRoot/People('russellwhyte')/Trips. Which means that it seems to be possible to modify an entity or a collection through a navigation property.

Below the OData Examples of importance in our case:

Create a Derived Entity
The request below creates an event entity in trips. Event derives from PlanItem.

POST serviceRoot/People("russellwhyte")/Trips(1003)/PlanItems
OData-Version: 4.0
Content-Type: application/json ; odata.metadata=minimal
Accept: application/json

{
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.Event",
"ConfirmationCode": "4372899DD",
"Description": "Client Meeting",
"Duration": "PT3H",
"EndsAt": "2014-06-01T23:11:17.5479185-07:00",
"OccursAt": {
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.EventLocation",
"Address": "100 Church Street, 8th Floor, Manhattan, 10007",
"BuildingInfo": "Regus Business Center",
"City": {
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.City",
"CountryRegion": "United States",
"Name": "New York City",
"Region": "New York"
}
},
"PlanItemId": 33,
"StartsAt": "2014-05-25T23:11:17.5459178-07:00"
}

Response Payload

 Response HTTP/1.1 201 Created
{
"@odata.context": "serviceRoot/$metadata#People('russellwhyte')/Trips(1003)/PlanItems/$entity",
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.Event",
"PlanItemId": 33,
"ConfirmationCode": "4372899DD",
"StartsAt": "2014-05-25T23:11:17.5459178-07:00",
"EndsAt": "2014-06-01T23:11:17.5479185-07:00",
"Duration": "PT3H",
"Description": "Client Meeting",
"OccursAt": {
  "Address": "100 Church Street, 8th Floor, Manhattan, 10007",
  "City": {
    "CountryRegion": "United States",
    "Name": "New York City",
    "Region": "New York"
    },
"BuildingInfo": "Regus Business Center"
  }
}
Update a Derived Entity
The request below updates an event. Event derives from PlanItem.

PATCH serviceRoot/People('russellwhyte')/Trips(1003)/PlanItems(5)/Microsoft.OData.SampleService.Models.TripPin.Event
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json

{
"@odata.type": "#Microsoft.OData.SampleService.Models.TripPin.Event",
"Description": "This is a new description"
}

Response Payload

HTTP/1.1 204 No Content
Delete a Derived Entity
The request below deletes the flight plan item with Id '21' from a trip of person. Flight derives from PlanItem.

DELETE serviceRoot/People('russellwhyte')/Trips(1003)/PlanItems(21)/Microsoft.OData.SampleService.Models.TripPin.Flight

Response Payload

HTTP/1.1 204 No Content

Another helpful article would be this one: https://devblogs.microsoft.com/odata/tutorial-sample-containment-is-coming-with-odata-v4/

Kind Regards Kapri

icapri commented 3 years ago

Hello Diego!

I achieved my goal with a quick hack by accessing the protected method post() in your base class ODataResource like this:

public async create(dto: Partial<TDto>): Promise<TDto> {
      return this.post(dto).pipe(map(o => o.entity!)).toPromise();
   }

Hopefully you can extend your library!

Kind Regards Kapri

diegomvh commented 3 years ago

Hi Kapri

You're right! Based on the examples and continuing with the idea of ​​publishing the behavior that is specific to each resource, it is a matter of incorporating the functionality in the navigation resource. At some point I am always evaluating the possibility of using words like create, destroy, update for the methods that expose the functionality of the post, delete, put respectively ... I accept suggestions .

For now "challenge accepted"

By the way the As of ODataClient in C# is cast in angular-odata.

Regards Diego

icapri commented 3 years ago

¡Hola de nuevo Diego!

¡Infórmeme cuando publique la nueva versión de su paquete!

¡Gracias por adelantado por tu respuesta!

Muchos Saludos Kapri

icapri commented 3 years ago

¡Hola Diego!

I saw that you had committed new changes regarding this issue.

Firstly, let me thank you for your consideration of my feature suggestion.

At second, I would like to know when the next release takes place so that I can proceed with my project.

Thank you in advance!

Kind Regards Kapri

diegomvh commented 3 years ago

Hi Kapri

I released the changes on version 0.75.0 today. Many thanks again for your contribution to enhance the library. And my knowledge of the OData Standard. Still remains me choose good names for http verbs... but for now using post, put, delete on navigation properties you can access to the new functionality.

Regards Diego

icapri commented 3 years ago

Hi again Diego!

This is good news!

Thank you again for your quick reaction and for adding the requested feature to your project!

Kind regards Kapri