Create a currency converter app with the provided API ? (Interview Question)
#api
Answer
Overview
This is a common Flutter interview question — implement a currency converter app using an exchange rate API. The key is a clean UI with API integration, state management, and error handling.
Prerequisites
yaml# pubspec.yaml dependencies: flutter: sdk: flutter http: ^1.2.0
Complete Currency Converter Implementation
dartimport 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; void main() => runApp(MaterialApp(home: CurrencyConverterScreen())); class CurrencyConverterScreen extends StatefulWidget { _CurrencyConverterScreenState createState() => _CurrencyConverterScreenState(); } class _CurrencyConverterScreenState extends State<CurrencyConverterScreen> { final _amountController = TextEditingController(); String _fromCurrency = 'USD'; String _toCurrency = 'INR'; double? _result; bool _isLoading = false; String? _error; final List<String> _currencies = ['USD', 'EUR', 'GBP', 'INR', 'JPY', 'AUD', 'CAD']; Future<void> _convert() async { final amount = double.tryParse(_amountController.text); if (amount == null) { setState(() => _error = 'Please enter a valid amount'); return; } setState(() { _isLoading = true; _error = null; }); try { // Free API: exchangerate-api.com (replace with your API key) final url = 'https://v6.exchangerate-api.com/v6/YOUR_API_KEY/pair/$_fromCurrency/$_toCurrency/$amount final response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { final data = jsonDecode(response.body); setState(() => _result = data['conversion_result']?.toDouble()); } else { setState(() => _error = 'API error: ${response.statusCode}'); } } catch (e) { setState(() => _error = 'Network error. Check your connection.'); } finally { setState(() => _isLoading = false); } } void dispose() { _amountController.dispose(); super.dispose(); } Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Currency Converter'), centerTitle: true), body: Padding( padding: EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Amount input TextField( controller: _amountController, keyboardType: TextInputType.numberWithOptions(decimal: true), decoration: InputDecoration( labelText: 'Amount', prefixIcon: Icon(Icons.attach_money), border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), ), ), SizedBox(height: 16), // Currency selectors Row( children: [ Expanded( child: DropdownButtonFormField<String>( value: _fromCurrency, decoration: InputDecoration( labelText: 'From', border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), ), items: _currencies.map((c) => DropdownMenuItem(value: c, child: Text(c))).toList(), onChanged: (v) => setState(() => _fromCurrency = v!), ), ), Padding( padding: EdgeInsets.symmetric(horizontal: 8), child: IconButton( icon: Icon(Icons.swap_horiz, size: 32), onPressed: () => setState(() { final temp = _fromCurrency; _fromCurrency = _toCurrency; _toCurrency = temp; }), ), ), Expanded( child: DropdownButtonFormField<String>( value: _toCurrency, decoration: InputDecoration( labelText: 'To', border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), ), items: _currencies.map((c) => DropdownMenuItem(value: c, child: Text(c))).toList(), onChanged: (v) => setState(() => _toCurrency = v!), ), ), ], ), SizedBox(height: 24), // Convert button ElevatedButton( onPressed: _isLoading ? null : _convert, style: ElevatedButton.styleFrom( padding: EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), child: _isLoading ? CircularProgressIndicator(color: Colors.white) : Text('Convert', style: TextStyle(fontSize: 18)), ), SizedBox(height: 24), // Result / Error if (_error != null) Container( padding: EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.red.shade50, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.red.shade200), ), child: Text(_error!, style: TextStyle(color: Colors.red)), ), if (_result != null && _error == null) Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.green.shade50, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.green.shade200), ), child: Column( children: [ Text('Converted Amount', style: TextStyle(color: Colors.grey)), SizedBox(height: 8), Text( '${_result!.toStringAsFixed(2)} $_toCurrency', style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold, color: Colors.green.shade700), ), ], ), ), ], ), ), ); } }
Free APIs for Currency Conversion
| API | Free Tier | URL |
|---|---|---|
| ExchangeRate-API | 1500 req/month | exchangerate-api.com |
| Open Exchange Rates | 1000 req/month | openexchangerates.org |
| Fixer.io | 100 req/month | fixer.io |
| frankfurter.app | Free, no key | frankfurter.app |
dart// Frankfurter (no API key needed!) final url = 'https://api.frankfurter.app/latest?from=$_fromCurrency&to=$_toCurrency&amount=$amount final data = jsonDecode(response.body); final result = data['rates'][_toCurrency];
Interview Tips: Show currency swap button, handle loading/error states, use
properly withtextTextEditingController, and demonstrate API error handling.textdispose()