How to use the Amadeus API

Recently a Wappler user was trying to use the Amadeus API for their job and asked a few questions, here is a full guide on how I use the Amadeus API for anyone else in the travel / bookings sector that wants a small head start.

Go to https://developers.amadeus.com/ and register as a user, email activate your account, login and navigate to My Self-Service Workspace where you can very simply “Create new app”, the options here are super simple to figure out.
Once your App is created you will be given a API Key and API Secret that you can use in their sandbox environment while you develop the application using the sandbox URL test.api.amadeus.com

From the Amadeus side that is all you really need besides their documentation for what parameters and endpoints you will need to use to make calls to their interface.

In Wappler create a new Server Action, I called mine amadeus-api and place a new API Action inside it, I called mine api1Auth


Use your own API Key for the client_id and your API Secret for the client_secret
Once setup click Define Schema, one of the parts we will use in our next step is the returned access_token.

Now that Auth is done, create a second API Action in the same server action, i called mine api1Query


Make sure to add the Authorization header with a value of Bearer {{api1Auth.data.access_token}} however if you have altered names of any of your server actions please make sure to adjust accordingly.
Adjust your Url to whatever you require from the documentation reference on Amadeus.

Once setup, click Define Schema which brings in most of the schema correctly.
I have sent George a PM on this as the schema is not being served back perfectly, so by the time you do this the schema returned could in fact be perfect.

You are now done on the server connect side and can save and move onto displaying the data returned on your page.

Because the api has multiple arrays inside various parts, and because the schema is not served back perfectly in Wappler as yet I have already gone through the task of adding repeats in the correct places and accessing all the returned data in the right sort of places.

The trick to this was getting the Airline Carrier codes returned inside their various arrays to also show their real life definitions, example
Carrier Code: DL - Definition: DELTA AIR LINES

The API returns a separate array of dictionaries which defines various properties such as carrier codes, currencies, aircraft, and locations.
To use these dictionary definitions inside your returned data inside their repeats I used the getValueOrKey data formatter built into Wappler, example
Carrier Code: {{carrierCode}} which would return say DL, I use the returned DL as the key in the dictionary like this
{{sc_amadeus_api.data.api1Query.data.dictionaries.carriers.getValueOrKey(carrierCode)}} which then returns the definition of DELTA AIR LINES

Because the schema is a little off I will give you my base code sample which calls all the parameters returned from the api1Query url I used above, this should assist you on your way.

<!doctype html>
<html>

<head>
	<script src="/dmxAppConnect/dmxAppConnect.js"></script>
	<meta charset="UTF-8">
	<title>Untitled Document</title>
	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous" />
	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous" />
	<script src="/dmxAppConnect/dmxFormatter/dmxFormatter.js" defer=""></script>
</head>

<body is="dmx-app" id="test_amadeus">
	<dmx-serverconnect id="sc_amadeus_api" url="/dmxConnect/api/amadeus-api.php"></dmx-serverconnect>

	<div class="container">
		<div class="row">
			<div class="col">
				<div id="repeatAmadeus" is="dmx-repeat" dmx-bind:repeat="sc_amadeus_api.data.api1Query.data.data">
					<p class="m-0 p-0">
						<b>General Section:</b><br />
						type: {{type}}<br />
						id: {{id}}<br />
						Source: {{source}}<br />
						Instant Ticketing Required: {{instantTicketingRequired}}<br />
						Non Homogeneous: {{nonHomogeneous}}<br />
						One Way: {{oneWay}}<br />
						Last Ticketing Date: {{lastTicketingDate}}<br />
						Number Of Bookable Seats: {{numberOfBookableSeats}}<br />

						<b>Itineraries Section:</b><br />
						<div id="repeatItineraries" is="dmx-repeat" dmx-bind:repeat="itineraries" class="m-0 p-0">
							Duration: {{duration}}<br />
							<div id="repeatItinerariesSegments" is="dmx-repeat" dmx-bind:repeat="segments" class="m-0 p-0">
								Departure IATA Code: {{departure.iataCode}} - {{sc_amadeus_api.data.api1Query.data.dictionaries.locations.getValueOrKey(departure.iataCode).countryCode}}<br />
								Departure Terminal: {{departure.terminal}}<br />
								Departure AT: {{departure.at}}<br />
								Arrival IATA Code: {{arrival.iataCode}} - {{sc_amadeus_api.data.api1Query.data.dictionaries.locations.getValueOrKey(arrival.iataCode).countryCode}}<br />
								Arrival Terminal: {{arrival.terminal}}<br />
								Arrival AT: {{arrival.at}}<br />
								Carrier Code: {{carrierCode}} - {{sc_amadeus_api.data.api1Query.data.dictionaries.carriers.getValueOrKey(carrierCode)}}<br />
								Number: {{number}}<br />
								Aircraft Code: {{aircraft.code}} - {{sc_amadeus_api.data.api1Query.data.dictionaries.aircraft.getValueOrKey(aircraft.code)}}<br />
								Operating Carrier Code: {{operating.carrierCode}} - {{sc_amadeus_api.data.api1Query.data.dictionaries.carriers.getValueOrKey(operating.carrierCode)}}<br />
								Duration: {{duration}}<br />
								ID: {{id}}<br />
								Number Of Stops: {{numberOfStops}}<br />
								Blacklisted In EU: {{blacklistedInEU}}<br />
							</div>
						</div>

						<b>Price Section:</b><br />
						Currency: {{price.currency}} - {{sc_amadeus_api.data.api1Query.data.dictionaries.currencies.getValueOrKey(price.currency)}}<br />
						Total: {{price.total}}<br />
						Base: {{price.base}}
						<div id="repeatPriceFees" is="dmx-repeat" dmx-bind:repeat="price.fees" class="m-0 p-0">
							<b>Fees:</b><br />
							Amount: {{amount}}<br />
							Type: {{type}}<br />
						</div>
						Grand Total: {{price.grandTotal}}<br />

						<b>Pricing Options:</b><br />
						<div id="repeatPricingOptionsFareType" is="dmx-repeat" dmx-bind:repeat="pricingOptions.fareType" class="m-0 p-0">
							Fare Type: {{$value}}<br />
						</div>
						Included Checked Bags Only: {{pricingOptions.includedCheckedBagsOnly}}<br />

						<div id="repeatValidatingAirlineCodes" is="dmx-repeat" dmx-bind:repeat="validatingAirlineCodes" class="m-0 p-0">
							Validating Airline Codes: {{$value}}<br />
						</div>

						<div id="repeatTravelerPricings" is="dmx-repeat" dmx-bind:repeat="travelerPricings" class="m-0 p-0">
							<b>Traveler Pricings Section</b><br />
							Traveler ID: {{travelerId}}<br />
							Fare Option: {{fareOption}}<br />
							Traveler Type: {{travelerType}}<br />
							Currency: {{price.currency}}<br />
							Total: {{price.total}}<br />
							Base: {{price.base}}<br />
							<div id="repeatFareDetailsBySegment" is="dmx-repeat" dmx-bind:repeat="fareDetailsBySegment" class="m-0 p-0">
								Segment ID: {{segmentId}}<br />
								Cabin: {{cabin}}<br />
								Fare Basis: {{fareBasis}}<br />
								Class: {{class}}<br />
								Included Checked Bags: Quantity: {{includedCheckedBags.quantity}}<br />
							</div>
						</div>
					</p>
				</div>
			</div>
		</div>
	</div>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</body>

</html>

Please make sure to save and publish the code, also make sure your Wappler publishes the dmxFormatter.js if your project had not already used it or things will not work correctly. If not close the document after save and re-open it which should add the required components to your server on next publish.

Happy Wapplering.

4 Likes

An extension to this tutorial for people that would like to use a full city name instead on the 3 letter IATA code of the airport.

Using the same Server Action where you already have your api1Auth and api1Query step, add a repeat step named repeatIATAcode with an expression of {{api1Query.data.dictionaries.locations}}

We are going to repeat through all the locations returned from api1Query in the dictionary, so possibly only 5 records or so.

Inside the repeat step add another API Action called api1QueryCity
URL: https://test.api.amadeus.com/v1/reference-data/locations/A{{$key}}
Headers: Name: Authorization Value: Bearer {{api1Auth.data.access_token}}

Here is the final Server Action File

In your client side we need to add one more repeat with a where clause that will only return the city name where the IATA code matches each other.
This is the single line of code added inside the repeatItinerariesSegments

Departure City Name: <span dmx-repeat:repeat1="sc_amadeus_api.data.repeatIATAcode.where(`api1QueryCity.data.data.iataCode`, departure.iataCode, &quot;==&quot;)">{{api1QueryCity.data.data.address.cityName}}</span><br />

Some oddities to the above code is that the where clause only works exactly as i have given it, one parameter needs backticks and the second can not have backticks or it no longer works, maybe @patrick or @George could explain why as it took some time to figure that one out.

Here is a replacement of the full code sample above with the addition of this code.

<!doctype html>
<html>

<head>
	<script src="/dmxAppConnect/dmxAppConnect.js"></script>
	<meta charset="UTF-8">
	<title>Untitled Document</title>
	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous" />
	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous" />
	<script src="/dmxAppConnect/dmxFormatter/dmxFormatter.js" defer=""></script>
</head>

<body is="dmx-app" id="test_amadeus">
	<dmx-serverconnect id="sc_amadeus_api" url="/dmxConnect/api/amadeus-api.php"></dmx-serverconnect>

	<div class="container">
		<div class="row">
			<div class="col">
				<div id="repeatAmadeus" is="dmx-repeat" dmx-bind:repeat="sc_amadeus_api.data.api1Query.data.data">
					<p class="m-0 p-0">
						<b>General Section:</b><br />
						type: {{type}}<br />
						id: {{id}}<br />
						Source: {{source}}<br />
						Instant Ticketing Required: {{instantTicketingRequired}}<br />
						Non Homogeneous: {{nonHomogeneous}}<br />
						One Way: {{oneWay}}<br />
						Last Ticketing Date: {{lastTicketingDate}}<br />
						Number Of Bookable Seats: {{numberOfBookableSeats}}<br />

						<b>Itineraries Section:</b><br />
						<div id="repeatItineraries" is="dmx-repeat" dmx-bind:repeat="itineraries" class="m-0 p-0">
							Duration: {{duration}} - {{duration.replace("PT", "").replace("H", " Hours, ").replace("M", " Minutes")}}<br />
							<div id="repeatItinerariesSegments" is="dmx-repeat" dmx-bind:repeat="segments" class="m-0 p-0">
								Departure IATA Code: {{departure.iataCode}} - {{sc_amadeus_api.data.api1Query.data.dictionaries.locations.getValueOrKey(departure.iataCode).countryCode}}<br />
								Departure City Name: <span dmx-repeat:repeat1="sc_amadeus_api.data.repeatIATAcode.where(`api1QueryCity.data.data.iataCode`, departure.iataCode, &quot;==&quot;)">{{api1QueryCity.data.data.address.cityName}}</span><br />
								Departure Terminal: {{departure.terminal}}<br />
								Departure AT: {{departure.at}}<br />
								Arrival IATA Code: {{arrival.iataCode}} - {{sc_amadeus_api.data.api1Query.data.dictionaries.locations.getValueOrKey(arrival.iataCode).countryCode}}<br />
								Arrival City Name: <span dmx-repeat:repeat2="sc_amadeus_api.data.repeatIATAcode.where(`api1QueryCity.data.data.iataCode`, arrival.iataCode, &quot;==&quot;)">{{api1QueryCity.data.data.address.cityName}}</span><br />
								Arrival Terminal: {{arrival.terminal}}<br />
								Arrival AT: {{arrival.at}}<br />
								Carrier Code: {{carrierCode}} - {{sc_amadeus_api.data.api1Query.data.dictionaries.carriers.getValueOrKey(carrierCode)}}<br />
								Number: {{number}}<br />
								Aircraft Code: {{aircraft.code}} - {{sc_amadeus_api.data.api1Query.data.dictionaries.aircraft.getValueOrKey(aircraft.code)}}<br />
								Operating Carrier Code: {{operating.carrierCode}} - {{sc_amadeus_api.data.api1Query.data.dictionaries.carriers.getValueOrKey(operating.carrierCode)}}<br />
								Duration: {{duration}} - {{duration.replace("PT", "").replace("H", " Hours, ").replace("M", " Minutes")}}<br />
								ID: {{id}}<br />
								Number Of Stops: {{numberOfStops}}<br />
								Blacklisted In EU: {{blacklistedInEU}}
							</div>
						</div>

						<b>Price Section:</b><br />
						Currency: {{price.currency}} - {{sc_amadeus_api.data.api1Query.data.dictionaries.currencies.getValueOrKey(price.currency)}}<br />
						Total: {{price.total}}<br />
						Base: {{price.base}}
						<div id="repeatPriceFees" is="dmx-repeat" dmx-bind:repeat="price.fees" class="m-0 p-0">
							<b>Fees:</b><br />
							Amount: {{amount}}<br />
							Type: {{type}}<br />
						</div>
						Grand Total: {{price.grandTotal}}<br />

						<b>Pricing Options:</b><br />
						<div id="repeatPricingOptionsFareType" is="dmx-repeat" dmx-bind:repeat="pricingOptions.fareType" class="m-0 p-0">
							Fare Type: {{$value}}<br />
						</div>
						Included Checked Bags Only: {{pricingOptions.includedCheckedBagsOnly}}<br />

						<div id="repeatValidatingAirlineCodes" is="dmx-repeat" dmx-bind:repeat="validatingAirlineCodes" class="m-0 p-0">
							Validating Airline Codes: {{$value}}<br />
						</div>

						<div id="repeatTravelerPricings" is="dmx-repeat" dmx-bind:repeat="travelerPricings" class="m-0 p-0">
							<b>Traveler Pricings Section</b><br />
							Traveler ID: {{travelerId}}<br />
							Fare Option: {{fareOption}}<br />
							Traveler Type: {{travelerType}}<br />
							Currency: {{price.currency}}<br />
							Total: {{price.total}}<br />
							Base: {{price.base}}<br />
							<div id="repeatFareDetailsBySegment" is="dmx-repeat" dmx-bind:repeat="fareDetailsBySegment" class="m-0 p-0">
								Segment ID: {{segmentId}}<br />
								Cabin: {{cabin}}<br />
								Fare Basis: {{fareBasis}}<br />
								Class: {{class}}<br />
								Included Checked Bags: Quantity: {{includedCheckedBags.quantity}}<br />
							</div>
						</div>
					</p>
				</div>
			</div>
		</div>
	</div>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</body>

</html>
1 Like