Xamarin.Forms Entirely Weather App Using OpenWeather Map REST API
Contents
Want to develop a weather app but don’t have a weather data available to you? Do not worry. Many weather services provide their data to developers for free. OpenWeatherMap weather service has also been the choice of millions of developers with the paid and free packages it provides.
You can access a lot of data with the free account of OpenWeatherMap service. For example, with the Current Weather Data collection, you can only get instant data in JSON, XML and HTML format. Or, with the Hourly Forecast 4 Days collection, you can access 4-day data every hour on the hour. As a result of your queries, you can reach many data such as the temperature of the region you want, weather, sunrise and sunset times.
Besides, you can of course also buy paid packages. However, if you are not going to process data for a commercial purpose, the free package will be more than enough.
In this post, I will explain step by step how to use the OpenWeatherMap REST API in a Xamarin.Forms project. I will also implement the MVVM model in the project, but I will not mention the details of this topic. I have already explained this issue in my article called Xamarin.Forms MVVM Pattern.
In this project I will use the One Call API collection of the OpenWeatherMap service. One Call API offers minute, hourly and daily data in JSON format. I chose this because I can access many data from a single collection.
So, let’s started. Follow the steps below in order.
1) Sign Up for OpenWeatherMap
An API key is required to use the OpenWeatherMap API. Get your API key by following the steps below.
1) Firstly, log into the OpenWeatherMap and Sign in if you already have an account.
2) If you don’t have an account, create a new account by clicking Create an Account.
3) Then click the Create Account button after filling the necessary information.
4) In this step, a popup window will open. After entering the company name and the purpose of using the service, click the Save button. Thus, you will go to the administration panel of your account.
5) Then confirm your account with the email you received. Now your account is created and you are ready to receive the API key.
6) Click on API keys to generate the API key. By default, an API key will already be generated. If you wish, you can generate a new API key from the Create key section.
2) Convert JSON to C#
In this step, you have to convert the API collection you want to use to the C # class. How to use API collections is available on OpenWeatherMap.
In other words, you should first learn which query to access the API collection of your choice and then get an answer from this query with the Get medhod. Since the answer you will receive will be in JSON format, you should convert this JSON to C # class using json2csharp.com.
Follow the steps sequentially.
1) First, go to https://openweathermap.org/api. You can also access this address from the navigation menu of the OpenWeatherMap site.
2) There are collections of APIs you can use here. After selecting the collection you want according to the content of your account, click the API doc button to access the documentation. I will use the One Call API collection in this project.
3) Here, in How to make an API call section, you will see the connection address and parameters that you need to query to call the API. The link that will be used to call the One Call API collection is:
https://api.openweathermap.org/data/2.5/onecall?lat=41.008240&lon=28.978359&units=metric&appid=YOUR API KEY
Here lat is the latitude of your location, lon longitude, units in which unit you want to get the data, and apikey is your API key. Please review the documentation for more customization.
4) After entering the parameters according to you, search for this address in a new tab. Alternatively, you can use API tools such as Postman or Fiddler. As a result, you will get a JSON file with weather data.
{"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}]}
5) Convert this JSON file to C # class using json2csharp.com. This class will be the Model class in your Xamarin.Forms project.
// 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; }
}
3) Download Newtonsoft.JSON Plugin
Now let’s start building the Xamarin.Forms project. I’m going through these steps, assuming you know how to create a Xamarin.Forms project.
Use the Newtonsoft.JSON plugin to make API queries in the projects you develop. Json.NET is a popular high-performance JSON framework for .NET. It is also one of the most useful plugins in Xamarin.
Run the following command in Package Manager Console to install this add-in to the project.
Install-Package Newtonsoft.Json -Version 12.0.3
Or, open NuGet Package Manager by right-clicking the project in Solution Explorer. Then type Newtonsoft.JSON in the search bar and upload the plugin to the project.
4) Implement MVVM Model
Now it’s time to implement the MVVM model in the Xamarin project. I have written an article about MVVM model before. So I will not go into details.
Add Model Class
Add a folder named Models to the project and add a class named OneCallAPI inside that folder. Then paste the codes you get from json2csharp.com into this class. Then rename the class named Root to OneCallAPI. This is up to your preference.
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; }
}
You may have noticed that some properties in the class you obtained from json2csharp.com site do not exist in the Model class codes above. Because we can access the icons provided by the API in PNG format. However, in order to display these icons in Image view in the View layer https://openweathermap.org/img/wn/01n@4x.png it is necessary to obtain this url. In other words, our goal is to make the necessary arrangements and obtain a url instead of using the weather icons we get directly from the API.
Add Services Class
Then add a folder called Services to the project. We will write the necessary methods to make any API query to the classes in this folder. You can create classes in the Services folder for queries you will do not only for the OpenWeatherMap API but for other APIs.
Create a class named WeatherAPI inside the Services folder. We will call the One Call API collection by using the model class with the method in this class. Of course, in order to do this query, you need to add the API key to the link you will query.
public const string OPENWEATHERMAP_API_KEY = "ece317b574b62dbc425b34aedcc2a774";
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;
}
Add ViewModel Class
To bind the views you will create in the last layer, you need a ViewModel class. In the MVVM model, the classes in the ViewModel layer act as a bridge between the Model and View layers.
Add a folder named ViewModels to the project. Then create a class named WeatherViewModel inside the ViewModels folder. Call the GetFiveDaysAsync method that you created in the Services folder in the constructor method of the WeatherViewModel class. And add the response from this method into IList. You will bind this IList to the view in the next step. It will explain better what I want to explain the codes.
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);
}
}
Add View Page
In the MVVM model, the pages that the user will see are located in the Views folder. So add a folder called Views to the project.
Add a ContentPage named WeatherPage.xaml to the Views folder.
Next, bind the WeatherViewModel class with BindingContext to the constructor method of the WeatherPage.xaml.cs class to bind the ViewModel class with View.
public partial class WeatherPage : ContentPage
{
public WeatherPage()
{
InitializeComponent();
this.BindingContext = new WeatherViewModel();
}
}
Alternatively, you can provide this binding directly in the view with BindingContext.
<ContentPage.BindingContext>
<ob:WeatherViewModel/>
</ContentPage.BindingContext>
Then do not forget to add the required namespace according to the warning given by the IDE.
There is no design customization in WeatherPage.xaml. Simply, I connected the data I accessed from the ViewModel class to the views arranged with grid structure. As you know, this is a deep subject and it takes a lot of time. That’s why I intend to mention the subject of design in my later articles.
<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>
After completing all the steps in order, run the application and see how it looks.
Conclusion
OpenWeatherMap API allows developers to access a lot of weather data with their paid and free accounts. Of course, there are services similar to this one. However, as a result of my research, I decided that OpenWeatherMap API is more useful for a Mobile application than others.
In this post, I explained step by step how to develop an MVVM model Xamarin.Forms application using the data we have accessed from the OpenWeatherMap API. I hope it was useful.
If you’re still not sure what to do, or if you got any errors, then I suggest you use the comment section below and let me know! I am here to help!
Also, share this blog post on social media and help more people learn.
Hi there I bumped in your articles about xamarin, they are excellent
Do you have a github repo where we can download the code?
Firstly, thank you.
I recommend that you write the codes yourself to better understand the topic.