Day 2: Open data feeds
Last updated
Last updated
Create open data RPDE feeds live from your application.
Open Booking API is built on top of open data feed publishing, and RPDE feeds are therefore a prerequisite to implementing the rest of the API.
Even for systems that have already implemented OpenActive open data feeds, it is highly recommended that the feed generation code is migrated to within the OpenActive.Server.NET framework, using the steps below. This will greatly simplify the rest of the implementation, and increase maintainability.
Before continuing with this tutorial, the following video offers a good theoretical understanding of the RPDE specification. Further information can be found in the developers guide and RPDE specification.
In order for opportunities and offers within open RPDE feeds to be bookable via the Open Booking API, they must have IDs.
The Open Booking API is based on JSON-LD. JSON-LD IDs always take the form of a URL, and hence all IDs within the Open Booking API also take the form of a URL. The StoreBookingEngine
automatically constructs and parses these URLs for you, and deserialises them into POCOs. It also handles routing based on the URL template to the relevant store depending on the type of opportunity.
In order to take advantage of these features, you need to configure the URL structure specifically for your application.
When making changes to these setting, specifically for IBookableIdComponents
, consider using Visual Studio's refactoring tools to alter the example provided, to ensure that the rest of the project still compiles.
The first URLs we'll set up are for the Opportunity and Offer pairs, such as the IDs found in the Open Booking API request snippet below:
There are two key components that handle JSON-LD ID serialisation and deserialisation within the StoreBookingEngine
:
IBookablePairIdTemplate
instances specify the ID URL templates used by your application and associates them with OpenActive opportunity types, as well as the hierarchy of types that are in use from the OpenActive data model. They also define the types of opportunities that are bookable, and which feeds are used to publish the opportunities.
IBookableIdComponents
are POCO objects that you define specifically based on the underlying data model within your booking system, used to deserialise the ID URL. The properties within these are mapped by name to the placeholders within the associated IBookablePairIdTemplate
URL templates. IBookableIdComponents
represents an Opportunity and Offer pair, and hence includes both the Opportunity ID and Offer ID, with their matching overlapping components.
Note that the JSON-LD IDs do not need to resolve to actual endpoints, provided they are unique and exist within your domain.
IBookablePairIdTemplate
instances are configured in Startup.cs
or ServiceConfig.cs
within BookingEngineSettings
:
IBookableIdComponents
are defined by the classes in the IdComponents
directory.
These classes must be created by the booking system. There is a choice of string
, long?
and Uri
available as the type for each component of the ID, as well as any enum
type. The names of the components must exactly match the placeholders within the associated IBookablePairIdTemplates
.
The Seller IDs are configured slightly differently to the Opportunity and Offer pair IDs, for simplicity.
There is a built-in POCO named SellerIdComponents
that is defined as follows:
Within BookingEngineSettings
the SellerIdTemplate
setting controls how the Seller ID is serialised and deserialised. There are two options for Seller IDs: Single Seller and Multiple Seller.
Depending on the type of your internal Seller ID, you may use either SellerIdLong
or SellerIdString
within the URL template. Once you have chosen which one to use, simply reference that same property consistently wherever you use the Seller ID throughout your code, and ignore the other property.
The following example demonstrates BookingSystemSettings
for Multiple Sellers:
To use Single Seller mode, simply use neither SellerIdLong
or SellerIdString
within the URL template, and set HasSingleSeller
to true
. Then simply do not reference SellerIdComponents
anywhere in your code, as both SellerIdLong
and SellerIdString
will be null. RenderSingleSellerId
is provided for scenarios where a Single Seller ID needs to be rendered.
The following example demonstrates BookingSystemSettings
for a Single Seller:
The StoreBookingEngine
handles the serialisation and parameter validation that would usually be required when implementing an RPDE feed. All that is required for each feed is to implement a single method within an IOpportunityDataRPDEFeedGenerator
class.
If you have already implemented RPDE feeds within your application using OpenActive.NET, your existing database queries and OpenActive model mapping should easily transferable to within the generator method.
Within BookingEngineSettings
within EngineConfig.cs
the OpenDataFeeds
setting configures the routing to the different feed generators from the GetOpenDataRPDEPageForFeed
method being called in the controller.
Three implementations of IOpportunityDataRPDEFeedGenerator
are available depending on your prefered RPDE Ordering Strategy, and whether your ID is a long
or string
.
Using the example of the IBookableIdComponents
class SessionOpportunity
from Step 2, and the OpenActive feed root type of ScheduledSession
, a generator is created by subclassing one of the following:
RPDEFeedModifiedTimestampAndIDLong<SessionOpportunity, ScheduledSession>
RPDEFeedModifiedTimestampAndIDString<SessionOpportunity, ScheduledSession>
RPDEFeedIncrementingUniqueChangeNumber<SessionOpportunity, ScheduledSession>
Any of the above would require the same GetRPDEItems
method be implemented, as below:
The appropriate query for the database for your chosen RPDE Ordering Strategy must be used, and the ordering of the items returned from your overridden method is automatically validated to ensure consistency with the specification.
Within the mapping of your data to the OpenActive model, there are a few helper methods available from the base class to construct IDs specific for the feed:
The DatasetSiteGeneratorSettings
within EngineConfig.cs
can be used to configure your dataset site.
Only the OpenDataFeedBaseUrl
is used by the StoreBookingEngine
, so this must be accurate to proceed with testing.
All other settings are described within the documentation for OpenActive.DatasetSite.NET.
If you have already implemented a dataset site within your application using OpenActive.DatasetSite.NET, the settings should be easily transferable to EngineConfig.cs
.
If you run your application and navigate to the dataset site endpoint (e.g. https://localhost:44307/openactive), you should find it now reflects your updated settings, and the links to the RPDE pages on that page work as expected.
Where you these referenced in the example above...
The following annotations apply...
SessionOpportunity
and EventOpportunity
Examples of an IBookableIdComponents
POCO used to map to placeholders within the ID templates defined
BookablePairIdTemplate
A template that contains a hierarchy of up to three OpenActive types, in order from child to parent (e.g. ScheduledSession
→ SessionSeries
→ EventSeries
). BookablePairIdTemplate
accepts the generic parameter of an IBookableIdComponents
type, which binds the placeholders within the URL templates specified to the properties defined within the IBookableIdComponents
POCO.
BookablePairIdTemplateWithOfferInheritance
A specialism of BookablePairIdTemplate
designed for the special case of ScheduledSession
→ SessionSeries
where Offers may be inherited from SessionSeries
to ScheduledSession
.
OpportunityType
The OpenActive opportunity type represented
AssignedFeed
The feed within which this opportunity type is published (for example, the EventSeries
may be embedded within a SessionSeries
feed as shown in this example).
OpportunityUriTemplate
OfferUriTemplate
The URL Templates
used to serialise/deserialise the POCO for an Opportunity ID and Offer ID. Note that the Opportunity ID and Offer ID are deserialised into the same POCO, as an Opportunity and Offer pair, and hence any shared components within these must match (e.g. an Offer is specific to an Event, and hence will include both the Event ID and and
Bookable
Whether the specified Opportunity and Offer pair is bookable within this booking system using the Open Booking API. Note that SessionSeries
and FacilityUse
are not bookable within the Open Booking API, which instead prefers ScheduledSessions
or Slots
.
BaseUrl
This is a placeholder within the ID templates that has a special function of ensuring conformity with the JsonLdIdBaseUrl
setting within BookingEngineSettings
, both for serialisation and deserialisation.
In the example above
Description
OpportunityType
The OpportunityType
represents the type in the hierarchy that the Opportunity and Offer pair represents (e.g. HeadlineEvent
or its child Event
). This property is available by the class extending either IBookableIdComponents
or IBookableIdComponentsWithInheritance
.
OfferOpportunityType
For SessionSeries
, where the Offer
can be inherited to the child ScheduledSession
, OfferOpportunityType
indicates which Offer
is being referenced - the parent or the child. This property is only available by the class extending IBookableIdComponentsWithInheritance
.
Method
Example
RenderOpportunityId
Id = this.RenderOpportunityId(new SessionOpportunity
{
OpportunityType = OpportunityType.SessionSeries,
SessionSeriesId = @class.Id
}),
RenderOfferId
Id = this.RenderOfferId(new SessionOpportunity
{
OfferOpportunityType = OpportunityType.SessionSeries,
SessionSeriesId = @class.Id,
OfferId = 0
}),
RenderSellerId
(for Multiple Sellers)
Id = this.RenderSellerId(new SellerIdComponents
{
SellerIdLong = seller.Id
}),
RenderSingleSellerId
(for Single Seller)
Id = this.RenderSingleSellerId(),