diff --git a/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- false.bru b/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- false.bru new file mode 100644 index 0000000..59b4b1a --- /dev/null +++ b/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- false.bru @@ -0,0 +1,31 @@ +meta { + name: dronesWithCooling -> false + type: http + seq: 1 +} + +get { + url: {{API_BASE}}/dronesWithCooling/false + body: none + auth: inherit +} + +tests { + test("Status code is 200", function() { + expect(res.status).to.equal(200); + }); + + test("Response body is a JSON array", function() { + expect(res.getBody()).to.be.an('array'); + }); + + test("Array is not empty and contains numbers", function() { + const data = res.getBody(); + expect(data[0]).to.be.a('number'); // data should be in number + }); +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- illegal.bru b/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- illegal.bru new file mode 100644 index 0000000..949d45e --- /dev/null +++ b/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- illegal.bru @@ -0,0 +1,24 @@ +meta { + name: dronesWithCooling -> illegal + type: http + seq: 1 +} + +get { + url: {{API_BASE}}/dronesWithCooling/illegal + body: none + auth: inherit +} + +tests { + test("Status code is 400", function() { + expect(res.status).to.equal(400); + }); + + +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- true.bru b/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- true.bru new file mode 100644 index 0000000..295e3a2 --- /dev/null +++ b/ilp-cw-api/[GET] dronesWithCooling/dronesWithCooling -- true.bru @@ -0,0 +1,31 @@ +meta { + name: dronesWithCooling -> true + type: http + seq: 1 +} + +get { + url: {{API_BASE}}/dronesWithCooling/true + body: none + auth: inherit +} + +tests { + test("Status code is 200", function() { + expect(res.status).to.equal(200); + }); + + test("Response body is a JSON array", function() { + expect(res.getBody()).to.be.an('array'); + }); + + test("Array is not empty and contains numbers", function() { + const data = res.getBody(); + expect(data[0]).to.be.a('number'); // data should be in number + }); +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[GET] dronesWithCooling/folder.bru b/ilp-cw-api/[GET] dronesWithCooling/folder.bru new file mode 100644 index 0000000..2c9f0d3 --- /dev/null +++ b/ilp-cw-api/[GET] dronesWithCooling/folder.bru @@ -0,0 +1,8 @@ +meta { + name: [GET] dronesWithCooling + seq: 1 +} + +auth { + mode: inherit +} diff --git a/ilp-cw-api/bruno.json b/ilp-cw-api/bruno.json new file mode 100644 index 0000000..1fcef84 --- /dev/null +++ b/ilp-cw-api/bruno.json @@ -0,0 +1,9 @@ +{ + "version": "1", + "name": "ILP CW API Collection", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ] +} \ No newline at end of file diff --git a/ilp-cw-api/collection.bru b/ilp-cw-api/collection.bru new file mode 100644 index 0000000..ad0a499 --- /dev/null +++ b/ilp-cw-api/collection.bru @@ -0,0 +1,4 @@ +vars:pre-request { + BASE_URL: http://localhost:8080 + API_BASE: {{BASE_URL}}/api/v1 +} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/controller/ApiController.java b/src/main/java/io/github/js0ny/ilp_coursework/controller/ApiController.java index 51aeb63..7eb937f 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/controller/ApiController.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/controller/ApiController.java @@ -16,7 +16,7 @@ import io.github.js0ny.ilp_coursework.service.GpsCalculationService; /** * Main REST Controller for the ILP Coursework 1 application. *
- * This class handles all incoming HTTP requests for the API under {@code /api/v1} path. + * This class handles incoming HTTP requests for the API under {@code /api/v1} path (defined in CW1) * This is responsible for mapping requests to the appropriate service method and returning the results as responses. * The business logic is delegated to {@link GpsCalculationService} */ diff --git a/src/main/java/io/github/js0ny/ilp_coursework/controller/DroneController.java b/src/main/java/io/github/js0ny/ilp_coursework/controller/DroneController.java index e535b7f..411e3fe 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/controller/DroneController.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/controller/DroneController.java @@ -8,44 +8,51 @@ import org.springframework.web.client.RestTemplate; import java.util.Arrays; +/** + * Main Rest Controller for the ILP Coursework 2 application. + *
+ * This class handles incoming HTTP requests for the API under {@code /api/v1} path (defined in CW2) + * The business logic is delegated to {@link DroneInfoService} + */ @RestController @RequestMapping("/api/v1") public class DroneController { private final DroneInfoService droneService; - private final String baseUrl; private final RestTemplate restTemplate = new RestTemplate(); + /** + * Constructor of the {@code DroneController} with the business logic dependency {@code DroneInfoService} + *
+ * We handle the {@code baseUrl} here. Use a predefined URL if the environment variable {@code ILP_ENDPOINT}
+ * is not given.
+ *
+ * @param droneService The service component that contains all business logic
+ */
public DroneController(DroneInfoService droneService) {
this.droneService = droneService;
- String baseUrl = System.getenv("ILP_ENDPOINT");
- if (baseUrl == null || baseUrl.isBlank()) {
- this.baseUrl = "https://ilp-rest-2025-bvh6e9hschfagrgy.ukwest-01.azurewebsites.net/";
- } else {
- if (!baseUrl.endsWith("/")) {
- baseUrl += "/";
- }
- this.baseUrl = baseUrl;
- }
}
+ /**
+ * Handles GET requests to retrieve an array of drones (identified by id) that has the capability of cooling
+ *
+ * @param state The path variable that indicates the return should have or not have the capability
+ * @return An array of drone id with cooling capability.
+ */
@GetMapping("/dronesWithCooling/{state}")
-
- public int[] getDronesWithCoolingAbility(@PathVariable boolean state) {
-
- String droneUrl = baseUrl + "drones";
-
- DroneDto[] drones = restTemplate.getForObject(droneUrl, DroneDto[].class);
-
- if (drones == null) {
- return new int[]{};
- }
-
- return Arrays.stream(drones).
- filter(drone -> drone.capability().cooling() == state).
- mapToInt(drone -> Integer.parseInt(String.valueOf(drone.id()))).
- toArray();
+ public int[] getDronesWithCoolingCapability(@PathVariable boolean state) {
+ return droneService.dronesWithCooling(state);
}
+// @GetMapping("/droneDetails/{id}")
+// public DroneDto getDroneDetail(@PathVariable int id) {
+// String droneUrl = baseUrl + "drones";
+//
+// DroneDto[] drones = restTemplate.getForObject(droneUrl, DroneDto[].class);
+//
+// return new DroneDto();
+//
+// }
+
@PostMapping("queryAvailableDrones")
public int queryAvailableDrones() {
return 1;
diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/DroneDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/DroneDto.java
index 8282573..1997d26 100644
--- a/src/main/java/io/github/js0ny/ilp_coursework/data/DroneDto.java
+++ b/src/main/java/io/github/js0ny/ilp_coursework/data/DroneDto.java
@@ -5,6 +5,6 @@ package io.github.js0ny.ilp_coursework.data;
*/
public record DroneDto(
String name,
- int id,
+ String id,
DroneCapabilityDto capability) {
}
diff --git a/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java b/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java
index 9ac70eb..c70862c 100644
--- a/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java
+++ b/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java
@@ -1,8 +1,73 @@
package io.github.js0ny.ilp_coursework.service;
+import io.github.js0ny.ilp_coursework.data.DroneDto;
import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriBuilder;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.stream.Stream;
@Service
public class DroneInfoService {
+ private final String baseUrl;
+ private final String dronesEndpoint = "drones";
+
+ private final RestTemplate restTemplate = new RestTemplate();
+
+ /**
+ * Constructor, handles the base url here.
+ */
+ public DroneInfoService() {
+
+ String baseUrl = System.getenv("ILP_ENDPOINT");
+ if (baseUrl == null || baseUrl.isBlank()) {
+ this.baseUrl = "https://ilp-rest-2025-bvh6e9hschfagrgy.ukwest-01.azurewebsites.net/";
+ } else {
+ // Defensive: Add '/' to the end of the URL
+ if (!baseUrl.endsWith("/")) {
+ baseUrl += "/";
+ }
+ this.baseUrl = baseUrl;
+ }
+ }
+
+ /**
+ * Return an array of ids of drones with/without cooling capability
+ *
+ * @param state determines the capability filtering
+ * @return if {@code state} is true, return ids of drones with cooling capability, else without cooling
+ */
+ public int[] dronesWithCooling(boolean state) {
+ URI droneUrl = URI.create(baseUrl).resolve(dronesEndpoint);
+
+ DroneDto[] drones = restTemplate.getForObject(droneUrl, DroneDto[].class);
+
+ if (drones == null) {
+ return new int[]{};
+ }
+
+ return Arrays.stream(drones).
+ filter(drone -> drone.capability().cooling() == state).
+ mapToInt(drone -> Integer.parseInt(drone.id())).
+ toArray();
+ }
+
+ // TODO: This is function is WIP
+ public Stream