A resource describes a URL of the OData service: its path segments and its query options.
You build resources with ODataClient (or with a service) and then call
methods that send requests. Every request method returns an Observable.
The examples in this chapter use the TripPin sample service, as the demo application does.
import { firstValueFrom } from 'rxjs';
const airports = client.entitySet<Airport>('Airports');
// GET Airports
const { entities } = await firstValueFrom(airports.fetch());
// GET Airports?$count=true
const { annots } = await firstValueFrom(airports.fetch({ withCount: true }));
console.log(annots.count);
// GET Airports/$count
const count = await firstValueFrom(airports.count().fetch());
// GET Airports?$top=1
const { entity: first } = await firstValueFrom(airports.fetchOne());
// Fetch pages until there are at least 4 airports
const { entities: four } = await firstValueFrom(airports.fetchMany(4));
// Follow every next link and return all the airports
const { entities: all } = await firstValueFrom(airports.fetchAll());fetch() emits { entities, annots }. annots holds the annotations of the response:
count, skip and skiptoken (from the next link), etag, and so on.
query() changes the resource it is called on. Call clone() first to keep the original:
const unitedStates = airports
.clone()
.query((q) => q.filter(({ e, t }) => e().eq(t.Location.City.CountryRegion, 'United States')));
airports.query((q) => q.filter(({ e, t }) => e().eq(t.Location.City.Region, 'California')));
airports.query((q) => q.filter().clear());Pass the key to entity(). Use an object for compound keys, or to name the key property:
const cyyz = client.entitySet<Airport>('Airports').entity('CYYZ');
const russell = client.entitySet<Person>('People').entity({ UserName: 'russellwhyte' });
cyyz.fetch().subscribe(({ entity, annots }) => console.log(entity, annots.etag));
cyyz.fetchEntity().subscribe((airport) => {});
russell.update(person); // PUT
russell.modify({ FirstName: 'Russell' }); // PATCH
russell.destroy(); // DELETESend the entity ETag with the etag option to use optimistic concurrency:
russell.modify(changes, { etag: annots.etag }).
const trips = russell.navigationProperty<Trip>('Trips');
trips.fetch().subscribe(({ entities }) => {});
trips
.entity(0)
.fetch()
.subscribe(({ entity }) => {});
// $ref
russell.navigationProperty<Person>('Friends').reference();
// Single property value
russell
.property<string>('FirstName')
.fetchProperty()
.subscribe((value) => {});Media entities, such as TripPin photos, expose their content with media():
client
.entitySet<Photo>('Photos')
.entity(person.Photo)
.media()
.fetchBlob()
.subscribe((blob) => (image.src = URL.createObjectURL(blob)));Unbound callables are built from the client. Bound callables are built from the resource they are bound to.
Example :// Unbound function
client
.function<{ lat: number; lon: number }, Airport>('GetNearestAirport')
.callEntity({ lat: 33, lon: -118 })
.subscribe((airport) => {});
// Function bound to an entity
russell
.function<{ userName: string }, Trip[]>(
'Microsoft.OData.SampleService.Models.TripPin.GetFriendsTrips',
)
.callEntities({ userName: 'ronaldmundy' })
.subscribe((trips) => {});
// Unbound action
client.action<null, null>('ResetDataSource').call(null).subscribe();The call* helpers choose how the response is read: callProperty, callEntity,
callEntities, callModel, callCollection, callArraybuffer and callBlob. Generated
services include typed methods for every callable. See Code generation.
client
.singleton<Person>('Me')
.fetch()
.subscribe(({ entity }) => {});batch().exec() collects every request created inside its callback and sends them all in a
single $batch request. Each inner observable still emits its own response.
import { combineLatest } from 'rxjs';
const people = client.entitySet<Person>('People');
client
.batch()
.exec(() =>
combineLatest({
russell: people.entity('russellwhyte').fetch(),
scott: people.entity('scottketchum').fetch(),
}),
)
.subscribe(([result$, response]) => result$.subscribe(({ russell, scott }) => {}));When you register several APIs, use apiFor() to build resources for one of them:
const northwind = client.apiFor('Northwind');
const orders = await firstValueFrom(northwind.entitySet<Order>('Orders').fetchEntities());A resource can be converted to JSON, for example to keep the current query of a page, and rebuilt later:
Example :const json = airports.toJson();
const restored = client.fromJson(json) as ODataEntitySetResource<Airport>;
restored.fetch().subscribe(({ entities }) => {});// GET $metadata, parsed into an ODataMetadata object
client
.metadata()
.fetch()
.subscribe((metadata) => console.log(metadata.toConfig()));ODataClient also has get, post, put, patch, delete and request methods that
take a resource or a URL, for cases the resource API does not cover.
Every resource has a query() method that edits its query options. See
Query builder.
airports.query((q) => q.top(5));
console.log(airports.toString()); // Airports?$top=5