diff --git a/README.md b/README.md index 30c8fa3..e968ce1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,38 @@ # Backend [Places-Microservice-Server] [![Build Status](https://travis-ci.com/climatetree/places-microservice.svg?branch=develop)](https://travis-ci.com/climatetree/places-microservice) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=com.climatetree%3Aplaces-microservice&metric=alert_status)](https://sonarcloud.io/dashboard?id=com.climatetree%3Aplaces-microservice) + +# Microservice Architecture +## Repo Structure +This repository holds the source code for the backend services for locations/places included included the +climateTree.wiki web application. This application was built using Java, Maven, and Spring Boot. +This repo contains the following important folders: +- Controller + - Hosts the API endpoints +- Dao + - Provides queries that can be called on the connected database. + - All queries return a GeoJson object string. +- Services + - Intermediary class between the Controller and the Dao that performs additional data processing + steps. + +The Model and DTO folders are not currently in use, but were kept for archiving purposes. + +## API Endpoints +It is important to note that only 1 of the 4 APIs is currently being used in the climateTree.wiki project. The +only API that is being used is `/api/v1/places/{name}`. This is being used by the front end to retrieve the names +of places that contain the given `name`. All other APIs have been transition to GeoServer. The GeoServer repository +can be viewed [here](https://github.com/climatetree/geoserver-docker). + +The endpoints that are defined in the Controller can be viewed [here on Postman](https://documenter.getpostman.com/view/10295047/Szf55VXU?version=latest) + +## Database +This application directly connects to the ClimateTree project's Places Database that is currently hosted +on Azure. Connection strings are provided as environment variables to the `application.properties` configuration. The +database schema can be seen [here](https://tinyurl.com/yaa3rfp3). + +## Bugs, Enhancements, and Improvements + + + + diff --git a/src/main/java/com/climatetree/places/PlacesMicroserviceServerApplication.java b/src/main/java/com/climatetree/places/PlacesMicroserviceServerApplication.java index ad3a807..8127f42 100644 --- a/src/main/java/com/climatetree/places/PlacesMicroserviceServerApplication.java +++ b/src/main/java/com/climatetree/places/PlacesMicroserviceServerApplication.java @@ -4,6 +4,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; +/** + * Main entry point for the application. + */ @SpringBootApplication @EnableCaching public class PlacesMicroserviceServerApplication { diff --git a/src/main/java/com/climatetree/places/controller/PlacesController.java b/src/main/java/com/climatetree/places/controller/PlacesController.java index d470dbd..6c1f575 100644 --- a/src/main/java/com/climatetree/places/controller/PlacesController.java +++ b/src/main/java/com/climatetree/places/controller/PlacesController.java @@ -17,9 +17,12 @@ import com.climatetree.places.service.NamesService; import com.climatetree.places.service.PlacesService; +/** + * Class that defines all of the API endpoints for the Places backend microservice. + */ @RestController @RequestMapping("/api") -@CrossOrigin(origins = "*") +@CrossOrigin(origins = "https://climatetree-api-gateway.azurewebsites.net") public class PlacesController { @Autowired @@ -28,11 +31,36 @@ public class PlacesController { @Autowired NamesService namesService; + /** + * This endpoint returns a list of places as a GeoJson object that are similar to the place + * with the given placeId. A place is similar if it is within 95%-150% population of the provided + * place. + * + * @param placeId integer + * @return GeoJson list of places + */ @GetMapping("/v1/places/{placeId}/similar") public String getSimilarPlaces(@PathVariable("placeId") int placeId) { return placesService.getSimilarPlacesDefault(placeId); } + /** + * This endpoint returns a list of places as a GeoJson object that are similar to the place + * with the given placeId. This is an advanced filter for similar searching which means that all + * places that are returned are within every range that are provided from the user. All ranges + * are optional. + * + * @param placeId int + * @param populationStart low value of population range + * @param populationEnd high value of the population range + * @param carbonStart low value of carbon range + * @param carbonEnd high value of carbon range + * @param perCapCarbonStart low value of per capita carbon range + * @param perCapCarbonEnd high value of per capita carbon range + * @param popDensityStart low value of population density range + * @param popDensityEnd hig value of population density range + * @return GeoJson list of places + */ @GetMapping("/v1/places/{placeId}/similar/advanced") public String getSimilarPlaces(@PathVariable("placeId") int placeId, @RequestParam(required = false) Integer populationStart, @@ -47,11 +75,27 @@ public String getSimilarPlaces(@PathVariable("placeId") int placeId, carbonEnd, perCapCarbonStart, perCapCarbonEnd, popDensityStart, popDensityEnd); } + /** + * THIS IS THE ONLY API THAT IS CURRENTLY BEING USED ON THE FRONT END. + * + * This endpoint returns a list of places that contain the provided name. For example if the given + * name is 'Man', any place in the database that has a name that contains "man", will be returned. + * @param name serach term + * @return GeoJson list of places + */ @GetMapping("/v1/places/{name}") public String getPlacesByName(@PathVariable("name") String name) { return namesService.getPlacesBySearchTerm(name); } + /** + * This endpoint returns a single place that is closest (in geographical location) to the given + * latitude/longitude point. + * + * @param latitude latitude in degrees + * @param longitude longitude in degrees + * @return GeoJson object containing 1 place + */ @GetMapping("/v1/places/nearest") public String getNearestPlace(@RequestParam double latitude, @RequestParam double longitude){ return placesService.getNearbyPlace(latitude, longitude); diff --git a/src/main/java/com/climatetree/places/dao/NameRepository.java b/src/main/java/com/climatetree/places/dao/NameRepository.java index eb30d3a..055a0bd 100644 --- a/src/main/java/com/climatetree/places/dao/NameRepository.java +++ b/src/main/java/com/climatetree/places/dao/NameRepository.java @@ -10,6 +10,13 @@ @Repository public interface NameRepository extends CrudRepository { + /** + * Calls a stored function in the database to return a list of GeoJson objects that contain + * the provided searchTerm. + * + * @param upperName Search term + * @return GeoJson list of places + */ @Query(value = "SELECT public.\"getPlacesBySearchTerm\"(\n" + "\t:upperName\n" + ")", nativeQuery = true) diff --git a/src/main/java/com/climatetree/places/dao/PlaceRepository.java b/src/main/java/com/climatetree/places/dao/PlaceRepository.java index 9a657e2..cf6c972 100644 --- a/src/main/java/com/climatetree/places/dao/PlaceRepository.java +++ b/src/main/java/com/climatetree/places/dao/PlaceRepository.java @@ -14,7 +14,6 @@ public interface PlaceRepository extends CrudRepository { /** - * Queries the database for PlaceInfo entries that are within the following range: * Uses a stored database function to query the database and return a geoJson object where each * Place in the list fits the following criteria: * - TypeId = TypeId diff --git a/src/main/java/com/climatetree/places/dto/PlaceDTO.java b/src/main/java/com/climatetree/places/dto/PlaceDTO.java index 35093b7..52f032d 100644 --- a/src/main/java/com/climatetree/places/dto/PlaceDTO.java +++ b/src/main/java/com/climatetree/places/dto/PlaceDTO.java @@ -1,5 +1,8 @@ package com.climatetree.places.dto; +/** + * Defines a Places data transfer object. + */ public class PlaceDTO { private int placeId; diff --git a/src/main/java/com/climatetree/places/model/EcoName.java b/src/main/java/com/climatetree/places/model/EcoName.java index 93df081..4c0919c 100644 --- a/src/main/java/com/climatetree/places/model/EcoName.java +++ b/src/main/java/com/climatetree/places/model/EcoName.java @@ -13,6 +13,9 @@ import com.fasterxml.jackson.annotation.JsonIgnore; +/** + * Mirrors the Eco Name table from the database. + */ @Entity @Table(name="\"ECO_NAME\"") public class EcoName implements Serializable { diff --git a/src/main/java/com/climatetree/places/model/Name.java b/src/main/java/com/climatetree/places/model/Name.java index 58a9d3d..5fc3c7b 100644 --- a/src/main/java/com/climatetree/places/model/Name.java +++ b/src/main/java/com/climatetree/places/model/Name.java @@ -15,6 +15,9 @@ import com.fasterxml.jackson.annotation.JsonManagedReference; +/** + * Mirrors the Name table from the database. + */ @Entity @Table(name = "\"NAME\"") public class Name implements Serializable { diff --git a/src/main/java/com/climatetree/places/model/PlaceInfo.java b/src/main/java/com/climatetree/places/model/PlaceInfo.java index 26f7e06..9ac4a38 100644 --- a/src/main/java/com/climatetree/places/model/PlaceInfo.java +++ b/src/main/java/com/climatetree/places/model/PlaceInfo.java @@ -15,6 +15,11 @@ import com.climatetree.places.dto.PlaceDTO; import com.fasterxml.jackson.annotation.JsonBackReference; +/** + * Defines the PlaceInfo object which is based off the PlaceInfo table in the database. This class + * definition does NOT contain all fields in teh PlaceInfo db table. It only contains a small + * subset of the data. + */ @Entity @Table(name = "\"PLACE_INFO\"") public class PlaceInfo implements Serializable { diff --git a/src/main/java/com/climatetree/places/model/Type.java b/src/main/java/com/climatetree/places/model/Type.java index 85deb67..4a6514d 100644 --- a/src/main/java/com/climatetree/places/model/Type.java +++ b/src/main/java/com/climatetree/places/model/Type.java @@ -13,6 +13,9 @@ import com.fasterxml.jackson.annotation.JsonIgnore; +/** + * Mirrors the Type table from the database. + */ @Entity @Table(name = "\"TYPE\"") public class Type implements Serializable { diff --git a/src/main/java/com/climatetree/places/model/WwfMhtnam.java b/src/main/java/com/climatetree/places/model/WwfMhtnam.java index 69177be..d455d93 100644 --- a/src/main/java/com/climatetree/places/model/WwfMhtnam.java +++ b/src/main/java/com/climatetree/places/model/WwfMhtnam.java @@ -13,6 +13,9 @@ import com.fasterxml.jackson.annotation.JsonIgnore; +/** + * Mirrors the wwfmhtnam table from the database. + */ @Entity @Table(name = "\"WWF_MHTNAM\"") public class WwfMhtnam implements Serializable { diff --git a/src/main/java/com/climatetree/places/model/WwfRealm2.java b/src/main/java/com/climatetree/places/model/WwfRealm2.java index 58c3d92..63d03d8 100644 --- a/src/main/java/com/climatetree/places/model/WwfRealm2.java +++ b/src/main/java/com/climatetree/places/model/WwfRealm2.java @@ -13,6 +13,9 @@ import com.fasterxml.jackson.annotation.JsonIgnore; +/** + * Mirrors the wwfrealm2 table from the database. + */ @Entity @Table(name = "\"WWF_REALM2\"") public class WwfRealm2 implements Serializable { diff --git a/src/main/java/com/climatetree/places/service/NamesService.java b/src/main/java/com/climatetree/places/service/NamesService.java index 6ee5a59..2ec6981 100644 --- a/src/main/java/com/climatetree/places/service/NamesService.java +++ b/src/main/java/com/climatetree/places/service/NamesService.java @@ -12,6 +12,13 @@ public class NamesService { @Autowired NameRepository namesRepo; + /** + * Function that takes the provided place, changes it to all uppercase and calls the repository function + * to find places that contain the given search term. + * + * @param name search term + * @return GeoJson list of places + */ @Cacheable(value="places") public String getPlacesBySearchTerm(String name) { return namesRepo.getPlacesBySearchTerm(name.toUpperCase()); diff --git a/src/main/java/com/climatetree/places/service/PlacesService.java b/src/main/java/com/climatetree/places/service/PlacesService.java index f7d8a27..d04e71c 100644 --- a/src/main/java/com/climatetree/places/service/PlacesService.java +++ b/src/main/java/com/climatetree/places/service/PlacesService.java @@ -27,12 +27,22 @@ public class PlacesService { @Value("${default_population_end}") private int defaultEnd; - + /** + * Find a single Place from the database with the provided placeId. + * + * @param placeId place Id + * @return PlaceInfo object + */ public PlaceInfo findPlaceById(int placeId) { Optional placesOp = placesRepo.findById(placeId); return placesOp.isPresent() ? placesOp.get() : null; } + /** + * Find all Place from the database. + * + * @return List of PlaceInfo objects + */ public List findAllPlaces() { List places = new ArrayList<>(); placesRepo.findAll().forEach(p -> places.add(p)); @@ -41,7 +51,7 @@ public List findAllPlaces() { /** * Returns places that adhere to all of the following constraints when compared - * to the given place: 1. Between percentStart and percentEnd of the given place's population 2. + * to the given place: 1. Between 95% and 150% of the given place's population 2. * Is the same type (nation, state, county, or urban extent) as the given place. * * @param placeId the placeId of a Place @@ -64,11 +74,15 @@ public String getSimilarPlacesDefault(int placeId) { /** * Returns places that adhere to all of the following constraints when compared - * to the given place: 1. Between percentStart and percentEnd of the given place's population 2. - * Is the same type (nation, state, county, or urban extent) as the given place. + * to the given place: + * 1. Between percentStart and percentEnd of the given place's population + * 2. Between carbonStart and carbonEnd of the given place's carbon + * 3. Between perCapCarbonStart and perCapCarbonEnd of the given places per capita carbon. + * 4. Between popDensityStart and popDensityEnd of the given places population density. + * 5. Is the same type (nation, state, county, or urban extent) as the given place. * * @param placeId the placeId of a Place - * @return a list of PlaceDTO objects that are "similar" to the given PlaceDTO + * @return a GeoJson string listing all matching places */ public String getSimilarPlacesAdvanced(int placeId, Integer popStart, Integer popEnd, Integer carbonStart, Integer carbonEnd, Integer perCapCarbonStart,