Backend Integration - Node.js / Express
A minimal Express server that proxies all four PickPoint APIs. The key lives in an environment variable and never reaches the client.
1
Install dependencies
npm install express node-fetch ws2
Environment variables
# .env
PICKPOINT_KEY=your_key_here
PORT=3000Load with dotenv/config in development. In production set the variable in your hosting environment - never commit .env to git.
3
Geocoding endpoints
Three thin proxy handlers - forward, reverse, and address search. Query parameters from the client are forwarded to PickPoint unchanged:
// server.js
import express from 'express';
import { fetch } from 'node-fetch'; // or use built-in fetch (Node 18+)
import 'dotenv/config';
const app = express();
const KEY = process.env.PICKPOINT_KEY;
const BASE = 'https://api.pickpoint.io/v2';
app.use(express.json());
// ── Geocoding ──────────────────────────────────────────────────────────────
// Forward geocoding: GET /geo/forward?q=Eiffel+Tower&limit=5
app.get('/geo/forward', async (req, res) => {
const params = new URLSearchParams(req.query);
const up = await fetch(`${BASE}/geocode/forward?${params}`, {
headers: { 'X-Api-Key': KEY },
});
res.status(up.status).json(await up.json());
});
// Reverse geocoding: GET /geo/reverse?lat=48.85&lon=2.29&zoom=18
app.get('/geo/reverse', async (req, res) => {
const params = new URLSearchParams(req.query);
const up = await fetch(`${BASE}/geocode/reverse?${params}`, {
headers: { 'X-Api-Key': KEY },
});
res.status(up.status).json(await up.json());
});
// Address search: GET /geo/search?q=Baker+St&viewbox=…
app.get('/geo/search', async (req, res) => {
const params = new URLSearchParams(req.query);
const up = await fetch(`${BASE}/address/search?${params}`, {
headers: { 'X-Api-Key': KEY },
});
res.status(up.status).json(await up.json());
});4
Routing endpoints
// ── Routing ───────────────────────────────────────────────────────────────
// Route: POST /route { locations, costing, … }
app.post('/route', async (req, res) => {
const up = await fetch(`${BASE}/route`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Api-Key': KEY },
body: JSON.stringify(req.body),
});
res.status(up.status).json(await up.json());
});
// Optimized route: POST /route/optimized { locations, costing }
app.post('/route/optimized', async (req, res) => {
const up = await fetch(`${BASE}/route/optimized`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Api-Key': KEY },
body: JSON.stringify(req.body),
});
res.status(up.status).json(await up.json());
});5
Device tracking - REST
// ── Device Tracking - REST ────────────────────────────────────────────────
// List devices: GET /devices
app.get('/devices', async (req, res) => {
const up = await fetch(`${BASE}/devices`, { headers: { 'X-Api-Key': KEY } });
res.status(up.status).json(await up.json());
});
// Track history: GET /devices/:uid/tracks?from=…&to=…
app.get('/devices/:uid/tracks', async (req, res) => {
const params = new URLSearchParams(req.query);
const up = await fetch(`${BASE}/devices/${req.params.uid}/tracks?${params}`, {
headers: { 'X-Api-Key': KEY },
});
res.status(up.status).json(await up.json());
});
app.listen(process.env.PORT || 3000);6
Device tracking - WebSocket subscriber relay
For live tracking dashboards, the server subscribes to PickPoint using the API key and fans events out to browser clients over a plain WebSocket. The key never leaves the server:
// ── Device Tracking - WebSocket subscriber relay ─────────────────────────
import { WebSocketServer } from 'ws';
import { io } from 'socket.io-client';
const wss = new WebSocketServer({ port: 3001 });
wss.on('connection', (client, req) => {
// Expect: ws://your-server/tracking-relay?deviceUid=d_xxx
const deviceUid = new URL(req.url, 'http://x').searchParams.get('deviceUid');
if (!deviceUid) { client.close(1008, 'deviceUid required'); return; }
// Open one Socket.IO subscriber connection to PickPoint per client
const socket = io('wss://ws.pickpoint.io', {
transports: ['websocket'],
path: '/v2/tracking',
query: { 'x-api-key': KEY },
});
socket.on('connect', () => socket.emit('device:subscribe', { deviceUid }));
socket.on('location:added', (data) => {
if (client.readyState === 1) client.send(JSON.stringify(data));
});
client.on('close', () => socket.disconnect());
socket.on('error', () => client.close(1011));
});