Individual Contribution Report 2 Beyza Akçınar - bounswe/bounswe2023group3 GitHub Wiki

Info about myself:

I am Beyza Akçınar, a member of the Group #3 for the course CMPE 352. To find out more about me, you can visit this page.

Important Issues Related to the Practice Application

  • See issue #69.
  • See issue #70.
  • See issue #90.

Third-Party URIs

I decided to use OpenWeatherAPI while creating my application. OpenWeatherAPI is a weather data provider that offers access to a wide range of weather-related information and forecasts. I mainly used the 5 day weather forecast and air pollution APIs provided to retrieve weather data for various locations around the world.

API Functions

I implemented 3 GET and 2 POST api calls in my application.

  • weather(GET): Route=/weather/.
  • forecast(GET): Route=/weather/forecast.
  • forecast(POST): Route=/weather/forecast.
  • air_quality(GET): Route=/weather/air_quality.
  • air_quality(POST): Route=/weather/air_quality.
def fetch_weather_data(city, API_key, weather_url, forecast_url):
    response = requests.get(weather_url.format(city, API_key)).json()

    if response['cod'] == '404': #if city name is not valid
        return None, None
    
    lat, lon = response['coord']['lat'], response['coord']['lon']
    all_response = requests.get(forecast_url.format(lat, lon, API_key)).json()

    weather_data = {
        "city" : city,
        "temperature" : round(response['main']['temp'] - 273.15, 1),
        "description" : response['weather'][0]['description'],
        "icon" : response['weather'][0]['icon']
    }

    forecast_data = [] 
    
    for data in all_response['list'][:40:8]:
        forecast_data.append(
            {
                "day" : datetime.datetime.fromtimestamp(data['dt']).strftime("%A"),
                "min_temperature" : round(data['main']['temp_min'] - 273.15, 1),
                "max_temperature" : round(data['main']['temp_max'] - 273.15, 1),
                "description" : data['weather'][0]['description'],
                "icon" : data['weather'][0]['icon']
            }
        )

    return weather_data, forecast_data
def fetch_air_quality_data(city, API_key, weather_url, air_url):
    response = requests.get(weather_url.format(city, API_key)).json()

    if response['cod'] == '404': #if city name is not valid
        return None, None
    
    lat, lon = response['coord']['lat'], response['coord']['lon']
    air_response = requests.get(air_url.format(lat, lon, API_key)).json()

    weather_data = {"city" : city}

    air_quality_data = [] 
    air_index_data = ['Good', 'Fair', 'Moderate', 'Poor', 'Very Poor'] 
    
    for data in air_response['list'][:40:8]:
        air_quality_data.append(
            {
                "day" : datetime.datetime.fromtimestamp(data['dt']).strftime("%A"),
                "index" : air_index_data[int(data['main']['aqi'])-1],
                "CO" : data['components']['co'],
                "NO" : data['components']['no'],
                "NO2" : data['components']['no2'],
                "O3" : data['components']['o3'],
                "SO2" : data['components']['so2']
            }
        )

    return weather_data, air_quality_data

Each of these functions are called from POST functions and fetched json data is processed to return only the needed parts. You can view my application here.

Unit Tests

class FetchWeatherDataTestCase(TestCase):
    def test_fetch_weather_data_with_valid_city(self):
        city = 'New York' 
        weather_data, forecast_data = fetch_weather_data(city, API_key, weather_url, forecast_url)
        self.assertIsNotNone(weather_data)
        self.assertIsNotNone(forecast_data)

        city = 'London' 
        weather_data, forecast_data = fetch_weather_data(city, API_key, weather_url, forecast_url)
        self.assertIsNotNone(weather_data)
        self.assertIsNotNone(forecast_data)

    def test_fetch_weather_data_with_invalid_city(self):
        city = 'Invalid Name'
        weather_data, forecast_data = fetch_weather_data(city, API_key, weather_url, forecast_url)
        self.assertIsNone(weather_data)
        self.assertIsNone(forecast_data)
class FetchAirQualityDataTestCase(TestCase):
    def test_fetch_air_quality_data_with_valid_city(self):
        city = 'New York'
        weather_data, air_quality_data = fetch_air_quality_data(city, API_key, weather_url, air_url)

        self.assertIsNotNone(weather_data)
        self.assertIsNotNone(air_quality_data)

    def test_fetch_air_quality_data_with_invalid_city(self):
        city = 'Invalid Name'
        weather_data, air_quality_data = fetch_air_quality_data(city, API_key, weather_url, air_url)

        self.assertIsNone(weather_data)
        self.assertIsNone(air_quality_data)

Challenges

Since this was my first time using GitHub for collaborative code development, I have faced some issues. Especially during the initial process of developing our practice application, I was hesitant to take action in case I might result in some irreversible problems. Even though this process was mentally challenging, I gained more skills and confidence after this experience. I have become more comfortable with opening significant issues, navigating through GitHub, creating branches and pull requests when necessary. I also learned so much from our group members. In addition, our group took a risk and decided on using Django Framework for creating our practice application. Even though I had experience with developing web applications with another tools before, I am thankful to this decision since learning another significant tool surely enhanced my capabilities as a developer. Also, installing all of the necessary tools, setting the environment for development and getting used to using another framework was also challenging.