Xamarin.Forms OpenWeatherMap REST API Kullanımı
İçindekiler
Birçok hava durumu servisi, verilerini geliştiricilere ücretsiz olarak sağlar. Bir hava durumu uygulaması geliştirmek istediğinizde bu servislerden yararlanabilirsiniz. Ancak bunların bazıları ücretliyken bazıları servisler de verileri kısıtlı olarak paylaşıyor. Yaptığım araştırmalara göre ücretsiz olarak faydalanabileceğiniz en iyi hava durumu servisi OpenWeatherMap.
OpenWeatherMap hizmetinin ücretsiz hesabı ile birçok veriye erişebilirsiniz. Örneğin, Current Weather Data koleksiyonu ile verileri JSON, XML ve HTML biçiminde anlık olarak alabilirsiniz. Veya Hourly Forecast 4 Days koleksiyonu ile 4 günlük hava durumu verilerine erişebilirsiniz. Sorgularınız neticesinde istediğiniz bölgenin sıcaklığı, hava durumu, gün doğumu ve gün batımı saatleri gibi birçok veriye ulaşabilirsiniz.
İsterseniz ücretli paketleri de satın alabilirsiniz. Ancak, verileri ticari bir amaçla kullanmayacaksanız, ücretsiz paket fazlasıyla yeterli olacaktır.
Bu yazımda bir Xamarin.Forms projesinde OpenWeatherMap REST API’nin nasıl kullanılacağını adım adım anlatacağım.
OpenWeatherMap API Anahtarınızı Alın
OpenWeatherMap API’sini kullanabilmek için bir API anahtarı gereklidir. Aşağıdaki adımları izleyerek API anahtarınızı alın.
1) Öncelikle, OpenWeatherMap sitesine giriş yapın.

2) Eğer bir hesabınız yoksa, Create an account‘a tıklayarak yeni bir hesap oluşturun.

3) Gerekli bilgileri doldurduktan sonra Create Account düğmesine tıklayın.

4) Bu adımda, bir açılır pencere açılacak. Şirket adını(varsa) ve servisi kullanma amacınızı yazdıktan sonra, Save butonuna tıklayın. Böylece hesabınızın yönetim paneline gideceksiz.

5) Ardından, e-posta ile hesabınızı onaylayın. Artık hesabınız oluşturuldu ve API anahtarını almaya hazırsınız.

6) API anahtarını oluşturmak için yönetim panelindeki API keys‘e tıklayın. Varsayılan olarak, bir API anahtarı zaten oluşturulacaktır. Dilerseniz Create bölümünden yeni bir API anahtarı oluşturabilirsiniz.

API anahtarı alma işlemi bitti. Bu anahtarı API’den veri çekerken kullanacağız.
OpenWeatherMap API’sinden Yanıt Alın
Bu adımda, öncelikle seçtiğiniz API koleksiyonuna hangi sorguyla erişeceğinizi öğrenmelisiniz. Ve ardından bu sorguyu çalıştırarak bir yanıt almalısınız. Ben bu projede OpenWeatherMap hizmetinin One Call API koleksiyonunu kullanacağım. One Call API, dakikalık, saatlik ve günlük verileri JSON formatında sunar. Tek bir koleksiyondan bir çok veriye ulaşabildiğim için One Call API koleksiyonunu seçtim.
Adımları sırayla uygulayın.
1) İlk önce https://openweathermap.org/api adresine gidin. Bu sayfadan API koleksiyonlarının nasıl kullanılacağı ayrıntılı olarak öğrenebilirsiniz.
2) Hesabınızın içeriğine göre istediğiniz koleksiyonu seçtikten sonra, belgelere erişmek için API documentation butonuna tıklayın. Ben bu projede One Call API koleksiyonunu kullanacağım.
3) Burada, How to make an API call bölümünde, API’yi çağırmak için sorgulamanız gereken bağlantı adresini ve parametreleri göreceksiniz. One Call API koleksiyonunu çağırmak aşağıdaki bağlantıyı kullanabilirsiniz.
https://api.openweathermap.org/data/2.5/onecall?lat=41.008240&lon=28.978359&units=metric&appid=YOUR API KEY
URL adresinde lat konumunuzun enlemi, lon boylamı, units verileri almak istediğiniz ölçü birimi, appid ise ve sizin API anahtarınızdır. Verileri almak istediğiniz konumun enlem ve boylamını gerekli yerlere yazın. YOUR API KEY kısmına da yukarıda aldığınız API anahtarını yazın.
Ölçü birimleriyle ilgili daha ayrıntılı bilgilereAPI dökümantasyonundan ulaşabilirsiniz.
4) URL parametrelerini göre girdikten sonra bu URL adresini yeni bir sekmede açın. Alternatif olarak, Postman veya Fiddler gibi API araçlarını kullanabilirsiniz.
Yanıt olarak hava durumu verilerini içeren bir JSON alacaksınız. Aşağıdaki gibi.
{"lat":41.01,"lon":28.98,"timezone":"Europe/Istanbul","timezone_offset":10800,"current":{"dt":1608376276,"sunrise":1608355480,"sunset":1608388678,"temp":9.69,"feels_like":7.23,"pressure":1028,"humidity":76,"dew_point":5.67,"uvi":0.89,"clouds":75,"visibility":10000,"wind_speed":2.1,"wind_deg":340,"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}]},"minutely":[{"dt":1608376320,"precipitation":0},{"dt":1608376380,"precipitation":0},{"dt":1608376440,"precipitation":0},{"dt":1608376500,"precipitation":0},{"dt":1608376560,"precipitation":0},{"dt":1608376620,"precipitation":0},{"dt":1608376680,"precipitation":0},{"dt":1608376740,"precipitation":0},{"dt":1608376800,"precipitation":0},{"dt":1608376860,"precipitation":0},{"dt":1608376920,"precipitation":0},{"dt":1608376980,"precipitation":0},{"dt":1608377040,"precipitation":0},{"dt":1608377100,"precipitation":0},{"dt":1608377160,"precipitation":0},{"dt":1608377220,"precipitation":0},{"dt":1608377280,"precipitation":0},{"dt":1608377340,"precipitation":0},{"dt":1608377400,"precipitation":0},{"dt":1608377460,"precipitation":0},{"dt":1608377520,"precipitation":0},{"dt":1608377580,"precipitation":0},{"dt":1608377640,"precipitation":0},{"dt":1608377700,"precipitation":0},{"dt":1608377760,"precipitation":0},{"dt":1608377820,"precipitation":0},{"dt":1608377880,"precipitation":0},{"dt":1608377940,"precipitation":0},{"dt":1608378000,"precipitation":0},{"dt":1608378060,"precipitation":0},{"dt":1608378120,"precipitation":0},{"dt":1608378180,"precipitation":0},{"dt":1608378240,"precipitation":0},{"dt":1608378300,"precipitation":0},{"dt":1608378360,"precipitation":0},{"dt":1608378420,"precipitation":0},{"dt":1608378480,"precipitation":0},{"dt":1608378540,"precipitation":0},{"dt":1608378600,"precipitation":0},{"dt":1608378660,"precipitation":0},{"dt":1608378720,"precipitation":0},{"dt":1608378780,"precipitation":0},{"dt":1608378840,"precipitation":0},{"dt":1608378900,"precipitation":0},{"dt":1608378960,"precipitation":0},{"dt":1608379020,"precipitation":0},{"dt":1608379080,"precipitation":0},{"dt":1608379140,"precipitation":0},{"dt":1608379200,"precipitation":0},{"dt":1608379260,"precipitation":0},{"dt":1608379320,"precipitation":0},{"dt":1608379380,"precipitation":0},{"dt":1608379440,"precipitation":0},{"dt":1608379500,"precipitation":0},{"dt":1608379560,"precipitation":0},{"dt":1608379620,"precipitation":0},{"dt":1608379680,"precipitation":0},{"dt":1608379740,"precipitation":0},{"dt":1608379800,"precipitation":0},{"dt":1608379860,"precipitation":0},{"dt":1608379920,"precipitation":0}],"hourly":[{"dt":1608375600,"temp":9.69,"feels_like":6.35,"pressure":1028,"humidity":76,"dew_point":5.67,"uvi":0.89,"clouds":75,"visibility":10000,"wind_speed":3.36,"wind_deg":62,"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"pop":0.08},{"dt":1608379200,"temp":10.08,"feels_like":6.22,"pressure":1028,"humidity":71,"dew_point":5.07,"uvi":0.61,"clouds":51,"visibility":10000,"wind_speed":3.92,"wind_deg":58,"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"pop":0.08},{"dt":1608382800,"temp":10.21,"feels_like":5.93,"pressure":1028,"humidity":68,"dew_point":4.57,"uvi":0.45,"clouds":68,"visibility":10000,"wind_speed":4.38,"wind_deg":48,"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"pop":0},{"dt":1608386400,"temp":9.9,"feels_like":5.51,"pressure":1028,"humidity":68,"dew_point":4.28,"uvi":0.12,"clouds":53,"visibility":10000,"wind_speed":4.46,"wind_deg":49,"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"pop":0},{"dt":1608390000,"temp":9.36,"feels_like":4.9,"pressure":1028,"humidity":70,"dew_point":4.17,"uvi":0,"clouds":34,"visibility":10000,"wind_speed":4.53,"wind_deg":49,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03n"}],"pop":0},{"dt":1608393600,"temp":9,"feels_like":4.31,"pressure":1028,"humidity":69,"dew_point":3.81,"uvi":0,"clouds":26,"visibility":10000,"wind_speed":4.71,"wind_deg":46,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03n"}],"pop":0},{"dt":1608397200,"temp":8.8,"feels_like":4.01,"pressure":1028,"humidity":69,"dew_point":3.52,"uvi":0,"clouds":22,"visibility":10000,"wind_speed":4.81,"wind_deg":46,"weather":[{"id":801,"main":"Clouds","description":"few clouds","icon":"02n"}],"pop":0},{"dt":1608400800,"temp":8.65,"feels_like":3.95,"pressure":1028,"humidity":68,"dew_point":3.17,"uvi":0,"clouds":19,"visibility":10000,"wind_speed":4.59,"wind_deg":47,"weather":[{"id":801,"main":"Clouds","description":"few clouds","icon":"02n"}],"pop":0},{"dt":1608404400,"temp":8.53,"feels_like":4.04,"pressure":1028,"humidity":67,"dew_point":2.95,"uvi":0,"clouds":15,"visibility":10000,"wind_speed":4.21,"wind_deg":51,"weather":[{"id":801,"main":"Clouds","description":"few clouds","icon":"02n"}],"pop":0},{"dt":1608408000,"temp":8.37,"feels_like":4.16,"pressure":1028,"humidity":67,"dew_point":2.77,"uvi":0,"clouds":11,"visibility":10000,"wind_speed":3.77,"wind_deg":52,"weather":[{"id":801,"main":"Clouds","description":"few clouds","icon":"02n"}],"pop":0},{"dt":1608411600,"temp":8.2,"feels_like":4.24,"pressure":1028,"humidity":68,"dew_point":2.8,"uvi":0,"clouds":7,"visibility":10000,"wind_speed":3.42,"wind_deg":51,"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}],"pop":0},{"dt":1608415200,"temp":8.03,"feels_like":4.11,"pressure":1028,"humidity":69,"dew_point":2.75,"uvi":0,"clouds":6,"visibility":10000,"wind_speed":3.38,"wind_deg":49,"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}],"pop":0},{"dt":1608418800,"temp":7.84,"feels_like":4.16,"pressure":1028,"humidity":70,"dew_point":2.83,"uvi":0,"clouds":12,"visibility":10000,"wind_speed":3.04,"wind_deg":47,"weather":[{"id":801,"main":"Clouds","description":"few clouds","icon":"02n"}],"pop":0},{"dt":1608422400,"temp":7.73,"feels_like":4.16,"pressure":1028,"humidity":71,"dew_point":2.92,"uvi":0,"clouds":24,"visibility":10000,"wind_speed":2.91,"wind_deg":44,"weather":[{"id":801,"main":"Clouds","description":"few clouds","icon":"02n"}],"pop":0},{"dt":1608426000,"temp":7.64,"feels_like":4.16,"pressure":1028,"humidity":73,"dew_point":3.18,"uvi":0,"clouds":98,"visibility":10000,"wind_speed":2.85,"wind_deg":44,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608429600,"temp":7.54,"feels_like":4.08,"pressure":1028,"humidity":75,"dew_point":3.45,"uvi":0,"clouds":86,"visibility":10000,"wind_speed":2.9,"wind_deg":46,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608433200,"temp":7.45,"feels_like":3.94,"pressure":1027,"humidity":76,"dew_point":3.58,"uvi":0,"clouds":58,"visibility":10000,"wind_speed":2.99,"wind_deg":48,"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04n"}],"pop":0},{"dt":1608436800,"temp":7.4,"feels_like":3.95,"pressure":1027,"humidity":77,"dew_point":3.7,"uvi":0,"clouds":44,"visibility":10000,"wind_speed":2.94,"wind_deg":51,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03n"}],"pop":0},{"dt":1608440400,"temp":7.37,"feels_like":4.05,"pressure":1027,"humidity":78,"dew_point":3.88,"uvi":0,"clouds":36,"visibility":10000,"wind_speed":2.8,"wind_deg":50,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03n"}],"pop":0},{"dt":1608444000,"temp":7.64,"feels_like":4.35,"pressure":1028,"humidity":77,"dew_point":4.05,"uvi":0,"clouds":34,"visibility":10000,"wind_speed":2.78,"wind_deg":51,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"pop":0},{"dt":1608447600,"temp":8.38,"feels_like":4.87,"pressure":1028,"humidity":73,"dew_point":3.96,"uvi":0.16,"clouds":47,"visibility":10000,"wind_speed":3.08,"wind_deg":54,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"pop":0},{"dt":1608451200,"temp":9.11,"feels_like":5.13,"pressure":1028,"humidity":68,"dew_point":3.54,"uvi":0.36,"clouds":49,"visibility":10000,"wind_speed":3.68,"wind_deg":56,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"pop":0},{"dt":1608454800,"temp":9.74,"feels_like":5.54,"pressure":1028,"humidity":64,"dew_point":3.36,"uvi":0.56,"clouds":50,"visibility":10000,"wind_speed":3.92,"wind_deg":58,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"pop":0.04},{"dt":1608458400,"temp":10.23,"feels_like":6.07,"pressure":1027,"humidity":63,"dew_point":3.65,"uvi":0.89,"clouds":50,"visibility":10000,"wind_speed":3.92,"wind_deg":51,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"pop":0.07},{"dt":1608462000,"temp":10.27,"feels_like":6.28,"pressure":1027,"humidity":69,"dew_point":4.9,"uvi":0.82,"clouds":46,"visibility":10000,"wind_speed":4.05,"wind_deg":36,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"pop":0.07},{"dt":1608465600,"temp":9.6,"feels_like":5.65,"pressure":1027,"humidity":80,"dew_point":6.36,"uvi":0.55,"clouds":47,"visibility":10000,"wind_speed":4.43,"wind_deg":28,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"pop":0.04},{"dt":1608469200,"temp":9.8,"feels_like":5.52,"pressure":1027,"humidity":77,"dew_point":6.03,"uvi":0.26,"clouds":100,"visibility":10000,"wind_speed":4.79,"wind_deg":44,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"pop":0},{"dt":1608472800,"temp":9.83,"feels_like":5.41,"pressure":1027,"humidity":77,"dew_point":6.05,"uvi":0.07,"clouds":88,"visibility":10000,"wind_speed":5,"wind_deg":45,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"pop":0.04},{"dt":1608476400,"temp":9.58,"feels_like":5.1,"pressure":1027,"humidity":79,"dew_point":6.23,"uvi":0,"clouds":73,"visibility":10000,"wind_speed":5.13,"wind_deg":48,"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04n"}],"pop":0},{"dt":1608480000,"temp":9.42,"feels_like":4.96,"pressure":1027,"humidity":80,"dew_point":6.33,"uvi":0,"clouds":72,"visibility":10000,"wind_speed":5.11,"wind_deg":52,"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04n"}],"pop":0.08},{"dt":1608483600,"temp":9.5,"feels_like":4.56,"pressure":1028,"humidity":80,"dew_point":6.24,"uvi":0,"clouds":78,"visibility":10000,"wind_speed":5.81,"wind_deg":55,"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04n"}],"pop":0.04},{"dt":1608487200,"temp":9.39,"feels_like":4.22,"pressure":1028,"humidity":79,"dew_point":6.1,"uvi":0,"clouds":82,"visibility":10000,"wind_speed":6.05,"wind_deg":54,"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04n"}],"pop":0.04},{"dt":1608490800,"temp":9.29,"feels_like":3.95,"pressure":1028,"humidity":79,"dew_point":5.88,"uvi":0,"clouds":100,"visibility":10000,"wind_speed":6.27,"wind_deg":53,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608494400,"temp":9.16,"feels_like":3.5,"pressure":1028,"humidity":76,"dew_point":5.28,"uvi":0,"clouds":100,"visibility":10000,"wind_speed":6.53,"wind_deg":53,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608498000,"temp":9.15,"feels_like":3.6,"pressure":1028,"humidity":72,"dew_point":4.55,"uvi":0,"clouds":100,"visibility":10000,"wind_speed":6.15,"wind_deg":53,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608501600,"temp":9.15,"feels_like":3.84,"pressure":1028,"humidity":73,"dew_point":4.57,"uvi":0,"clouds":100,"visibility":10000,"wind_speed":5.86,"wind_deg":53,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608505200,"temp":9.05,"feels_like":4.04,"pressure":1028,"humidity":74,"dew_point":4.73,"uvi":0,"clouds":100,"visibility":10000,"wind_speed":5.46,"wind_deg":53,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608508800,"temp":9.01,"feels_like":4,"pressure":1028,"humidity":74,"dew_point":4.78,"uvi":0,"clouds":100,"visibility":10000,"wind_speed":5.45,"wind_deg":53,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608512400,"temp":8.85,"feels_like":3.76,"pressure":1028,"humidity":74,"dew_point":4.57,"uvi":0,"clouds":100,"visibility":10000,"wind_speed":5.51,"wind_deg":52,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608516000,"temp":8.73,"feels_like":3.51,"pressure":1028,"humidity":72,"dew_point":4.17,"uvi":0,"clouds":100,"visibility":10000,"wind_speed":5.57,"wind_deg":48,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608519600,"temp":8.63,"feels_like":3.49,"pressure":1027,"humidity":72,"dew_point":3.89,"uvi":0,"clouds":100,"visibility":10000,"wind_speed":5.42,"wind_deg":45,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608523200,"temp":8.49,"feels_like":3.58,"pressure":1027,"humidity":74,"dew_point":4.28,"uvi":0,"clouds":100,"visibility":10000,"wind_speed":5.16,"wind_deg":44,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608526800,"temp":8.29,"feels_like":3.32,"pressure":1027,"humidity":77,"dew_point":4.65,"uvi":0,"clouds":100,"visibility":10000,"wind_speed":5.35,"wind_deg":47,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"pop":0},{"dt":1608530400,"temp":8.35,"feels_like":3.33,"pressure":1027,"humidity":76,"dew_point":4.43,"uvi":0,"clouds":99,"visibility":10000,"wind_speed":5.39,"wind_deg":45,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"pop":0},{"dt":1608534000,"temp":8.66,"feels_like":3.55,"pressure":1028,"humidity":73,"dew_point":4.22,"uvi":0.22,"clouds":89,"visibility":10000,"wind_speed":5.44,"wind_deg":45,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"pop":0},{"dt":1608537600,"temp":8.77,"feels_like":3.63,"pressure":1028,"humidity":69,"dew_point":3.47,"uvi":0.49,"clouds":95,"visibility":10000,"wind_speed":5.3,"wind_deg":39,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"pop":0},{"dt":1608541200,"temp":8.84,"feels_like":3.87,"pressure":1028,"humidity":65,"dew_point":2.83,"uvi":0.77,"clouds":97,"visibility":10000,"wind_speed":4.86,"wind_deg":35,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"pop":0},{"dt":1608544800,"temp":8.99,"feels_like":4.31,"pressure":1027,"humidity":63,"dew_point":2.5,"uvi":1.44,"clouds":97,"visibility":10000,"wind_speed":4.37,"wind_deg":31,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"pop":0}],"daily":[{"dt":1608372000,"sunrise":1608355480,"sunset":1608388678,"temp":{"day":10.67,"min":7.91,"max":10.67,"night":8.37,"eve":9,"morn":8.01},"feels_like":{"day":7.49,"night":4.16,"eve":4.31,"morn":5.66},"pressure":1029,"humidity":64,"dew_point":4.21,"wind_speed":2.7,"wind_deg":51,"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}],"clouds":3,"pop":0.24,"uvi":0.98},{"dt":1608458400,"sunrise":1608441912,"sunset":1608475103,"temp":{"day":10.23,"min":7.37,"max":10.27,"night":9.16,"eve":9.42,"morn":7.4},"feels_like":{"day":6.07,"night":3.5,"eve":4.96,"morn":3.95},"pressure":1027,"humidity":63,"dew_point":3.65,"wind_speed":3.92,"wind_deg":51,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"clouds":50,"pop":0.08,"uvi":0.89},{"dt":1608544800,"sunrise":1608528343,"sunset":1608561530,"temp":{"day":8.99,"min":7.65,"max":9.17,"night":7.65,"eve":8.53,"morn":8.49},"feels_like":{"day":4.31,"night":3.63,"eve":3.29,"morn":3.58},"pressure":1027,"humidity":63,"dew_point":2.5,"wind_speed":4.37,"wind_deg":31,"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"clouds":97,"pop":0.35,"rain":0.11,"uvi":1.44},{"dt":1608631200,"sunrise":1608614771,"sunset":1608647959,"temp":{"day":8.46,"min":6.8,"max":8.82,"night":6.8,"eve":7.58,"morn":7.52},"feels_like":{"day":4.56,"night":3.72,"eve":3.53,"morn":2.35},"pressure":1027,"humidity":60,"dew_point":1.36,"wind_speed":2.99,"wind_deg":57,"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"clouds":94,"pop":0.4,"rain":0.47,"uvi":1.1},{"dt":1608717600,"sunrise":1608701198,"sunset":1608734391,"temp":{"day":8.01,"min":5.92,"max":8.87,"night":7.84,"eve":8.23,"morn":5.92},"feels_like":{"day":5.41,"night":5.1,"eve":5.08,"morn":3.44},"pressure":1025,"humidity":62,"dew_point":1.31,"wind_speed":1.13,"wind_deg":199,"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"clouds":70,"pop":0.04,"uvi":1.5},{"dt":1608804000,"sunrise":1608787622,"sunset":1608820824,"temp":{"day":10.1,"min":7.74,"max":10.73,"night":10.53,"eve":10.5,"morn":7.74},"feels_like":{"day":6.28,"night":7.73,"eve":7.42,"morn":4.03},"pressure":1019,"humidity":59,"dew_point":2.64,"wind_speed":3.18,"wind_deg":187,"weather":[{"id":801,"main":"Clouds","description":"few clouds","icon":"02d"}],"clouds":24,"pop":0,"uvi":2},{"dt":1608890400,"sunrise":1608874044,"sunset":1608907260,"temp":{"day":12.69,"min":10.16,"max":14.62,"night":13.99,"eve":14.6,"morn":10.17},"feels_like":{"day":7.95,"night":9.27,"eve":8.77,"morn":6.58},"pressure":1013,"humidity":55,"dew_point":4.05,"wind_speed":4.85,"wind_deg":188,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"clouds":98,"pop":0,"uvi":2},{"dt":1608976800,"sunrise":1608960464,"sunset":1608993697,"temp":{"day":9.72,"min":8.89,"max":13.37,"night":8.89,"eve":9.15,"morn":12.07},"feels_like":{"day":5.69,"night":3.78,"eve":4.54,"morn":10.26},"pressure":1016,"humidity":88,"dew_point":7.88,"wind_speed":5.03,"wind_deg":359,"weather":[{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"}],"clouds":99,"pop":1,"rain":10.18,"uvi":2}]}
JSON’u C#’a Dönüştürün
API’den yaptığınız sorguya yanıt olarak bir JSON döndü. Ancak bir C# sınıfına ihtiyacınız var. Yani bu JSON’u C# sınıfına çevirmelisiniz. Neyse ki, bunu yapan araçlar var.
json2csharp.com sitesine gidin ve JSON’u C# sınıfına çevirin. Bu sınıf, Xamarin.Forms projenizdeki Model sınıfı olacak.

// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Weather {
public int id { get; set; }
public string main { get; set; }
public string description { get; set; }
public string icon { get; set; }
}
public class Current {
public int dt { get; set; }
public int sunrise { get; set; }
public int sunset { get; set; }
public double temp { get; set; }
public double feels_like { get; set; }
public int pressure { get; set; }
public int humidity { get; set; }
public double dew_point { get; set; }
public double uvi { get; set; }
public int clouds { get; set; }
public int visibility { get; set; }
public double wind_speed { get; set; }
public int wind_deg { get; set; }
public List<Weather> weather { get; set; }
}
public class Minutely {
public int dt { get; set; }
public int precipitation { get; set; }
}
public class Weather2 {
public int id { get; set; }
public string main { get; set; }
public string description { get; set; }
public string icon { get; set; }
}
public class Hourly {
public int dt { get; set; }
public double temp { get; set; }
public double feels_like { get; set; }
public int pressure { get; set; }
public int humidity { get; set; }
public double dew_point { get; set; }
public double uvi { get; set; }
public int clouds { get; set; }
public int visibility { get; set; }
public double wind_speed { get; set; }
public int wind_deg { get; set; }
public List<Weather2> weather { get; set; }
public double pop { get; set; }
}
public class Temp {
public double day { get; set; }
public double min { get; set; }
public double max { get; set; }
public double night { get; set; }
public double eve { get; set; }
public double morn { get; set; }
}
public class FeelsLike {
public double day { get; set; }
public double night { get; set; }
public double eve { get; set; }
public double morn { get; set; }
}
public class Weather3 {
public int id { get; set; }
public string main { get; set; }
public string description { get; set; }
public string icon { get; set; }
}
public class Daily {
public int dt { get; set; }
public int sunrise { get; set; }
public int sunset { get; set; }
public Temp temp { get; set; }
public FeelsLike feels_like { get; set; }
public int pressure { get; set; }
public int humidity { get; set; }
public double dew_point { get; set; }
public double wind_speed { get; set; }
public int wind_deg { get; set; }
public List<Weather3> weather { get; set; }
public int clouds { get; set; }
public double pop { get; set; }
public double uvi { get; set; }
public double? rain { get; set; }
}
public class Root {
public double lat { get; set; }
public double lon { get; set; }
public string timezone { get; set; }
public int timezone_offset { get; set; }
public Current current { get; set; }
public List<Minutely> minutely { get; set; }
public List<Hourly> hourly { get; set; }
public List<Daily> daily { get; set; }
}
Newtonsoft.JSON Eklentisini Yükleyin
Şimdi Xamarin.Forms projesini oluşturmaya başlayalım. Bir Xamarin.Forms projesinin nasıl oluşturulacağını bildiğinizi varsayarak bu adımlardan geçiyorum.
Projede hava durumu verilerini aldıktan sonra bu verileri bir koleksiyona atmalısınız. Ancak yapacağınız sorgulara JSON formatında bir yanıt geliyor. JSON formatındaki verileri bir koleksiyona atmak için JSON’u deserialize etmelisiniz.
Newtonsoft.JSON eklentisi .NET için popüler bir yüksek performanslı JSON çerçevesidir. Bu eklenti sayesinde JSON dosyalarını serialize ve deserialize edebilirisiniz.
Newtonsoft.JSON eklentisini projeye yüklemek için Paket Yöneticisi Konsolunda aşağıdaki komutu çalıştırın.
Install-Package Newtonsoft.Json -Version 12.0.3
Alternatif olarak, NuGet Paket Yöneticisi ile Newtonsoft.JSON eklentisini projeye yükleyebilirsiniz.

Xamarin.Forms OpenWeatherMap Projesi
Gerekli eklentileri projeye yükledikten sonra MVVM modelini uygulamaya başlayalım.
Model Sınıfı Ekleyin
Projeye Models adında bir klasör ekleyin ve bu klasörün içine OneCallAPI.cs adlı bir sınıf ekleyin. Daha sonra json2csharp.com’dan aldığınız kodları bu sınıfa yapıştırın. Ardından Root adlı sınıfı OneCallAPI olarak yeniden adlandırın. (Bu adlandırmalar tercihinize bağlıdır.)
public class Weather
{
public int id { get; set; }
public string main { get; set; }
public string description { get; set; }
public string icon { get; set; }
public string icon_url => string.Format("{0}{1}{2}", "https://openweathermap.org/img/wn/", icon, "@4x.png");
}
public class Current
{
public int dt { get; set; }
public int sunrise { get; set; }
public int sunset { get; set; }
public double temp { get; set; }
public double feels_like { get; set; }
public int pressure { get; set; }
public int humidity { get; set; }
public double dew_point { get; set; }
public double uvi { get; set; }
public int clouds { get; set; }
public int visibility { get; set; }
public double wind_speed { get; set; }
public int wind_deg { get; set; }
public List<Weather> weather { get; set; }
}
public class Minutely
{
public int dt { get; set; }
public int precipitation { get; set; }
}
public class Weather2
{
public int id { get; set; }
public string main { get; set; }
public string description { get; set; }
public string icon { get; set; }
public string icon_url => string.Format("{0}{1}{2}", "https://openweathermap.org/img/wn/", icon, "@4x.png");
}
public class Hourly
{
public int dt { get; set; }
public double temp { get; set; }
public double feels_like { get; set; }
public int pressure { get; set; }
public int humidity { get; set; }
public double dew_point { get; set; }
public double uvi { get; set; }
public int clouds { get; set; }
public int visibility { get; set; }
public double wind_speed { get; set; }
public int wind_deg { get; set; }
public List<Weather2> weather { get; set; }
public double pop { get; set; }
}
public class Temp
{
public double day { get; set; }
public double min { get; set; }
public double max { get; set; }
public double night { get; set; }
public double eve { get; set; }
public double morn { get; set; }
}
public class FeelsLike
{
public double day { get; set; }
public double night { get; set; }
public double eve { get; set; }
public double morn { get; set; }
}
public class Weather3
{
public int id { get; set; }
public string main { get; set; }
public string description { get; set; }
public string icon { get; set; }
public string icon_url =>string.Format("{0}{1}{2}", "https://openweathermap.org/img/wn/", icon , "@4x.png");
}
public class Daily
{
public int dt { get; set; }
public DateTimeOffset date_time => DateTimeOffset.FromUnixTimeSeconds(dt);
public int sunrise { get; set; }
public int sunset { get; set; }
public Temp temp { get; set; }
public FeelsLike feels_like { get; set; }
public int pressure { get; set; }
public int humidity { get; set; }
public double dew_point { get; set; }
public double wind_speed { get; set; }
public int wind_deg { get; set; }
public List<Weather3> weather { get; set; }
public int clouds { get; set; }
public double pop { get; set; }
public double uvi { get; set; }
public double? rain { get; set; }
}
public class OneCallAPI
{
public double lat { get; set; }
public double lon { get; set; }
public string timezone { get; set; }
public int timezone_offset { get; set; }
public Current current { get; set; }
public List<Minutely> minutely { get; set; }
public List<Hourly> hourly { get; set; }
public List<Daily> daily { get; set; }
}
ÖNEMLİ OpenWeatherMap API’si hava durumu ikonlarını kendi özel kodlarıyla(01n gibi) gönderir. Yani direkt olarak bir URL adresi göndermez. Dolayısıyla XAML’da <Image> bileşeniyle bu ikonları görüntüleyemezsiniz.
Ben de şu yola başvurdum: Model sınıfında her icon property’sinin altına icon_url adında yeni bir property tanımladım. Ardından bu property ile API’den gelen ikon kodunu ve OpenWeatherMap sitesinin adresini string.Format ile birleştirdim. (https://openweathermap.org/img/wn/01n@4x.png @4x ise ikonun büyüklüğü). Sonraki adımlarda elde ettiğim bu URL adresini XAML’da <Image> bileşenine Source olarak ayarlayacağım.
Services Sınıfı Ekleyin
Projeye Services adlı bir klasör ekleyin. Bu klasördeki sınıflara herhangi bir API sorgusu yapmak için gerekli methodları yazacağız. Yalnızca OpenWeatherMap API’si için değil diğer API’ler için yapacağınız sorgular için Services klasöründe sınıflar oluşturabilirsiniz.
Daha sonra Services klasörünün içinde WeatherAPI.cs adlı bir sınıf oluşturun. Bu sınıftaki method ile model sınıfını kullanarak One Call API koleksiyonunu çağıracağız. Tabi bu sorguyu yapabilmek için sorgu yapacağınız URL adresine gerekli parametreleri eklemeniz gerekiyor.
public const string OPENWEATHERMAP_API_KEY = "YOUR API KEY";
public const string BASE_URL = "https://api.openweathermap.org/data/2.5/onecall?lat={0}&lon={1}&units={2}&appid={3}";
public static async Task<OneCallAPI> GetOneCallAPIAsync(double lat, double lon, string units)
{
OneCallAPI weather = new OneCallAPI();
string url = String.Format(BASE_URL, lat, lon, units, OPENWEATHERMAP_API_KEY);
HttpClient httpClient = new HttpClient();
var response = await httpClient.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
var posts = JsonConvert.DeserializeObject<OneCallAPI>(content);
weather = posts;
}
return weather;
}
ViewModel Sınıfı Ekleyin
Projeye ViewModels adlı bir klasör ekleyin. Ardından ViewModels klasörünün içinde WeatherViewModel.cs adlı bir sınıf oluşturun. WeatherViewModel sınıfının kurucu methodunda Services klasöründe oluşturduğunuz GetFiveDaysAsync() yöntemini çağırın. Ve bu yöntemin döndürdüğü yanıtı bir IList’e atın. Bu IList’i sonraki adımda görünüme bağlayacaksınız. Kodlar anlatmak istediğim şeyi daha iyi açıklayacak.
public class WeatherViewModel
{
private IList<OneCallAPI> _weatherList;
public IList<OneCallAPI> WeatherList
{
get
{
if (_weatherList == null)
_weatherList = new ObservableCollection<OneCallAPI>();
return _weatherList;
}
set
{
_weatherList = value;
}
}
private async Task APIAsync()
{
var weather = await WeatherAPI.GetOneCallAPIAsync(41.008240, 28.978359, "metric");
// var weather = await WeatherAPI.GetFiveDaysAsync("Istanbul");
WeatherList.Add(weather);
}
public WeatherViewModel()
{
Task.Run(APIAsync);
}
}
View Sayfası Ekleyin
MVVM modelinde, UI bileşenlerinin bulunduğu sayfalar Views katmanında yer alır. Yani son kullanıcının gördüğü sayfalar.
Projeye Views adında bir klasör ekleyin ve bu klasör içerisinde WeatherPage.xaml adlı bir ContentPage ekleyin.
Ardından, ViewModel sınıfını View ile bağlamak için WeatherViewModel sınıfını BindingContext ile WeatherPage.xaml.cs sınıfının yapıcı yöntemine bağlayın.
public partial class WeatherPage : ContentPage
{
public WeatherPage()
{
InitializeComponent();
this.BindingContext = new WeatherViewModel();
}
}
Alternatif olarak, bu bağlamayı doğrudan görünümde BindingContext ile sağlayabilirsiniz.
<ContentPage.BindingContext>
<ob:WeatherViewModel/>
</ContentPage.BindingContext>
Daha sonra IDE tarafından verilen uyarıya göre gerekli namespace’leri eklemeyi unutmayınız.
Bu örnek projede XAML’da tasarım özelleştirmesi yapmadım. Basitçe, ViewModel sınıfından eriştiğim verileri Grid yapısı ile düzenlenmiş görünümlere bağladım. Bildiğiniz gibi bu derin bir konu ve çok zaman alıyor. Bu yüzden sonraki yazılarımda tasarım konusuna değinmek niyetindeyim.
<CollectionView ItemsSource="{Binding WeatherList}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" BackgroundColor="#E9E9E5" >
<Label Grid.Row="0" Grid.Column="0" Text="{Binding timezone}" FontSize="20" FontAttributes="Bold" TextColor="#52524E"/>
<Label Grid.Row="1" Grid.Column="0" Text="{Binding Source={x:Static sys:DateTime.Now}, StringFormat='{0:MMMM dd, yyyy}'}" />
</Grid>
<Grid Grid.Row="1" BackgroundColor="#d4d6c8" >
<Label Grid.Row="0" Grid.ColumnSpan="2" Text="Today" VerticalOptions="Center" HorizontalOptions="Center" FontSize="15"/>
<Image Grid.Row="1" Grid.Column="0" Source="{Binding current.weather[0].icon_url}" VerticalOptions="Center" HorizontalOptions="Center"/>
<Label Grid.Row="1" Grid.Column="1" Text="{Binding current.temp, StringFormat='{0:N0}°'}" VerticalOptions="Center" HorizontalOptions="Center" FontSize="20" FontAttributes="Bold"/>
<Label Grid.Row="2" Grid.ColumnSpan="2" Text="{Binding current.weather[0].main}" VerticalOptions="Center" HorizontalOptions="Center" FontSize="15"/>
</Grid>
<Grid Grid.Row="2" BackgroundColor="#e9e9e5">
<Label Grid.Row="0" Grid.Column="0" Text="{Binding current.wind_speed, StringFormat='{0:N0}km/h'}" VerticalOptions="Center" HorizontalOptions="Center"/>
<Label Grid.Row="1" Grid.Column="0" Text="Wind" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold"/>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding current.humidity, StringFormat='{0:N0}%'}" VerticalOptions="Center" HorizontalOptions="Center"/>
<Label Grid.Row="1" Grid.Column="1" Text="Humidity" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold"/>
<Label Grid.Row="0" Grid.Column="2" Text="{Binding current.feels_like, StringFormat='{0:N0}°'}" VerticalOptions="Center" HorizontalOptions="Center"/>
<Label Grid.Row="1" Grid.Column="2" Text="Feels Like" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold"/>
</Grid>
<Grid Grid.Row="3" BackgroundColor="#d4d6c8">
<Label Grid.Row="0" Grid.Column="0" Text="{Binding daily[1].date_time, StringFormat='{0:M}'}" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold"/>
<Image Grid.Row="1" Grid.Column="0" Source="{Binding daily[1].weather[0].icon_url}" VerticalOptions="Center" HorizontalOptions="Center"/>
<Label Grid.Row="2" Grid.Column="0" Text="{Binding daily[1].temp.day, StringFormat='{0:N0}°'}" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold" FontSize="20"/>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding daily[2].date_time, StringFormat='{0:M}'}" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold"/>
<Image Grid.Row="1" Grid.Column="1" Source="{Binding daily[2].weather[0].icon_url}" VerticalOptions="Center" HorizontalOptions="Center"/>
<Label Grid.Row="2" Grid.Column="1" Text="{Binding daily[2].temp.day, StringFormat='{0:N0}°'}" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold" FontSize="20"/>
<Label Grid.Row="0" Grid.Column="2" Text="{Binding daily[3].date_time, StringFormat='{0:M}'}" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold"/>
<Image Grid.Row="1" Grid.Column="2" Source="{Binding daily[3].weather[0].icon_url}" VerticalOptions="Center" HorizontalOptions="Center"/>
<Label Grid.Row="2" Grid.Column="2" Text="{Binding daily[3].temp.day, StringFormat='{0:N0}°'}" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold" FontSize="20"/>
<Label Grid.Row="0" Grid.Column="3" Text="{Binding daily[4].date_time, StringFormat='{0:M}'}" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold"/>
<Image Grid.Row="1" Grid.Column="3" Source="{Binding daily[4].weather[0].icon_url}" VerticalOptions="Center" HorizontalOptions="Center"/>
<Label Grid.Row="2" Grid.Column="3" Text="{Binding daily[4].temp.day, StringFormat='{0:N0}°'}" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold" FontSize="20"/>
<Label Grid.Row="0" Grid.Column="4" Text="{Binding daily[5].date_time, StringFormat='{0:M}'}" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold"/>
<Image Grid.Row="1" Grid.Column="4" Source="{Binding daily[5].weather[0].icon_url}" VerticalOptions="Center" HorizontalOptions="Center"/>
<Label Grid.Row="2" Grid.Column="4" Text="{Binding daily[5].temp.day, StringFormat='{0:N0}°'}" VerticalOptions="Center" HorizontalOptions="Center" FontAttributes="Bold" FontSize="20"/>
</Grid>
</Grid>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Tüm adımları sırayla tamamladıktan sonra uygulamayı çalıştırın ve nasıl göründüğüne bakın.

Sonuç
Hava durumu verilerini API koleksiyonları aracılığıyla paylaşan birçok servis var. Ancak bunlardan bazıları ücretliyken bazıları da sınırlı sayıda veri gönderiyor. Yaptığım araştırmalar sonucunda OpenWeatherMap API’sinin ücretsiz en iyi ücretsiz hava durumu servisi olduğuna karar verdim.
Bu yazımda bir Xamarin.Forms projesinde OpenWeatherMap REST API’nin nasıl kullanılacağını adım adım anlattım. Umarım faydalı olmuştur.