Laravel Server Proxy
For PHP idioms see ../integrations/php.md.
Route
php
// routes/api.php
use App\Http\Controllers\TileController;
Route::get('/tiles/{z}/{x}/{y}.pbf', [TileController::class, 'show'])
->where(['z' => '[0-9]+', 'x' => '[0-9]+', 'y' => '[0-9]+']);Controller
php
<?php
// app/Http/Controllers/TileController.php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;
class TileController extends Controller
{
public function show(int $z, int $x, int $y): Response
{
$key = config('services.mfd.srv_key');
$secret = config('services.mfd.srv_secret');
$path = "/tiles/$z/$x/$y.pbf";
$ts = (string) time();
$sig = hash_hmac('sha256', "GET\n$path\n$ts", $secret);
try {
$up = Http::timeout(10)->withHeaders([
'Authorization' => "Bearer $key",
'X-MFD-Timestamp' => $ts,
'X-MFD-Signature' => $sig,
])->get("https://tiles.mapsfordevs.com$path");
} catch (\Throwable $e) {
Log::error('[mfd] tile fetch failed', ['err' => $e->getMessage()]);
return response('', 502);
}
return response($up->body(), $up->status(), [
'Content-Type' => 'application/x-protobuf',
'Cache-Control' => 'public, max-age=86400',
]);
}
}Config
php
// config/services.php
return [
'mfd' => [
'srv_key' => env('MFD_SRV_KEY'),
'srv_secret' => env('MFD_SRV_SECRET'),
],
];bash
# .env
MFD_SRV_KEY=mfd_srv_xxx
MFD_SRV_SECRET=hex_secret_hereCache layer (Redis)
php
public function show(int $z, int $x, int $y): Response
{
$cacheKey = "mfd:tile:$z:$x:$y";
$body = \Cache::remember($cacheKey, 86400, fn () => $this->fetchUpstream($z, $x, $y));
return response($body, 200, [
'Content-Type' => 'application/x-protobuf',
'Cache-Control' => 'public, max-age=86400',
]);
}Octane (high-perf) gotchas
- Octane keeps the framework boot in memory. Avoid setting global state from
.envper request — useconfig(...)(cached at boot). - HTTP client connection-reuse — Laravel HTTP client uses Guzzle; in Octane it shares per-worker.
Geocoding service
php
// app/Services/MapsForDevsService.php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class MapsForDevsService
{
public function __construct(private string $apiKey) {}
public function geocode(string $query, ?string $country = null, int $limit = 5): array
{
$params = ['q' => $query, 'limit' => $limit];
if ($country) $params['country'] = $country;
$resp = Http::withToken($this->apiKey)
->timeout(10)
->get('https://api.mapsfordevs.com/geocode/forward', $params);
$body = $resp->json();
if (!($body['ok'] ?? false)) throw new \RuntimeException($body['error'] ?? 'mfd error');
return $body['items'];
}
}Bind in a service provider:
php
$this->app->bind(MapsForDevsService::class, fn () =>
new MapsForDevsService(config('services.mfd.pub_key'))
);