Xây dựng Store Locator tại Việt Nam bằng MapLibre và Geocoding API
Hướng dẫn thực tế với Next.js: tìm địa chỉ Việt Nam, resolve tọa độ, xếp hạng chi nhánh gần nhất và hiển thị marker bằng MapLibre mà không làm lộ API key.
Một Store Locator nhìn qua khá đơn giản: hiển thị các chi nhánh trên bản đồ và giúp người dùng tìm địa điểm gần nhất. Nhưng để chạy tốt trên production, tính năng này phải nối ba bài toán khác nhau:
- Chuyển địa chỉ tiếng Việt thành tọa độ đáng tin cậy.
- Xếp hạng chi nhánh theo khoảng cách từ vị trí người dùng.
- Hiển thị kết quả mà không làm lộ API key trong code trình duyệt.
Bài này xây dựng flow đó bằng Next.js, MapLibre GL JS và hai endpoint
GoGoDuk đã public:
/v1/suggest và
/v1/place/resolve.
Kiến trúc tổng thể
Nên tách riêng lớp hiển thị bản đồ, lớp xử lý địa chỉ và dữ liệu chi nhánh:
Browser chỉ gọi route backend của ứng dụng. Backend mới thêm X-API-Key, nhờ
đó key không xuất hiện trong JavaScript bundle hoặc request gọi trực tiếp từ
trình duyệt sang nhà cung cấp API.
Thiết kế dữ liệu chi nhánh
Hãy geocode địa chỉ chi nhánh khi tạo hoặc cập nhật record, không geocode lại mỗi lần khách hàng tìm kiếm. Lưu tọa độ ở dạng số và giữ địa chỉ gốc để hiển thị:
Nếu có hàng nghìn điểm, nên lưu trong PostgreSQL/PostGIS và query bằng spatial index. Với vài chục hoặc vài trăm chi nhánh, xếp hạng một tập dữ liệu nhỏ trong application thường đã đủ.
Proxy autocomplete qua Next.js
Tạo file app/api/locations/suggest/route.ts:
Lưu key trong biến môi trường chỉ dành cho server:
Không thêm prefix NEXT_PUBLIC_ vào API key. Prefix này chủ động đưa giá trị
vào browser bundle.
Resolve địa điểm người dùng đã chọn
Kết quả autocomplete chứa placeId ổn định. Sau khi user chọn một item, resolve
ID đó thành tọa độ thông qua một server route khác:
Chỉ resolve sau khi user chọn địa điểm. Gọi place resolve theo từng phím gõ sẽ tăng latency và tốn quota nhưng không làm dropdown tốt hơn.
Xếp hạng chi nhánh gần nhất
Với khoảng cách đường chim bay, có thể dùng công thức Haversine:
Haversine phù hợp để tạo shortlist nhưng không phải khoảng cách lái xe. Sông, cầu, đường một chiều hoặc địa hình có thể khiến chi nhánh gần nhất theo đường thẳng mất nhiều thời gian di chuyển hơn. UI nên ghi "cách khoảng X km"; nếu thời gian di chuyển ảnh hưởng quyết định nghiệp vụ, hãy bổ sung routing hoặc distance matrix.
Hiển thị kết quả bằng MapLibre
Cài MapLibre:
Map chỉ nhận tọa độ và dữ liệu hiển thị:
MapLibre là renderer, không tự cung cấp autocomplete địa chỉ. Style có thể đến từ tile server của bạn hoặc một provider tương thích, còn GoGoDuk xử lý tìm kiếm địa chỉ Việt Nam và place resolution. Khác với GoGoDuk API key, URL map style dùng trong browser được phép là cấu hình public.
Checklist trước khi lên production
- Debounce autocomplete khoảng 200-300 ms.
- Hủy request cũ khi input thay đổi nhanh.
- Yêu cầu user chọn suggestion thay vì tin hoàn toàn vào text tự do.
- Giữ GoGoDuk API key trong biến môi trường server-only.
- Cache dữ liệu chi nhánh ổn định và geocode trước địa chỉ chi nhánh.
- Hiển thị quận/huyện hoặc thành phố khi nhiều chi nhánh trùng tên.
- Xem khoảng cách Haversine là ước lượng, không phải thời gian di chuyển.
- Luôn có list view bên cạnh bản đồ để hỗ trợ mobile và accessibility.
Store Locator khác Delivery Zone thế nào?
Store Locator xếp hạng các điểm chi nhánh rời rạc. Delivery Zone kiểm tra khách hàng có nằm trong một polygon phục vụ hay không, sau đó có thể áp phí theo vùng. Nếu bước tiếp theo của bạn là vùng giao hàng, đọc Hướng dẫn xây dựng Delivery Zones tại Việt Nam.
Để đi sâu vào UX autocomplete và validation, xem Address Autocomplete API Việt Nam.
Bắt đầu
Tạo API key miễn phí, thử một địa chỉ khách hàng thật qua
/v1/suggest, resolve placeId được chọn, rồi xếp
hạng kết quả với một danh sách chi nhánh nhỏ. Chừng đó đã đủ để ship phiên bản
Store Locator đầu tiên mà không khóa phần tìm kiếm địa chỉ vào một map renderer
cụ thể.
Muốn dùng GoGoDuk?
Miễn phí trọn đời — 100 request/ngày mỗi tài khoản, không cần thẻ tín dụng. Giới hạn cao hơn theo yêu cầu.
Đăng ký →