Weather API - bounswe/2021SpringGroup9 GitHub Wiki
-
Story: A model in the database. It is a model for user's stories that they post in our app. Its fields are:
- id: Story's id to be kept in the database.
- title: Story's title with maximum char length 200
- story: Story's content with maximum char length 1000
- name: The user's name who posted the story. It has a maximum char length of 200.
- longitude: Story's location's longitude.
- latitude: Story's location's latitude.
- location: Story's location name with maximum char length 200.
- tag: Story's tag with maximum char length 200.
- date: Story's post date.
- notifyAdmin: Shows if a story needs to notify the admin or not.
- OpenWeatherMap API: This API is used to get a locations weather information at the time that request has been sent.
My API, when a get request has been sent, gets the story with the given ID. Then taking its longitude and latitude, it send a request to third party API (OpenWeatherMap API)with this headers and an API key taken from .env file. Then it takes this information and filters out the required information. Makes Kelvin to Celcius transformations. Timezone transformation (third party API provides this information with minutes, I changed it to hours to make it more understandable). Then it adds a comment about the weather.
- Get current weather information of the location of story.
Request:
GET
http://localhost:8000/api/weather/<story_id>
Parameters:
{
story_id = The id of the Story
}
Response:
{
"condition": "X",
"temperature": X,
"feel": X,
"wind": X,
"country": "X",
"time_zone": X,
"comment": "X"
}
GET /api/weather/<valid story id>
{
"condition": "Clouds",
"temperature": 27.08,
"feel": 27.31,
"wind": 4.87,
"country": "TR",
"time_zone": 3,
"comment": "Temperatures are great! Go out there and have fun!"
}
GET /api/weather/<invalid story id (story with that id does not exist)>
Story does not exist
GET /api/weather/<invalid story id (id is not an integer)>
Only integer values are used by this API
POST/DELETE/PUT /api/weather/<valid story id>
{
"detail": "Method \"POST/DELETE/PUT\" not allowed."
}
GET /api/weather/<valid story id> But this time OpenWeatherMap API is not operational (either servers are down or API key is invalid).
Could not send request to OpenWeather API
To use Weather API, there is no need for authentication. But since it uses OpenWeatherMap API, and OpenWeatherMap uses API keys, there should be an API key for using it. It should be stored in .env file.
More information about the status codes can be found in: https://httpstatuses.com/
Name | Meaning |
---|---|
HTTP_200_OK | Successful Request |
HTTP_400_BAD_REQUEST | If given story id is not integer or connection can not be established with OpenWeatherMap |
HTTP_404_NOT_FOUND | Error when story with that id does not exists. |
HTTP_405_METHOD_NOT_ALLOWED | Error when other requests than GET is requested. |
- Models Used in Weather API
This API uses only the Story model.
class Story(models.Model):
title = models.CharField(max_length=200)
story = models.CharField(max_length=1000)
name = models.CharField(max_length=200)
longitude = models.FloatField()
latitude = models.FloatField()
location = models.CharField(max_length=200)
tag = models.CharField(max_length=200)
date = models.DateTimeField(auto_now_add=True)
notifyAdmin = models.BooleanField(default=False)
def __str__(self):
return self.title
- Views
@api_view(['GET'])
def weather(request,story_id):
if(request.method!='GET'):
httpresponse=HttpResponse('Only GET method is available for this API')
httpresponse.status_code=405
return httpresponse
if(not isinstance(story_id,int)):
httpresponse=HttpResponse('Only integer values are used by this API')
httpresponse.status_code=400
return httpresponse
try:
story=Story.objects.get(id=story_id)
except Story.DoesNotExist:
httpresponse=HttpResponse('Story does not exist')
httpresponse.status_code=404
return httpresponse
resp=requests.get("http://api.openweathermap.org/data/2.5/weather?lat=%s&lon=%s&appid=%s" % (story.latitude,story.longitude,WEATHER_API_KEY))
if(resp.status_code!=200):
httpresponse=HttpResponse('Could not send request to OpenWeather API')
httpresponse.status_code=400
return httpresponse
weather=resp.json()
condition=weather['weather'][0]['main']
temperature=round(weather['main']['temp']-(273.15),2)
feel=round(weather['main']['feels_like']-(273.15),2)
wind=weather['wind']['speed']
country=weather['sys']['country']
timezone=round(weather['timezone']/3600)
if(temperature<0):
comment="Wow it is freezing out there!"
elif(temperature<15):
comment="It is cold!"
elif(temperature<30):
comment="Temperatures are great! Go out there and have fun!"
else:
comment="It is hot! You sure you are OK?"
return JsonResponse({
'condition':condition,
'temperature':temperature,
'feel':feel,
'wind':wind,
'country':country,
'time_zone':timezone,
'comment':comment
})
- Tests
class WeatherTest(TestCase):
def setUp(self):
"""
An instance that works
"""
Story.objects.create(
title = "Title1",
story = "Story1",
name = "User1",
longitude = 41,
latitude = 28,
location = "Istanbul",
tag = "Tag1",
notifyAdmin = False
)
"""
An instance with wrong longitude.
"""
Story.objects.create(
title = "Title2",
story = "Story2",
name = "User2",
longitude = 4100,
latitude = 28,
location = "Not Istanbul",
tag = "Tag2",
notifyAdmin = True
)
"""
Send post request. Should not be allowed.
"""
def test_post_requests(self):
c=Client()
resp=c.post("/api/weather/1")
self.assertEqual(resp.status_code,405)
"""
Send put request. Should not be allowed.
"""
def test_put_requests(self):
c=Client()
resp=c.put("/api/weather/1")
self.assertEqual(resp.status_code,405)
"""
Send delete request. Should not be allowed.
"""
def test_delete_requests(self):
c=Client()
resp=c.delete("/api/weather/1")
self.assertEqual(resp.status_code,405)
"""
Test when an instance does not exists.
"""
def test_when_story_does_not_exist(self):
c=Client()
resp=c.get("/api/weather/3")
self.assertEqual(resp.status_code,404)
"""
OpenWeather API fails with wrong longitude or latitude.
"""
def test_when_openweather_api_fails(self):
c=Client()
resp=c.get("/api/weather/2")
self.assertEqual(resp.status_code,400)
"""
This is an instance that works.
"""
def test_works_correct(self):
c=Client()
resp=c.get("/api/weather/1")
self.assertEqual(resp.status_code,200)
"""
When parameter is not an integer type.
"""
def test_string_type_parameter(self):
c=Client()
resp=c.get("/api/weather/mert")
self.assertEqual(resp.status_code,400)