Search

Building an iOS application with Amadeus APIs

Prerequisites

Before creating your app, you’ll need two things:

Xcode: the IDE required to build and run iOS projects. Download it for free from the Mac App Store.
Amadeus API Key: to get your key, create an account and follow the steps in our Get Started guide.

Installing the Amadeus Swift SDK

Now let’s create the app in Xcode and add the Amadeus Swift SDK. Using an actual iOS device to test your app is ideal, but you can use the iOS simulator if necessary.

First, create a new Single View App project in Xcode and select the following options for your project:

Language: Swift
User Interface: Storyboard
Deselect the checkboxes Use Core DataInclude Unit Tests, and Include UI Tests

Open the Swift Packages Menu by clicking File > Swift Packages > Add Package Dependency.

Amadeus for Developers provides the library for iOS, so you can import the package from GitHub to your project. Using https://github.com/amadeus4dev/amadeus-swift.git as the Package Repository URL, click Next and select Branch: master, then click Finish to add the Amadeus iOS SDK Swift Package.

Open ViewController.swift and import the Amadeus library at the top of your code:

				
					import Amadeus
				
			

Initialize Amadeus with your API Key and API Secret by adding a member variable called amadeus for an instance of the SDK and creating it in the viewDidLoad function of your ViewController class:

				
					class ViewController: UIViewController {
    var amadeus: Amadeus!

    override func viewDidLoad() {
        super.viewDidLoad()

        amadeus = Amadeus(client_id: "YOUR_API_KEY", client_secret: "YOUR_API_SECRET")
    }
				
			

Finally, build the project by pressing Command + B.

Receiving user input

Now, your app needs a UI to receive information from the user to pass into the hotel query. Add three input elements to the UI (city, check-in date, check-out date) as well as a button to start the search.

Inside Main.storyboard, add a Label and Text Field for City, Check-In Date, Check-Out Date, and a Button for Search.

Change the Xcode workspace to show the Editor on the right to see both the storyboard and your View Controller code.

Click on each Text Field and attach references from the storyboard into the View Controller. Do this through the Connections Inspector by clicking and dragging the circle to the right of New Referencing Outlet to any spot inside your ViewController class, then naming them.

Add a tap event reference from your Button to your View Controller by clicking and dragging the circle to the right of Touch Up Inside into your code.

For this tutorial, we’ll use a pre-generated list if city codes, but you can also get a list of searched cities in real-time using the Amadeus Airport & City Search API, as shown below:

				
					amadeus.referenceData.locations.get( data:["subType": "AIRPORT,CITY", 
          "keyword": "r"], onCompletion: { 
    ( result, error ) in 
    if( result != nil ) { 
        for loc in result!.result[ "data" ].arrayValue 
        { 
            print( loc[ "address" ][ "cityName" ].stringValue,  

                   loc[ "iataCode" ].stringValue ) 
        } 
    } 
})
				
			

Here is the pre-generated list of codes:

				
					let cityData:[(name: String, code: String)] = [("Amsterdam, Netherlands", "AMS"), ("Atlanta, USA", "ATL"), ("Bangkok, Thailand", "BKK"), ("Barcelona, Spain", "BCN"), ("Beijing, China", "PEK"), ("Chicago, USA", "ORD"), ("Dallas, USA", "DFW"), ("Delhi, India", "DEL"), ("Denver, USA", "DEN"), ("Dubai, UAE", "DXB"), ("Frankfurt, Germany", "FRA"), ("Guangzhou, China", "CAN"), ("Hong Kong", "HKG"), ("Jakarta, Indonesia", "CGK"), ("Kuala Lumpur, Malaysia", "KUL"), ("Las Vegas, USA", "LAS"), ("London, UK", "LHR"), ("Los Angeles, USA", "LAX"), ("Madrid, Spain", "MAD"), ("Miami, USA", "MIA"), ("Munich, Germany", "MUC"), ("New York, USA", "JFK"), ("Paris, France", "CDG"), ("Seattle, USA", "SEA"), ("Seoul, South Korea", "ICN"), ("Shanghai, China", "PVG"), ("Singapore", "SIN"), ("Sydney, Australia", "SYD"), ("Tokyo, Japan", "HND"), ("Toronto, Canada", "YYZ"), ("San Francisco, USA", "SFO")]
				
			

Add UIPickerView protocols to your View Controller to use for your app’s city selection picker by adding UIPickerViewDelegate and UIPickerViewDataSource to the class and the delegates required. This will save the city code from the picker and pass it into the hotel query:

				
					class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource { 
    ...your code... 

    // Add the following below your current code 
    var cityCode: String = "" 
 
    func numberOfComponents(in pickerView: UIPickerView) -> Int { 
        return 1 
    } 
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
        return cityData.count 
    } 
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 
        cityInput.text = cityData[row].name 
        cityCode = cityData[row].code 
    } 
 
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { 
        return cityData[row].name 
    } 
}
				
			

Next, add event handlers below those functions in your View Controller class to be called when the check-in and check-out dates are selected by the user.

				
					    @objc func setCheckInDate(sender: UIDatePicker) { 
        let formatter = DateFormatter() 
        formatter.dateFormat = "yyyy-MM-dd" 
        checkInDate.text = formatter.string(from: sender.date) 
        checkOutDate.text = formatter.string(from: sender.date.advanced(by: 60*60*24)) // Automatically set the check-out date to the next day (Number of seconds in 1 day) 
    } 
    
    @objc func setCheckOutDate(sender: UIDatePicker) { 
        let formatter = DateFormatter() 
        formatter.dateFormat = "yyyy-MM-dd" 
        checkOutDate.text = formatter.string(from: sender.date) 
    }
				
			

Inside viewDidLoad, create a Picker View for your city list and two Date Pickers for the check-in and check-out dates to be displayed as the inputView when the user taps on those input elements. Set the check-in and check-out dates at load time as well.

Your viewDidLoad should now look something like this:

				
					 override func viewDidLoad() { 
        super.viewDidLoad() 
        // Do any additional setup after loading the view. 
        amadeus = Amadeus(client_id: "YOUR_API_KEY", client_secret: "YOUR_API_SECRET") 
        
        let cityPicker = UIPickerView() 
        cityPicker.delegate = self 
        cityPicker.dataSource = self 
        cityInput.inputView = cityPicker 
        self.pickerView(cityPicker, didSelectRow: 0, inComponent: 0) 
        
        let checkInDatePicker = UIDatePicker() 
        checkInDatePicker.datePickerMode = .date 
        checkInDatePicker.addTarget(self, action: #selector(setCheckInDate), for: .valueChanged) 
        checkInDate.inputView = checkInDatePicker 
        
        let checkOutDatePicker = UIDatePicker() 
        checkOutDatePicker.datePickerMode = .date 
        checkOutDatePicker.addTarget(self, action: #selector(setCheckOutDate), for: .valueChanged) 
        checkOutDate.inputView = checkOutDatePicker 
        
        setCheckInDate(sender: checkInDatePicker) // Set initial date 
    }
				
			

At this point, you should be able to build and run your app to bring up a screen like this:

Calling the API

Now, you’re just one asynchronous function call away from getting hotel deals from the Hotel Search API. We’ll parse the results and store the availability data to be displayed in the next step.

Add an array to keep track of the search results by adding this code inside your View Controller:

				
					var searchResults:[(hotel: String, rating: String, offer: String, price: String)] = []
				
			

Inside your search button event handler, call the function amadeus.shopping.hotelOffers.get with the user input from the previous step, and loop through the results to save them into searchResults like this:

				
					@IBAction func onSearch(_ sender: Any) { 
        self.searchResults.removeAll() 
        amadeus.shopping.hotelOffers.get(data: ["cityCode" : cityCode, 
                                                "checkInDate" : checkInDate.text!, 
                                                "checkOutDate" : checkOutDate.text!]) { ( result, error ) in 
            if( result != nil ) { 
                print( "Found (result!.result[ "data" ].arrayValue.count) Results" ); 
                for hotel in result!.result[ "data" ].arrayValue 
                { 
                    for offer in hotel[ "offers" ].arrayValue 
                    { 
                        self.searchResults.append((hotel: hotel[ "hotel" ][ "name" ].stringValue, rating: hotel[ "hotel" ][ "rating" ].stringValue, offer: offer[ "room" ][ "description" ][ "text" ].stringValue, price: offer[ "price" ][ "total" ].stringValue)) 
                    } 
                } 
            } 
        } 
    }
				
			

When you select a city, add check-in and check-out dates and tap the search button, your app should retrieve hotel results.

Showing the data

You’re almost done! All that’s left is to display the search results in your app by setting up a Table View.

Add a Table View to your storyboard and drop a Table View Cell directly into this new Table View.

Connect an outlet reference to the Table View so you can manage it inside your View Controller.

Select your Table View Cell, open the Attributes Inspector, and set the style to Subtitle and the Identifier to offerCell.

Add UITableView protocols, UITableViewDelegate, and UITableViewDataSource to your View Controller class (like what you did with the Picker View) and use the searchResults array to populate the Table View’s cells. Don’t forget to set the View Controller as the delegate and dataSource.

				
					class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITableViewDelegate,  UITableViewDataSource { 

    var amadeus: Amadeus! 
    @IBOutlet weak var cityInput: UITextField! 
    @IBOutlet weak var checkInDate: UITextField! 
    @IBOutlet weak var checkOutDate: UITextField! 
    @IBOutlet weak var hotelResults: UITableView! 
    
    override func viewDidLoad() { 
        ... 
        hotelResults.delegate = self 
        hotelResults.dataSource = self 
    } 
    
    @IBAction func onSearch(_ sender: Any) { 
        ... 
    } 
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
        return searchResults.count 
    } 
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
        let cell = hotelResults.dequeueReusableCell(withIdentifier: "offerCell", for: indexPath) 
        let offer = searchResults[indexPath.row] 
        cell.textLabel?.text = "(offer.price) - (offer.hotel) ((offer.rating) Star)" 
        cell.detailTextLabel?.text = "(offer.offer)" 
        return cell 
    } 
     
    ...other code... 
}
				
			

Finally, you need to let the app know to reload the Table View data whenever you’ve completed a call to the Amadeus API and finished adding all results into the searchResults array. You can do this with self.hotelResults.reloadData. Because this is a UI update, it must be done on the main thread using DispatchQueue.main.async.

Your search button event handler should now look like this:

				
					   @IBAction func onSearch(_ sender: Any) { 
        self.searchResults.removeAll() 
        amadeus.shopping.hotelOffers.get(data:  
            ["cityCode" : cityCode, 
             "checkInDate" : checkInDate.text!, 
             "checkOutDate" : checkOutDate.text!]) { ( result, error ) in 
            if( result != nil ) { 
                print( "Found (result!.result[ "data" ].arrayValue.count) Results" ); 
                for hotel in result!.result[ "data" ].arrayValue 
                { 
                    for offer in hotel[ "offers" ].arrayValue 
                    { 
                        self.searchResults.append((hotel: hotel[ "hotel" ][ "name" ].stringValue, rating: hotel[ "hotel" ][ "rating" ].stringValue, offer: offer[ "room" ][ "description" ][ "text" ].stringValue, price: offer[ "price" ][ "total" ].stringValue)) 
                    } 
                } 
            } 
            DispatchQueue.main.async { 
                self.hotelResults.reloadData() 
            } 
        } 
    }
				
			

 

And that’s it! You now have an app that can select a city and travel dates and display real-time hotel data.

Conclusion

Using the Amadeus Swift SDK, we quickly put together an iOS mobile app that retrieves and displays live hotel offers based on user input. The Hotel Search API allow many more parameters to narrow, filter, and sort the results than this sample app shows, and includes much more detailed information about amenities and rooms. Of course, the lessons learned in this tutorial can also be applied to all APIs in our Self-Service catalog.

To learn more about what’s available through Amadeus Self-Service APIs and how to use them effectively, check out our Self-Service APIs Documentation, Guides and Code Samples.

If you have any questions, visit our support page or reach out on Stack Overflow.

Good luck and search away for your next hotel stay!

This article was originally published on Amadues’s blog.


If you’re interested in developing expert technical content that performs,
let’s have a conversation today.

Facebook
Twitter
LinkedIn
Reddit
Email

POST INFORMATION

If you work in a tech space and aren’t sure if we cover you, hit the button below to get in touch with us. Tell us a little about your content goals or your project, and we’ll reach back within 2 business days. 

Share via
Copy link
Powered by Social Snap