DocsJava

Backend Integration - Java / Spring Boot

Spring Boot with WebClient (from spring-boot-starter-webflux) gives you reactive, non-blocking HTTP calls to PickPoint alongside a standard MVC REST layer.

1

Dependencies (Maven)

<!-- pom.xml -->
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>  <!-- for WebClient -->
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
  </dependency>
</dependencies>
2

Configuration and PickPoint client bean

Store the key in an environment variable and inject it via @Value:

# application.properties
pickpoint.key=${PICKPOINT_KEY}    # loaded from env var
// PickPointClient.java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

@Component
public class PickPointClient {
    private final WebClient client;

    public PickPointClient(@Value("${pickpoint.key}") String key) {
        this.client = WebClient.builder()
            .baseUrl("https://api.pickpoint.io/v2")
            .defaultHeader("X-Api-Key", key)
            .build();
    }

    public WebClient get() { return client; }
}
3

Geocoding controller

// GeocodingController.java
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping("/geo")
public class GeocodingController {
    private final WebClient pp;

    public GeocodingController(PickPointClient client) {
        this.pp = client.get();
    }

    // GET /geo/forward?q=Eiffel+Tower&limit=5
    @GetMapping("/forward")
    public Mono<String> forward(@RequestParam String q,
                                @RequestParam(defaultValue = "5") int limit,
                                @RequestParam(required = false) String countrycodes,
                                @RequestParam(required = false) String viewbox) {
        return pp.get()
            .uri(b -> b.path("/geocode/forward")
                        .queryParam("q", q)
                        .queryParam("limit", limit)
                        .queryParamIfPresent("countrycodes", java.util.Optional.ofNullable(countrycodes))
                        .queryParamIfPresent("viewbox",      java.util.Optional.ofNullable(viewbox))
                        .build())
            .retrieve().bodyToMono(String.class);
    }

    // GET /geo/reverse?lat=48.85&lon=2.29&zoom=18
    @GetMapping("/reverse")
    public Mono<String> reverse(@RequestParam double lat,
                                @RequestParam double lon,
                                @RequestParam(defaultValue = "18") int zoom) {
        return pp.get()
            .uri(b -> b.path("/geocode/reverse")
                        .queryParam("lat", lat).queryParam("lon", lon).queryParam("zoom", zoom)
                        .build())
            .retrieve().bodyToMono(String.class);
    }

    // GET /geo/search?q=Baker+St&viewbox=…
    @GetMapping("/search")
    public Mono<String> search(@RequestParam String q,
                               @RequestParam(required = false) String viewbox,
                               @RequestParam(defaultValue = "6") int limit) {
        return pp.get()
            .uri(b -> b.path("/address/search")
                        .queryParam("q", q).queryParam("limit", limit)
                        .queryParamIfPresent("viewbox", java.util.Optional.ofNullable(viewbox))
                        .build())
            .retrieve().bodyToMono(String.class);
    }
}
4

Routing controller

// RoutingController.java
@RestController
public class RoutingController {
    private final WebClient pp;

    public RoutingController(PickPointClient client) { this.pp = client.get(); }

    // POST /route
    @PostMapping("/route")
    public Mono<String> route(@RequestBody String body) {
        return pp.post().uri("/route")
            .header("Content-Type", "application/json")
            .bodyValue(body)
            .retrieve().bodyToMono(String.class);
    }

    // POST /route/optimized
    @PostMapping("/route/optimized")
    public Mono<String> routeOptimized(@RequestBody String body) {
        return pp.post().uri("/route/optimized")
            .header("Content-Type", "application/json")
            .bodyValue(body)
            .retrieve().bodyToMono(String.class);
    }
}
5

Device tracking - REST

// DeviceController.java
@RestController
@RequestMapping("/devices")
public class DeviceController {
    private final WebClient pp;

    public DeviceController(PickPointClient client) { this.pp = client.get(); }

    @GetMapping
    public Mono<String> list() {
        return pp.get().uri("/devices").retrieve().bodyToMono(String.class);
    }

    @GetMapping("/{uid}/tracks")
    public Mono<String> tracks(@PathVariable String uid,
                               @RequestParam(required = false) String from,
                               @RequestParam(required = false) String to) {
        return pp.get()
            .uri(b -> b.path("/devices/{uid}/tracks")
                        .queryParamIfPresent("from", java.util.Optional.ofNullable(from))
                        .queryParamIfPresent("to",   java.util.Optional.ofNullable(to))
                        .build(uid))
            .retrieve().bodyToMono(String.class);
    }
}

For the WebSocket subscriber relay, implement a WebSocketHandler that opens a Reactor Netty connection to wss://ws.pickpoint.io with the API key and pipes location:added events to the client session.

← OverviewNode.js →