Was this helpful?
This guide provides developers with the knowledge to create and read from curated lists on the Alpaca Travel Platform. By following this guide, developers can build integrations that manage and access lists of locations on the platform.
This guide is intended to provide developers with a comprehensive understanding of how to use the Alpaca Travel GraphQL API to create and manage lists of places. The guide covers the complete lifecycle of creating and managing lists, including step-by-step instructions for common operations such as creating lists, adding locations, and working with place providers.
The guide covers both GraphQL queries and mutations, providing developers with the complete set of tools to create and manage lists with the Alpaca Travel platform. The guide is intended to be a simple reference that developers can use when they are first getting started with the Alpaca Travel API and are working on their projects, so they can easily understand the different GraphQL operations they need to create a list and manage it.
What this guide does not cover:
Numerous alternative use cases; This is provided to give a developer an overview of calling the GraphQL API but there are numerous other operations and use cases covered outside of this guide.
This guide does not cover how to make API calls or connect your application to the GraphQL API using a specific client. It is technology agnostic and allows developers to use any GraphQL client to make the calls.
It does not cover how to obtain or use an API key to access the Alpaca Travel GraphQL API. Developers must have a valid API key to make calls to the API.
It does not cover implementation details such as handling errors or rate limiting, which are important but are out of scope of this guide.
It does not cover all the possible options and variations of the GraphQL operations, but it covers the most common and useful ones for managing itineraries.
Alpaca Travel GraphQL API Detailed Schema Reference
Apollo Sandbox for testing queries and seeing what other operations/fields are available
In this section, we will go over the steps to create a new itinerary using the Alpaca Travel GraphQL API. We will cover the following topics:
Defining the basic structure of an itinerary
Setting the title and default locale
Adding attributes to the itinerary
Retrieving the created itinerary
An itinerary is the main structure that contains the list of locations that the user wishes to visit. The itinerary can have different types, such as a simple list, a trip, or a trail. To create an itinerary, we need to define the basic structure of the itinerary.
The following GraphQL mutation can be used to create an itinerary:
1mutation CreateItinerary {
2 createItinerary(
3 itinerary: {
4 # Initial content
5 title: "List of Recommended Places"
6 # Some additional recommended but not required fields
7 defaultLocale: "en"
8 attrs: [
9 # Provide hints about the type of itinerary (e.g. list, trip, trail)
10 # Can be omitted or added later
11 { id: "itinerary/type", value: "list" }
12 ]
13 }
14 ) {
15 itinerary {
16 id
17 created
18 }
19 }
20}
Sandbox: Configure | Try Operation
If successful, the expected response will be:
1{
2 "data": {
3 "createItinerary": {
4 "itinerary": {
5 "id": "itinerary/ABC123",
6 "created": "2022-10-15T12:00:00Z"
7 }
8 }
9 }
10}
In this example, the createItinerary
mutation has been successfully executed,
and the server has returned the ID and creation date of the newly created
itinerary. The id
field will be used to reference this itinerary in future
operations, such as adding locations or modifying its attributes. The created
field indicates the date and time when the itinerary was first created.
When creating an itinerary, it is important to provide a title and default locale for the itinerary. The title is a brief summary of the itinerary and it will be used to identify the itinerary for users. The default locale is the language that the itinerary is written in and it will be used as the default language for the itinerary.
1mutation CreateItinerary {
2 createItinerary(
3 itinerary: {
4 title: "List of Recommended Places"
5 defaultLocale: "en"
6 attrs: [
7 # Provide hints about the type of itinerary (e.g. list, trip, trail)
8 # Can be omitted or added later
9 { id: "itinerary/type", value: "list" }
10 ]
11 }
12 ) {
13 itinerary {
14 id
15 created
16 }
17 }
18}
Sandbox: Configure | Try Operation
The above mutation will create an itinerary with the title "List of Recommended Places" and the default locale "en". The response will return the id and created timestamp of the newly created itinerary.
You can also use the updateItinerary mutation operation to update the title and defaultLocale of an existing itinerary.
1mutation UpdateItinerary {
2 updateItinerary(
3 id: "itinerary/ABC123"
4 itinerary: { title: "Liste des lieux recommandés", defaultLocale: "fr" }
5 ) {
6 itinerary {
7 id
8 title
9 defaultLocale
10 }
11 }
12}
Sandbox: Configure | Try Operation
When creating a list, you may want to indicate whether the list is ordered or unordered. An ordered list implies that there is a specific order to the items on the list, while an unordered list implies that the items on the list have no specific order.
To indicate if a list is ordered or unordered, you can use the
itinerary/list-presentation
attribute when creating the list. The attribute
can be set to either "ordered" or "unordered", depending on the desired
presentation of the list.
For example, the following GraphQL mutation sets the
itinerary/list-presentation
attribute to "ordered" when creating a new list:
1mutation CreateOrderedList {
2 createItinerary(
3 itinerary: {
4 title: "My Top 10 Destinations"
5 attrs: [{ id: "itinerary/list-presentation", value: "ordered" }]
6 }
7 ) {
8 itinerary {
9 id
10 }
11 }
12}
Sandbox: Configure | Try Operation
Similarly, the following GraphQL mutation sets the itinerary/list-presentation
attribute to "unordered" when creating a new list:
1mutation CreateUnorderedList {
2 createItinerary(
3 itinerary: {
4 title: "My Favorite Places"
5 attrs: [{ id: "itinerary/list-presentation", value: "unordered" }]
6 }
7 ) {
8 itinerary {
9 id
10 }
11 }
12}
Sandbox: Configure | Try Operation
It is important to note that when creating a list, you should consider whether the order of the items on the list is important or not. If the order is important, such as in a top 10 list where the order may imply significance, you would want to indicate the list as ordered. On the other hand, if the order is not important, such as in a list of bookmarks or suggestions without implying any hierarchy, you would want to indicate the list as unordered.
By indicating whether a list is ordered or unordered, you can ensure that the list is presented in the most appropriate way for your users.
You may also want to store your own identifiers against the list using the
attributes custom/external-ref
and custom/external-source
as well as other
custom data attributes.
This could be useful to store an important identifier that relates to your application.
To retrieve the basic structure of a list, you can use the itinerary
query and
provide the list ID. This will return the list's ID, title, default locale,
created and modified timestamps, as well as the number of items in the list.
1query GetList {
2 itinerary(id: "itinerary/ABC123") {
3 id
4 title
5 defaultLocale
6 created
7 modified
8 type: attrValue(id: "itinerary/type")
9 presentation: attrValue(id: "itinerary/list-presentation")
10 listItems: children(first: 0) {
11 totalCount
12 }
13 }
14}
Sandbox: Configure | Try Operation
Expected Result:
1{
2 "data": {
3 "itinerary": {
4 "id": "itinerary/ABC123",
5 "title": "My Favorite Places",
6 "defaultLocale": "en",
7 "created": "2022-09-18T21:45:13.640Z",
8 "modified": "2022-11-30T11:40:53.103Z",
9 "type": "list",
10 "presentation": "unordered",
11 "listItems": {
12 "totalCount": 0
13 }
14 }
15 }
16}
You can also retrieve the list items by using the children field of the
itinerary query and providing a limit to the number of items to retrieve. The
totalCount
field in the response will indicate the total number of items in
the list, even if not all of them were retrieved in the current query.
Managing the locations within an itinerary is an important aspect of creating an engaging and useful itinerary for your users. The Alpaca Travel API provides a number of GraphQL operations that allow you to easily add, remove, and reorder locations within your itineraries.
In this section, we will cover the following:
Adding a location directly to an itinerary
Adding a location using a place provider
Removing a location from an itinerary
When you want to add a location to your itinerary that does not have an
associated place provider, you can add the location directly to the itinerary.
In this case, you need to provide the title and longitude and latitude of the
location to the createItineraryLocation
mutation.
Here is an example of how you can add a location directly to an itinerary:
1mutation {
2 createItineraryLocation(
3 itineraryId: "itinerary/ABC123"
4 location: {
5 title: "Eiffel Tower"
6 synopsis: "An iconic place of interest"
7 place: { position: { lon: 2.2944, lat: 48.8584 } }
8 }
9 ) {
10 location {
11 id
12 }
13 }
14}
Sandbox: Configure | Try Operation
In the above example, we are adding the location "Eiffel Tower" to the itinerary
with the ID "itinerary/ABC123". The longitude and latitude of the location is
provided in the position
field of the place
object.
If the mutation is successful, the server will return the ID of the newly
created location, as seen in the location
field of the response.
1{
2 "data": {
3 "createItineraryLocation": {
4 "location": {
5 "__typename": "ItineraryLocation",
6 "id": "itinerary/ABC123/location/DEF456"
7 }
8 }
9 }
10}
Various information about the location can be stored against the location.
It is important to note that when adding a location directly, you will not have access to additional information about the location from a place provider. If you want to add a location with more information, you can use a place provider as described in the next subsection.
When adding a location to your itinerary, you have the option to associate the location with a place provider. This allows you to access additional information about the location, such as photos, ratings, contact information, addresses, website and social URL's or other information that is available from the place provider.
Alpaca supports a number of place providers, including OpenStreetMap/WikiData, GeoNames, OpenAddresses, Facebook, and Australian Tourism Data Warehouse. Each provider has their own unique identifier format for a place, so make sure to use the correct format when creating a location.
For example, to add a location to your itinerary and associate it with a place on Facebook, you can use the following mutation:
1mutation CreateItineraryLocationWithFacebookPlace {
2 createItineraryLocation(
3 itineraryId: "itinerary/ABC123"
4 location: {
5 title: "Visit Mavis The Grocer"
6 synopsis: "A great place to grab a breakfast and a coffee"
7 place: {
8 id: "place/facebook:page:mavisthegrocer"
9 position: { lon: 145.0043, lat: -37.8021 }
10 }
11 }
12 ) {
13 location {
14 __typename
15 id
16 }
17 }
18}
Sandbox: Configure | Try Operation
In this example, we are using the Facebook place ID
"place/facebook:page:mavisthegrocer" and providing a fallback position of
lon: 145.0043
, lat: -37.8021
. When querying the itinerary, the position from
the place provider will be used if available.
It's also worth noting that you can leave the place.id field empty, and instead you'll need to supply all the information about the place directly.
Using a place provider can be especially useful when you want to show additional information about the location, such as photos, ratings, or contact information, to your users. It also allows you to easily update the information about the location in case the place provider updates their data.
In addition to linking locations to places provided by external providers, you
may also want to store your own ID's against a location in your itinerary. To do
this, you can use the special custom attributes custom/external-ref
and
custom/external-source
.
The custom/external-ref
attribute accepts a string value, which should be a
unique identifier per record. The custom/external-source
attribute is used to
attribute the identifiers to a source. This attribute should be common across
all your locations and differentiate between different source locations you may
have.
Here's an example of creating an itinerary location with external references:
1mutation CreateItineraryLocationWithExternalReferences {
2 createItineraryLocation(
3 itineraryId: "itinerary/ABC123"
4 location: {
5 title: "Eiffel Tower"
6 place: { position: { lon: 2.2944, lat: 48.8584 } }
7 attrs: [
8 # Use the special custom attributes for linking to your identifiers
9 { id: "custom/external-ref", value: "12345" }
10 { id: "custom/external-source", value: "site" }
11 ]
12 # Other extended fields can be stored against a location
13 websiteUrl: "https://mywebsite.com/places/eiffel-tower"
14 }
15 ) {
16 location {
17 id
18
19 externalRef: attrValue(id: "custom/external-ref")
20 externalSource: attrValue(id: "custom/external-source")
21
22 websiteUrl
23 }
24 }
25}
Sandbox: Configure | Try Operation
With this example, the Alpaca platform will return the external reference ID's that you can then use to map your own place information outside of the Alpaca Travel GraphQL API call.
The Alpaca Data Structure enables a wide range of predefined fields for you to provide and store with your location. You can also store extended data outside of this set.
Once you have added locations to your list, you may want to check if a particular place is already present in the list before adding it again. This can be useful for creating a "Add to List" button with different states, such as "Added" or "Remove" depending on whether the place is already present in the list.
The following GraphQL query can be used to check if a place is present in a list:
1query CheckItineraryPlacePresent {
2 itinerary(id: "itinerary/ABC123") {
3 descendants(placeIds: ["place/123"], first: 1) {
4 nodes {
5 id
6 }
7 totalCount
8 }
9 }
10}
Sandbox: Configure | Try Operation
The itinerary
query is used, supplying the id
of the list to check. The
descendants
field is then queried, providing the placeIds
to check and the
first
parameter, which limits the number of returned results to 1.
In the response, the nodes
field will contain an array of itinerary location
objects, each representing a location in the list that matches the provided
placeIds
. The id
field of each itinerary location object can be used to
refer to the location in future operations. The totalCount
field will indicate
the total number of matching locations in the list, which can be used to check
if the place is already present in the list.
Example response:
1{
2 "data": {
3 "itinerary": {
4 "descendants": {
5 "nodes": [
6 {
7 "id": "itineraryLocation/123"
8 }
9 ],
10 "totalCount": 1
11 }
12 }
13 }
14}
If the place is already present in the list, the totalCount field will be greater than 0.
Once you have added locations to your list, you may want to display the list of
locations to the user. You can use the itinerary
query and the children
selector to list the locations in a list. The query can also be paginated using
the relay "cursor connection" specification.
Here is an example of how to use the itinerary
query to list the locations in
a curated list:
1query QueryItineraryLocationsAsSimpleList {
2 itinerary(id: "itinerary/ABC123") {
3 children(type: ItineraryLocation, first: 10) {
4 edges {
5 node {
6 id
7 __typename
8 ... on ItineraryLocation {
9 title
10 synopsis
11 preferredMedia {
12 resource {
13 ... on MediaImage {
14 url(bestFit: [200, 200])
15 caption
16 copyright
17 altText
18 }
19 }
20 }
21 place {
22 # Use this to draw the list on to a map
23 position {
24 lon
25 lat
26 }
27 # Example drawing basic information from a place provider
28 id
29 name
30 contact {
31 facebookUrl
32 instagramUrl
33 }
34 address {
35 addressLineOne
36 locality
37 }
38 }
39
40 # Othere references you have stored against your list
41 externalRef: attrValue(id: "custom/external-ref")
42 websiteUrl
43 }
44 }
45 position: edgePositionNumber
46 cursor
47 }
48 totalCount
49 }
50 }
51}
Sandbox: Configure | Try Operation
The itinerary
query is used, supplying the id
of the list to display. The
children
field is then queried, providing the type
of the children to return
and the first
parameter, which limits the number of returned results.
In the response, the edges
field will contain an array of itinerary location
objects, each representing a location in the list. Each location will include
information such as the place's ID, name, address, and categories. The
position
field will show the numbering of the result 1...X and the cursor
field will return the cursor to pass back as the "after" property in case you
want to paginate the result.
You can use this query to display the locations in a list on your application, and pass the cursor as the "after" property to retrieve the next set of locations. This will allow you to paginate through the results and display them in chunks to the user.
Note that the place
object contains the position field which is the location
of the place on map with lon and lat which could be used to show the places on a
map.
Once a location has been added to a list, you may want to remove it from the list. In order to remove a location from a list, you can use the "deleteItineraryItem" mutation operation.
This operation requires the id
of the itinerary location you wish to remove.
The id
field of each itinerary location object can be obtained when querying
for the locations in a list or when checking if a place is present in a list.
Here is an example of how to use the "deleteItineraryItem" operation to remove a location from a list:
1mutation DeleteItineraryLocation {
2 deleteItineraryItem(id: "itinerary/ABC123/item/DEF456") {
3 id
4 }
5}
Sandbox: Configure | Try Operation
When the operation is successful, the response will return the id
of the
itinerary location that was removed. Please note that there is no undo option
for this operation and the location will be permanently removed from the list.
Example Successful response:
1{
2 "data": {
3 "deleteItineraryItem": {
4 "id": "itinerary/ABC123/item/DEF456"
5 }
6 }
7}
Please be aware that the operation is irreversible.
After you have added multiple locations to your list, you may want to change the order of those locations. The Alpaca Travel API allows you to reorder the locations within a list by using the "moveItineraryItem" mutation operation.
The moveItineraryItem
mutation takes an id
parameter, which is the ID of the
itinerary location to be moved, and a positionAtStart
, positionAfterSibling
,
positionAtEnd
or positionBeforeSibling
property that specify the location in
the itinerary that the item should be moved to.
To move an itinerary location to the start of the sequence, you can use the following mutation:
1mutation {
2 moveItineraryItem(
3 id: "itinerary/ABC123/location/DEF456"
4 positionAtStart: {}
5 ) {
6 item {
7 id
8 }
9 }
10}
Sandbox: Configure | Try Operation
Alternatively, you can move an itinerary location to a relative position to
another item in the itinerary by using the positionAfterSibling
,
positionAtEnd
or positionBeforeSibling
properties in the mutation.
1mutation {
2 moveItineraryItem(
3 id: "itinerary/ABC123/location/DEF456"
4 positionAfterSibling: { siblingId: "itinerary/ABC123/location/GHI789" }
5 ) {
6 item {
7 id
8 }
9 }
10}
Sandbox: Configure | Try Operation
These mutations allow you to reorder the itinerary locations in a flexible way, whether it be moving them to a specific position or relative to other locations. This can be used to enable drag-and-drop functionality in your application, making it easy for users to rearrange their itinerary as they see fit.
Like other mutations, you can also read back cascaded changes to identify what has been affected by your mutation.
It is also possible to specify the position of the location when you are
initially creating the location. The same position properties are available
using the createItineraryLocation
method.
Your list can have content attached to both the itinerary as well as the individual locations appearing in your list.
Once you have added locations to your list, you may want to update the title of
a location. This can be done using the updateItineraryLocation
mutation. The
mutation takes in the id
of the location you wish to update and the new
title
you want to set.
Title
Synopsis and Descriptions
Tags, Read More URL and Website URLs
Media (Contained in a seperate guide)
Place information and extended Attributes
You can provide this content when you are initially creating the location using
the createItineraryLocation
mutation, or alternatively use the
updateItineraryLocation
mutation to provide or update these values later.
1mutation UpdateItineraryLocationContent {
2 updateItineraryLocation(
3 id: "itinerary/ABC123/location/DEF456"
4 location: {
5 # Various standard fields, see "UpdateItineraryLocationInput" type
6 title: "Eiffel Tower"
7 synopsis: "A short summary for the location"
8 description: "Markdown formatted description for the location"
9 # Extended attributes
10 upsertAttrs: [
11 { id: "place/website-url", value: "https://www.toureiffel.paris" }
12 {
13 id: "place/facebook-url"
14 value: "https://www.facebook.com/EiffelTower.OfficialPage"
15 }
16 ]
17 # You can remove values using the deleteAttrs
18 # example value: [{ id: "place/website-url" }]
19 deleteAttrs: []
20 }
21 ) {
22 location {
23 id
24 # Read back updated values in the response
25 title
26 }
27 }
28}
Sandbox: Configure | Try Operation
The location field contains the new title you want to set for the location.
In the response, the location field will contain the updated location object,
including the id
and updated title
fields.
Example response:
1{
2 "data": {
3 "updateItineraryLocation": {
4 "location": {
5 "id": "itinerary/ABC123/location/DEF456",
6 "title": "New Title"
7 }
8 }
9 }
10}
Please note that you can also update other fields for the location using this mutation.
You may want to also want to store content against the list itself. The itinerary data also supports content similar to the itinerary location. This structure provides numerous standard fields as well as supporting extended attributes to store both custom data as well as other elements such as classifications (such as genre, style, audience, etc).
The below example provides a synopsis and description, as well as an example of updating a classification.
1mutation UpdateItineraryContent {
2 updateItinerary(
3 id: "itinerary/ABC123"
4 itinerary: {
5 # Various standard fields, see "UpdateItineraryInput" type
6 title: "My new title"
7 synopsis: "A short summary of the list"
8 description: "A longer markdown formatted description for the list"
9 # Extended attributes
10 upsertAttrs: [
11 { id: "itinerary/genres", value: ["alpaca:genre:FOOD|CULINARY"] }
12 ]
13 # You can remove values using the deleteAttrs
14 # example value: [{ id: "place/website-url" }]
15 deleteAttrs: []
16 }
17 ) {
18 itinerary {
19 id
20 # Read back any updated values
21 title
22 }
23 }
24}
Sandbox: Configure | Try Operation
Like itinerary location, you are able to assign image media.
After you have created a list, you may want to share the list with others. You may choose to present your own shareable list, but you can also share an interactive map from the Alpaca Travel platform.
For this to work, you will need to have the id
for the itinerary and
substitute the id
value in place of the <ITINERARY_ID>
in the following URL:
1https://made.withalpaca.com/view/<ITINERARY_ID>
The user will be presented with an interactive version of your content by following the URL.
Copyright © 2024 - Made with love ❤️ in Australia.