Skip to content

Commit

Permalink
add /emissions/year/{year} endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
hehu80 committed Sep 13, 2024
1 parent 129a31f commit 65e3d17
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 6 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ The required raw data can be downloaded here https://www.kaggle.com/datasets/rej
| List all countries | GET | /countries |
| Returns a single country | GET | /countries/{name} |
| List all emissions of all countries for each year | GET | /emissions/year |
| Get all emissions of a specific year | GET | /emissions/year/{year} |
| List all emissions of all years for each country | GET | /emissions/country |
| List all emissions of a specific country | GET | /emissions/country/{name} |
| Get all emissions of a specific country | GET | /emissions/country/{name} |

## 🚀 How to run

Expand Down
12 changes: 12 additions & 0 deletions http-request-emissions.http
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@
# }
GET {{url}}:{{port}}/emissions/year/

### GET all emissions of a single year
# expected response:
# {
# "nox_emissions": {
# "average": 1597043.105081651,
# "median": 71152.08,
# "standard_deviation": 8007847.335584437
# },
# ...
# }
GET {{url}}:{{port}}/emissions/year/2000

### GET list of all emissions by year
# expected response:
# {
Expand Down
10 changes: 7 additions & 3 deletions internal/resource/countries_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@ type fakeCountryStorage struct {
}

func (s fakeCountryStorage) FindAllByYears() map[int][]*model.Emissions {
return nil
panic("not implemented")
}

func (s fakeCountryStorage) FindAllByYear(year int) map[string]*model.Emissions {
panic("not implemented")
}

func (s fakeCountryStorage) FindAllByCountries() map[string][]*model.Emissions {
return nil
panic("not implemented")
}

func (s fakeCountryStorage) FindAllByCountry(name string) map[int]*model.Emissions {
return nil
panic("not implemented")
}

func (s fakeCountryStorage) GetCountry(name string) *model.Country {
Expand Down
22 changes: 22 additions & 0 deletions internal/resource/emissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/go-chi/render"
"github.com/montanaflynn/stats"
"net/http"
"strconv"
)

type EmissionResource struct {
Expand Down Expand Up @@ -86,6 +87,7 @@ func (rs EmissionResource) Routes() chi.Router {

r.Route("/year/", func(r chi.Router) {
r.Get("/", rs.ListByYear)
r.Get("/{year}", rs.GetByYear)
})

r.Route("/country/", func(r chi.Router) {
Expand All @@ -108,6 +110,26 @@ func (rs EmissionResource) ListByYear(w http.ResponseWriter, r *http.Request) {
}
}

func (rs EmissionResource) GetByYear(w http.ResponseWriter, r *http.Request) {
year, err := strconv.Atoi(chi.URLParam(r, "year"))
if err != nil {
if err := render.Render(w, r, ErrRender(fmt.Sprintf("Invalid year"), 400)); err != nil {
render.Status(r, 500)
}
return
}

var yearEmissions []*model.Emissions
for _, emissions := range rs.Storage.FindAllByYear(year) {
yearEmissions = append(yearEmissions, emissions)
}

response := newAirPollutionEmissionsResponse(yearEmissions)
if err := render.Render(w, r, response); err != nil {
render.Status(r, 500)
}
}

func (rs EmissionResource) ListByCountry(w http.ResponseWriter, r *http.Request) {
response := make(map[string]airPollutionEmissionsResponse)
for country, emissions := range rs.Storage.FindAllByCountries() {
Expand Down
42 changes: 40 additions & 2 deletions internal/resource/emissions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"io/ioutil"
"net/http"
"net/http/httptest"
"strconv"
"testing"
)

Expand All @@ -22,6 +23,14 @@ func (s fakeEmissionsStorage) FindAllByYears() map[int][]*model.Emissions {
return result
}

func (s fakeEmissionsStorage) FindAllByYear(year int) map[string]*model.Emissions {
result := make(map[string]*model.Emissions)
for i, e := range s.emissions {
result[strconv.Itoa(i)] = e
}
return result
}

func (s fakeEmissionsStorage) FindAllByCountries() map[string][]*model.Emissions {
result := make(map[string][]*model.Emissions)
result["test"] = s.emissions
Expand All @@ -37,11 +46,11 @@ func (s fakeEmissionsStorage) FindAllByCountry(name string) map[int]*model.Emiss
}

func (s fakeEmissionsStorage) GetCountry(name string) *model.Country {
return nil
panic("not implemented")
}

func (s fakeEmissionsStorage) GetCountries() []*model.Country {
return nil
panic("not implemented")
}

func TestEmissionsListByYear(t *testing.T) {
Expand Down Expand Up @@ -118,3 +127,32 @@ func TestEmissionsGetByCountry(t *testing.T) {
assert.Equal(t, 3.0, airPollutionEmissions.NOxEmissions.Median)
assert.Equal(t, 3.559026084010437, airPollutionEmissions.NOxEmissions.StandardDeviation)
}

func TestEmissionsGetByYear(t *testing.T) {
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/", nil)
ctx := chi.NewRouteContext()
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, ctx))
ctx.URLParams.Add("year", "666")
emissionsHandler := EmissionResource{Storage: fakeEmissionsStorage{[]*model.Emissions{{
NOxEmissions: 10,
}, {
NOxEmissions: 2,
}, {
NOxEmissions: 3,
}}}}

emissionsHandler.GetByYear(w, req)
res := w.Result()
defer res.Body.Close()
data, err := ioutil.ReadAll(res.Body)
assert.Nil(t, err)
assert.Equal(t, 200, res.StatusCode)

airPollutionEmissions := airPollutionEmissionsResponse{}
err = json.Unmarshal(data, &airPollutionEmissions)
assert.Nil(t, err)
assert.Equal(t, 5.0, airPollutionEmissions.NOxEmissions.Average)
assert.Equal(t, 3.0, airPollutionEmissions.NOxEmissions.Median)
assert.Equal(t, 3.559026084010437, airPollutionEmissions.NOxEmissions.StandardDeviation)
}
12 changes: 12 additions & 0 deletions internal/store/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type Store struct {

type Storage interface {
FindAllByYears() map[int][]*model.Emissions
FindAllByYear(year int) map[string]*model.Emissions
FindAllByCountries() map[string][]*model.Emissions
FindAllByCountry(name string) map[int]*model.Emissions
GetCountry(name string) *model.Country
Expand Down Expand Up @@ -97,6 +98,17 @@ func (s *Store) FindAllByYears() map[int][]*model.Emissions {
return emissions
}

func (s *Store) FindAllByYear(year int) map[string]*model.Emissions {
emissions := make(map[string]*model.Emissions)
for name, countryEmissions := range s.emissions {
countryEmissionsOfYear, found := countryEmissions[year]
if found {
emissions[name] = &countryEmissionsOfYear
}
}
return emissions
}

func (s *Store) FindAllByCountries() map[string][]*model.Emissions {
emissions := make(map[string][]*model.Emissions)
for name, countryEmissions := range s.emissions {
Expand Down

0 comments on commit 65e3d17

Please sign in to comment.