Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Facilities API and Feed Example #311

Closed
nickevansuk opened this issue Jul 27, 2018 · 6 comments
Closed

Facilities API and Feed Example #311

nickevansuk opened this issue Jul 27, 2018 · 6 comments

Comments

@nickevansuk
Copy link
Contributor

nickevansuk commented Jul 27, 2018

Opportunity API for facilities

https://example.com/api/facility-uses

GET https://example.com/api/facility-uses?location.geo[radial]=51.5282923438685,-0.206177163090501,30&event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1

list of facilityUses. The example filter below includes each facilityUse which contains a slot with availability, within the range of startDate, and within a radius of a location
See related discussion about Opportunity API filters here: openactive-archive/opportunity-api#1 and openactive-archive/opportunity-api#2

{
  "@context": "https://www.openactive.io/ns/oa.jsonld",
  "id": "https://example.com/api/facility-uses?location.geo[radial]=51.5282923438685,-0.206177163090501,30&event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1",
  "type": "Collection",
  "totalItems": 4980,
  "view": {
    "id": "https://example.com/api/facility-uses?location.geo[radial]=51.5282923438685,-0.206177163090501,30&event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1&page=1",
    "type": "PartialCollectionView",
    "first": "https://example.com/api/facility-uses?location.geo[radial]=51.5282923438685,-0.206177163090501,30&event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1&page=1",
    "previous": "https://example.com/api/facility-uses?location.geo[radial]=51.5282923438685,-0.206177163090501,30&event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1&page=2",
    "next": "https://example.com/api/facility-uses?location.geo[radial]=51.5282923438685,-0.206177163090501,30&event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1&page=4",
    "last": "https://example.com/api/facility-uses?location.geo[radial]=51.5282923438685,-0.206177163090501,30&event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1&page=498"
  },
  "item": [
    {
      "type": "FacilityUse",
      "id": "http://www.example.org/facility-uses/1",
      "name": "Example Leisure Centre Outdoor Tennis",
      "description": "Table courts are available to hire for thirty minute slots",
      "activity": [
        {
          "id": "http://openactive.io/activity-list/#f2ea7405-6098-4378-b0fe-4e398a659fc4",
          "inScheme": "https://www.openactive.io/activity-list/activity-list.jsonld",
          "prefLabel": "Tennis",
          "type": "Concept"
        }
      ],
      "location": {
        "type": "Place",
        "id": "http://www.example.org/api/locations/8958f9b8-2004-4e90-80ff-50c98a9b121d",
        "url": "https://www.everyoneactive.com/centres/The-Castle-Centre",
        "name": "Example Leisure Centre",
        "address": {
          "type": "PostalAddress",
          "streetAddress": "1 High Street",
          "addressLocality": "Bristol",
          "addressRegion": "West England",
          "postalCode": "BS1 4SD",
          "addressCountry": "GB"
        },
        "telephone": "08448 933888",
        "geo": {
          "type": "GeoCoordinates",
          "latitude": 51.5282923438685,
          "longitude": -0.206177163090501
        }
      },
      "url": "https://www.example.com/booking/deep/link",
      "image": [
        {
          "type": "ImageObject",
          "url": "http://example.org/images/1.jpg"
        }
      ],
      "sportsActivityLocation": [
        {
          "type": "SportsActivityLocation",
          "name": "Main Tennis Court 1",
          "containedInPlace": "http://www.example.org/api/locations/8958f9b8-2004-4e90-80ff-50c98a9b121d"
        },
        {
          "type": "SportsActivityLocation",
          "name": "Main Tennis Court 2",
          "containedInPlace": "http://www.example.org/api/locations/8958f9b8-2004-4e90-80ff-50c98a9b121d"
        }
      ],
      "offers": [
        {
          "type": "Offer",
          "name": "30 minute hire",
          "price": 10,
          "priceCurrency": "GBP"
        }
      ],
      "event": [
        {
          "type": "Slot",
          "id": "https://example.com/api/facility-uses/1#/event/2018-03-01T10:00:00Z",
          "facilityUse": "https://example.com/api/facility-uses/1",
          "startDate": "2018-03-01T10:00:00Z",
          "duration": "PT30M",
          "remainingUses": 0,
          "maximumUses": 4
        },
        {
          "type": "Slot",
          "id": "https://example.com/api/facility-uses/1#/event/2018-03-01T10:00:00Z",
          "facilityUse": "https://example.com/api/facility-uses/1",
          "startDate": "2018-03-01T11:00:00Z",
          "duration": "PT30M",
          "remainingUses": 3,
          "maximumUses": 4,
          "offers": [
            {
              "type": "Offer",
              "name": "30 minute hire",
              "price": 15,
              "priceCurrency": "GBP",
            }
          ],
          "potentialAction": [ /* this facilitates searching for a specific court */
            {
              "type": "SearchAction",
              "name": "SelectSlot",
              "target": "https://example.com/api/facility-uses/1/individualFacilityUses?event.startDate=2018-03-01T10:00:00Z"
            }
          ]
        }
      ],
      "potentialAction": [ /* this will book a random available court at the specified slot time */
        {
          "type": "ReserveAction",
          "name": "Book",
          "target": {
            "type": "EntryPoint",
            "url": "https://example.com/api/orders",
            "encodingType": "application/vnd.openactive.v0.5+json",
            "httpMethod": "POST"
          }
        },
        {
          "type": "SearchAction",
          "name": "IndividualSlotCalendar",
          "target": "https://example.com/api/facility-uses/1/individualFacilityUses?event.startDate[gte]={dateFrom}&event.startDate[lte]={dateTo}",
          "dateFrom-input": {
            "type": "PropertyValueSpecification",
            "valueRequired": false,
            "multipleValues": false,
            "valueName": "dateFrom",
            "name": "From Date"
          },
          "dateTo-input": {
            "type": "PropertyValueSpecification",
            "valueRequired": false,
            "multipleValues": false,
            "valueName": "dateTo",
            "name": "To Date"
          }
        }
      ]
    }
  ]
}

https://example.com/api/facility-uses/{id}/individual-facility-uses

GET https://example.com/api/facility-uses/432/individual-facility-uses?event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1

list of individualFacilityUses (specific tennis courts), each of which contains slots with startDate as selected, which contain bookable offers

{
  "@context": "https://www.openactive.io/ns/oa.jsonld",
  "id": "https://example.com/api/facility-uses/432/individual-facility-uses?event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1",
  "type": "Collection",
  "totalItems": 4980,
  "view": {
    "id": "https://example.com/api/facility-uses/432/individual-facility-uses?event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1&page=1",
    "type": "PartialCollectionView",
    "first": "https://example.com/api/facility-uses/432/individual-facility-uses?event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1&page=1",
    "previous": "https://example.com/api/facility-use/432/individual-facility-uses?event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1&page=2",
    "next": "https://example.com/api/facility-uses/432/individual-facility-uses?event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1&page=4",
    "last": "https://example.com/api/facility-uses/432/individual-facility-uses?event.startDate[gte]=2018-07-20T11:00:00Z&event.startDate[lte]=2018-07-27T11:00:00Z&event.remainingUses[gte]=1&page=498"
  },
  "item": [
    {
      "type": "IndividualFacilityUse",
      "id": "http://www.example.org/api/facility-uses/432/individual-facility-uses/2593",
      "facilityUse": "http://www.example.org/api/facility-uses/432",
      "name": "Main Tennis Court",
      "description": "The main tennis court is outdoor, overlooking the nearby park",
      "image": [
        {
          "type": "ImageObject",
          "url": "http://example.org/images/1.jpg"
        }
      ],
      "activity": [
        {
          "id": "http://openactive.io/activity-list/#f2ea7405-6098-4378-b0fe-4e398a659fc4",
          "inScheme": "https://www.openactive.io/activity-list/activity-list.jsonld",
          "prefLabel": "Tennis",
          "type": "Concept"
        }
      ],
      "location":
        "type": "SportsActivityLocation",
        "name": "Main Tennis Court",
        "containedInPlace": {
           "type": "Place",
           "id": "http://www.example.org/api/locations/8958f9b8-2004-4e90-80ff-50c98a9b121d",
           "name": "Example Leisure Centre",
           "address": {
             "type": "PostalAddress",
             "streetAddress": "1 High Street",
             "addressLocality": "Bristol",
             "addressRegion": "West England",
             "postalCode": "BS1 4SD",
             "addressCountry": "GB"
           },
           "telephone": "020 8960 9629",
           "geo": {
             "type": "GeoCoordinates",
             "latitude": 51.5282923438685,
             "longitude": -0.206177163090501
           }
        }
      },
      "url": "https://www.example.com/booking/deep/link",
      "event": [
        {
          "type": "Slot",   
          "id": "http://www.example.org/api/facility-uses/432/individual-facility-uses/2593#/event/2018-03-01T10:00:00Z-1",
          "facilityUse": "http://www.example.org/api/facility-use/1",
          "startDate": "2018-03-01T10:00:00Z",   
          "duration": "PT30M",   
          "remainingUses": 1,
          "maximumUses": 1,
          "offers": [
            {
              "type": "Offer",
              "name": "30 minute hire",
              "price": 15,
              "priceCurrency": "GBP",
            }
          ]
        },
        {
          "type": "Slot",   
          "id": "http://www.example.org/api/facility-uses/432/individual-facility-uses/2593#/event/2018-03-01T10:00:00Z-2",
          "facilityUse": "http://www.example.org/api/facility-use/1",
          "startDate": "2018-03-01T11:00:00Z",   
          "duration": "PT30M",   
          "remainingUses": 0,
          "maximumUses": 1
        }
      ],
      "potentialAction": [ /* this will book a specific court */
        {
          "type": "ReserveAction",
          "name": "Book",
          "target": {
            "type": "EntryPoint",
            "url": "https://example.com/orders",
            "encodingType": "application/vnd.openactive.v0.5+json",
            "httpMethod": "POST"
          }
        }
      ]
    }
  ]
}

RPDE open data feeds for facilities

In order to support making the above data available as open data, the following RPDE feeds are required:

  • http://www.example.org/feeds/facility-uses
  • http://www.example.org/feeds/facility-uses/events
  • http://www.example.org/feeds/individual-facility-uses
  • http://www.example.org/feeds/individual-facility-uses/events

Note these feeds separate the infrequently-changing facilityUse and individualFacilityUse objects, from the frequently changing slot objects.

Also note that items from these feeds can be presented as a single feed, if possible based on the underlying implementation.

http://www.example.org/feeds/facility-uses

{
  "next": "http://www.example.org/feeds/facility-uses?afterChangeNumber=44254329",
  "items": [
    {
      "state": "updated",
      "kind": "facility-uses",
      "id": "009SQUASH2018-07-17T06:20:00Z",
      "modified": 44234351,
      "data": {
        "@context": "https://www.openactive.io/ns/oa.jsonld",
        "type": "FacilityUse",
        "id": "http://www.example.org/facility-uses/1",
        "name": "Example Leisure Centre Outdoor Tennis",
        "description": "Table courts are available to hire for thirty minute slots",
        "activity": [
          {
            "id": "http://openactive.io/activity-list/#f2ea7405-6098-4378-b0fe-4e398a659fc4",
            "inScheme": "https://www.openactive.io/activity-list/activity-list.jsonld",
            "prefLabel": "Tennis",
            "type": "Concept"
          }
        ],
        "location": {
          "type": "Place",
          "id": "http://www.example.org/api/locations/8958f9b8-2004-4e90-80ff-50c98a9b121d",
          "url": "https://www.everyoneactive.com/centres/The-Castle-Centre",
          "name": "Example Leisure Centre",
          "address": {
            "type": "PostalAddress",
            "streetAddress": "1 High Street",
            "addressLocality": "Bristol",
            "addressRegion": "West England",
            "postalCode": "BS1 4SD",
            "addressCountry": "GB"
          },
          "telephone": "08448 933888",
          "geo": {
            "type": "GeoCoordinates",
            "latitude": 51.5282923438685,
            "longitude": -0.206177163090501
          }
        },
        "url": "https://www.example.com/booking/deep/link",
        "image": [
          {
            "type": "ImageObject",
            "url": "http://example.org/images/1.jpg"
          }
        ],
        "sportsActivityLocation": [
          {
            "type": "SportsActivityLocation",
            "name": "Main Tennis Court 1",
            "containedInPlace": "http://www.example.org/api/locations/8958f9b8-2004-4e90-80ff-50c98a9b121d"
          },
          {
            "type": "SportsActivityLocation",
            "name": "Main Tennis Court 2",
            "containedInPlace": "http://www.example.org/api/locations/8958f9b8-2004-4e90-80ff-50c98a9b121d"
          }
        ],
        "offers": [
          {
            "type": "Offer",
            "name": "30 minute hire",
            "price": 10,
            "priceCurrency": "GBP"
          }
        ],
        "potentialAction": [ /* this will book a random available court at the specified slot time */
          {
            "type": "ReserveAction",
            "name": "Book",
            "target": {
              "type": "EntryPoint",
              "url": "https://example.com/orders",
              "encodingType": "application/vnd.openactive.v0.5+json",
              "httpMethod": "POST"
            }
          },
          {
            "type": "SearchAction",
            "name": "IndividualSlotCalendar",
            "target": "https://example.com/api/facility-uses/1/individualFacilityUses?event.startDate[gte]={dateFrom}&event.startDate[lte]={dateTo}",
            "dateFrom-input": {
              "type": "PropertyValueSpecification",
              "valueRequired": false,
              "multipleValues": false,
              "valueName": "dateFrom",
              "name": "From Date"
            },
            "dateTo-input": {
              "type": "PropertyValueSpecification",
              "valueRequired": false,
              "multipleValues": false,
              "valueName": "dateTo",
              "name": "To Date"
            }
          }
        ]
      }
    }
  ],
  "license": "https://creativecommons.org/licenses/by/4.0/"
}

http://www.example.org/feeds/facility-uses/events

{
  "next": "http://www.example.org/feeds/facility-uses/events?afterChangeNumber=44254329",
  "items": [
    {
      "state": "updated",
      "kind": "facility-uses/events",
      "id": "009/2018-03-01T10:00:00Z",
      "modified": 44234351,
      "data": {
        "@context": "https://www.openactive.io/ns/oa.jsonld",
        "type": "Slot",   
        "id": "http://www.example.org/api/facility-uses/432#/event/2018-03-01T10:00:00Z",
        "facilityUse": "http://www.example.org/api/facility-use/1",
        "startDate": "2018-03-01T11:00:00Z",   
        "duration": "PT30M",   
        "remainingUses": 3,
        "maximumUses": 6
      }
    }
  ],
  "license": "https://creativecommons.org/licenses/by/4.0/"
}

http://www.example.org/feeds/individual-facility-uses

{
  "next": "http://www.example.org/feeds/individual-facility-uses?afterChangeNumber=44254329",
  "items": [
    {
      "state": "updated",
      "kind": "facility-uses",
      "id": "009SQUASH2018-07-17T06:20:00Z",
      "modified": 44234351,
      "data": {
        "@context": "https://www.openactive.io/ns/oa.jsonld",
        "type": "IndividualFacilityUse",
        "id": "http://www.example.org/api/facility-uses/432/individual-facility-uses/2593",
        "facilityUse": "http://www.example.org/api/facility-uses/432",
        "name": "Main Tennis Court",
        "description": "The main tennis court is outdoor, overlooking the nearby park",
        "image": [
          {
            "type": "ImageObject",
            "url": "http://example.org/images/1.jpg"
          }
        ],
        "activity": [
          {
            "id": "http://openactive.io/activity-list/#f2ea7405-6098-4378-b0fe-4e398a659fc4",
            "inScheme": "https://www.openactive.io/activity-list/activity-list.jsonld",
            "prefLabel": "Tennis",
            "type": "Concept"
          }
        ],
        "location": {
          "type": "SportsActivityLocation",
          "name": "Main Tennis Court",
          "containedInPlace": {
             "type": "Place",
             "id": "http://www.example.org/api/locations/8958f9b8-2004-4e90-80ff-50c98a9b121d",
             "name": "Example Leisure Centre",
             "address": {
               "type": "PostalAddress",
               "streetAddress": "1 High Street",
               "addressLocality": "Bristol",
               "addressRegion": "West England",
               "postalCode": "BS1 4SD",
               "addressCountry": "GB" 
             },
             "telephone": "020 8960 9629",
             "geo": {
               "type": "GeoCoordinates",
               "latitude": 51.5282923438685,
               "longitude": -0.206177163090501
             }
          }
        },
        "url": "https://www.example.com/booking/deep/link",
        "potentialAction": [ /* this will book a specific court */
          {
            "type": "ReserveAction",
            "name": "Book",
            "target": {
              "type": "EntryPoint",
              "url": "https://example.com/api/orders",
              "encodingType": "application/vnd.openactive.v0.5+json",
              "httpMethod": "POST"
            }
          }
        ]
      }
    }
  ],
  "license": "https://creativecommons.org/licenses/by/4.0/"
}

http://www.example.org/feeds/individual-facility-uses/events

{
  "next": "http://www.example.org/feeds/individual-facility-uses/events?afterChangeNumber=44254329",
  "items": [
    {
      "state": "updated",
      "kind": "individual-facility-uses/events",
      "id": "009SQUASH2018-07-17T06:20:00Z",
      "modified": 44234351,
      "data": {
        "@context": "https://www.openactive.io/ns/oa.jsonld",
        "type": "Slot",   
        "id": "http://www.example.org/api/facility-uses/432/individual-facility-uses/2593#/event/2018-03-01T10:00:00Z-2",
        "facilityUse": "http://www.example.org/api/facility-use/432/individual-facility-uses/2593",
        "startDate": "2018-03-01T11:00:00Z",   
        "duration": "PT30M",   
        "remainingUses": 0,
        "maximumUses": 1
      }
    }
  ],
  "license": "https://creativecommons.org/licenses/by/4.0/"
}
@loalf
Copy link

loalf commented Aug 9, 2018

Hi @nickevansuk thank you for taking the time to write down this example. I'm struggling to understand how we should use the information contained in the potentialActions section (from a consumer point of view). For example:

 "potentialAction": [ /* this will book a specific court */
          {
            "type": "ReserveAction",
            "name": "Book",
            "target": {
              "type": "EntryPoint",
              "url": "https://example.com/api/orders",
              "encodingType": "application/vnd.openactive.v0.5+json",
              "httpMethod": "POST"
            }
          }

I reckon I should send a POST requesto to this URL but I have no idea what the payload should look like.

On a different note, type ("ReserveAction") and name ("Book") could be anything or is there a list of possible values for these two fields?

Thanks!

@nickevansuk
Copy link
Contributor Author

Hi @loalf the detail of how to use the ReserveAction can be found in the Open Booking API spec. Payload details included.

The types are defined by schema.org (see bottom of this page https://schema.org/Action for the top of the tree, and note that there are subclasses inside each too). Names are not currently defined.

Does that help? Also for context which organisation are you from?

@loalf
Copy link

loalf commented Aug 9, 2018

Thanks @nickevansuk , yes, that helps.

I'm working with MyLocalPitch, I reckon we met a few weeks ago in one the monthly meetings.

@house92
Copy link

house92 commented Oct 9, 2018

@nickevansuk The validator currently doesn't like the suggested FacilityUse object, so some adjustments need to be made to one or both. One thing that has come up is that the validator expects potentialAction to only include objects with type of "Action". Seeing as https://schema.org/Action allows an additionalType field for more specific types, could we leverage that for "SearchAction" and the like?

@lukehesluke
Copy link

@nickevansuk in the validator (e.g. https://validator.openactive.io/?url=https%3A%2F%2Fwww.openactive.io%2Fdata-models%2Fversions%2F2.x%2Fexamples%2Fslot_example_1.json&version=2.0), there are samples of Facility data. In these examples, the kind is FacilityUse and FacilityUse.Slot

In the examples you've given in this proposal, the kinds are facility-uses and facility-uses/events

Is there a place where kind is being discussed that I can look to for the most up-to-date thoughts?

@nickevansuk nickevansuk transferred this issue from openactive/implementation-tracker Feb 13, 2023
@nickevansuk
Copy link
Contributor Author

Moved to https://github.com/openactive/modelling-opportunity-data for historical value

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants