API نقشه راهیار
با این API میتوانید نقشه ایران، جستوجوی بیش از ۴۰ هزار مکان، ژئوکد معکوس و کاشیهای برداری را در برنامه خودتان استفاده کنید؛ بدون وابستگی به هیچ سرویس خارجی. همه دادهها از همین میزبان خوانده میشوند.
خودمیزبان
هیچ درخواستی به سرویس نقشه یا جستوجوی بیرونی ارسال نمیشود؛ داده از OpenStreetMap روی همین سرور است.
فارسی و راستبهچپ
جستوجو با حروف فارسی و عربی، اعداد فارسی و نیمفاصله یکسان رفتار میکند و نامها را فارسی برمیگرداند.
مناسب فلاتر
خروجی JSON ساده و CORS باز؛ کافی است با http درخواست بزنید و مکان تراکنش را ثبت کنید.
/api/v1 در دسترس قرار دارد. نمونههای این صفحه بهصورت خودکار با دامنه فعلی شما پر میشوند.شروع در سه قدم
۱) آدرس پایه را بگیرید
/api/v1این نشانی فهرست سرویسها را برمیگرداند و بهترین راه برای بررسی درستی نصب است.
۲) یک جستوجوی نمونه اجرا کنید
curl "/api/v1/search?q=مشهد&limit=3"
۳) پاسخ را بخوانید
{
"query": "مشهد",
"count": 3,
"results": [
{
"id": "iran-26038568",
"name": "مشهد",
"nameEn": "Mashhad",
"kind": "city",
"province": "خراسان رضوی",
"coordinates": [59.60592, 36.29749],
"distanceMeters": 0
}
],
"attribution": "© OpenStreetMap contributors, ODbL 1.0"
}
کلید API
استفاده عمومی از API بدون کلید هم ممکن است، اما ثبت کلید برای برنامه شما چند مزیت دارد: شناسایی مصرف، سقف روزانه قابل تنظیم و امکان مدیریت دسترسی در آینده.
| روش ارسال | نمونه |
|---|---|
| پارامتر آدرس | ?api_key=rahyar_... |
هدر X-API-Key | X-API-Key: rahyar_... |
| هدر Bearer | Authorization: Bearer rahyar_... |
کلیدها با پیشوند rahyar_ شروع میشوند. کلید واقعی فقط یکبار، هنگام تأیید درخواست، نشان داده میشود و روی سرور فقط درهمسازی SHA-256 آن نگه داشته میشود.
RAHYAR_REQUIRE_API_KEY=true کلید را برای همه فراخوانیهای داده اجباری کند. در آن حالت درخواست بدون کلید با خطای ۴۰۱ پاسخ داده میشود.جستوجوی مکان
/api/v1/search?q=مشهدجستوجوی رتبهبندیشده مکانها با همان الگوریتم و ترتیبی که نقشه راهیار نمایش میدهد. ورودی میتواند فارسی، انگلیسی یا ترکیبی از هر دو باشد.
| پارامتر | الزامی | توضیح |
|---|---|---|
q | بله | متن جستوجو تا ۱۲۰ نویسه. |
limit | خیر | تعداد نتایج ۱ تا ۱۰۰، پیشفرض ۱۲. |
offset | خیر | جابهجایی برای صفحهبندی. |
kind | خیر | فیلتر نوع مکان: city, park, hospital, university و غیره. |
province | خیر | فیلتر استان، مثلاً تهران. |
bbox | خیر | محدوده جغرافیایی به شکل west,south,east,north. |
lat, lon | خیر | نقطه مرجع؛ distanceMeters را فعال میکند. |
radius | خیر | حداکثر فاصله از نقطه مرجع بر حسب متر. |
sort | خیر | distance برای مرتبسازی بر اساس فاصله (نیاز به lat/lon). |
نمونهها
# نزدیکترین پارکها به یک نقطه
curl "/api/v1/search?q=پارک&lat=35.75&lon=51.4&sort=distance&limit=5"
# فقط بیمارستانها
curl "/api/v1/search?q=بیمارستان&kind=hospital&limit=10"
# جستوجوی انگلیسی
curl "/api/v1/search?q=tehran&limit=2"
دریافت یک مکان
/api/v1/places/{id}شناسهای که از جستوجو یا ژئوکد معکوس گرفتهاید را جای {id} بگذارید.
curl "/api/v1/places/iran-26038568"
شناسه نامعتبر با 404 و بدنه place_not_found پاسخ داده میشود.
ژئوکد معکوس
/api/v1/reverse?lat=35.700&lon=51.390مختصات را به نزدیکترین مکانهای نامدار تبدیل میکند. این سرویس برای برچسبگذاری مکان تراکنش یا هر رویداد مکانی مناسب است.
| پارامتر | الزامی | توضیح |
|---|---|---|
lat, lon | بله | عرض و طول جغرافیایی. |
radius | خیر | شعاع جستوجو بر حسب متر؛ پیشفرض ۱۵۰، حداکثر ۵۰۰۰۰. |
limit | خیر | تعداد نتایج ۱ تا ۵۰، پیشفرض ۵. |
curl "/api/v1/reverse?lat=35.700&lon=51.390&radius=500"
نتایج بر اساس فاصله مرتباند و هر مورد distanceMeters دارد. اگر در شعاع چیزی نباشد، results خالی است.
مکانهای اطراف
/api/v1/nearby?lat=35.7&lon=51.39&radius=1000فهرست مکانها درون یک شعاع، قابل فیلتر با kind و مرتبشده بر اساس فاصله.
# دانشگاههای نزدیک در شعاع ۵ کیلومتر
curl "/api/v1/nearby?lat=35.7&lon=51.39&radius=5000&kind=university"
پوشش نقشه
/api/v1/coverageمحدوده جغرافیایی، سقف زوم و تعداد مکانها را میدهد تا برنامه شما بداند کجا جزئیات خیابان وجود دارد.
| فیلد | معنی |
|---|---|
bounds | محدوده کشور به شکل [west,south,east,north]. |
maxZoom | عمیقترین زوم کاشیهای برداری (۱۵). |
plainMaxZoom | زوم مجاز بیرون از مناطق دارای جزئیات (۱۳). |
detailMaxZoom | زوم مجاز داخل مناطق دارای جزئیات (۱۸). |
detailAreas | فهرست مستطیلهایی که داده خیابان و ساختمان دارند. |
counts | تعداد مکانهای محلی، ملی و مجموع. |
کاشیهای برداری
/api/v1/tiles/{z}/{x}/{y}.mvtکاشیهای استاندارد Mapbox Vector Tile با کدگذاری gzip، از زوم ۰ تا ۱۵. لایهها: roads, buildings, landuse, earth, water, places, pois.
این آدرس مستقیماً در MapLibre، OpenLayers و QGIS (با XYZ) قابل استفاده است و به کلاینت PMTiles نیاز ندارد. کاشیهای خالی با 204 پاسخ داده میشوند.
const map = new maplibregl.Map({
container: 'map',
style: {
version: 8,
glyphs: '/fonts/{fontstack}/{range}.pbf',
sprite: '/sprites/light',
sources: {
rahyar: {
type: 'vector',
tiles: ['/api/v1/tiles/{z}/{x}/{y}.mvt'],
maxzoom: 15
}
},
layers: []
}
});
استایل آماده MapLibre
/api/v1/style.jsonبرای نمایش همان ظاهر نقشه راهیار، کافی است این نشانی را بهجای آبجکت استایل بدهید:
const map = new maplibregl.Map({
container: 'map',
style: '/api/v1/style.json',
center: [53.7, 32.4],
zoom: 5
});
مسیریابی
/api/v1/routeمسیریابی در مرورگر و روی دستگاه کاربر انجام میشود، نه روی سرور. شبکه جاده تهران به تنهایی نزدیک به ۴۷۰ مگابایت حافظه PHP در هر درخواست نیاز دارد که میزبان اشتراکی نمیتواند تأمین کند.
این نشانی، مدل محاسبه و نشانی فایلهای شبکه جاده را برمیگرداند. اگر مسیریابی سمت سرور لازم دارید، باید یک سرویس Node جدا راهاندازی کنید.
| فایل | کاربرد |
|---|---|
/data/tehran-roads.json.gz | شبکه کامل خیابانهای تهران. |
/data/iran-roads.json.gz | شبکه بینشهری جادههای اصلی. |
استفاده در فلاتر
برای ثبت مکان تراکنشها، مختصات را ذخیره کنید و با ژئوکد معکوس نام مکان را بگیرید:
import 'dart:convert';
import 'package:http/http.dart' as http;
class RahyarApi {
RahyarApi(this.baseUrl, {this.apiKey});
final String baseUrl; // مثلاً https://maps.example.com
final String? apiKey;
Future<Map<String, dynamic>> _get(String path) async {
final uri = Uri.parse('$baseUrl/api/v1$path');
final response = await http.get(uri, headers: {
if (apiKey != null) 'X-API-Key': apiKey!,
});
if (response.statusCode != 200) {
throw Exception('Rahyar API ${response.statusCode}: ${response.body}');
}
return jsonDecode(utf8.decode(response.bodyBytes)) as Map<String, dynamic>;
}
Future<List<dynamic>> search(String query) async {
final body = await _get('/search?q=${Uri.encodeQueryComponent(query)}');
return body['results'] as List<dynamic>;
}
// نام نزدیکترین مکان به مختصات تراکنش
Future<String?> labelFor(double lat, double lon) async {
final body = await _get('/reverse?lat=$lat&lon=$lon&radius=500');
final results = body['results'] as List<dynamic>;
if (results.isEmpty) return null;
return results.first['name'] as String?;
}
}
برای نمایش نقشه در فلاتر میتوانید از WebView با نشانی /?place={id} یا از style.json همین میزبان در maplibre_gl استفاده کنید.
خطاها
بدنه خطا همیشه JSON است و شامل کد ماشینخوان و توضیح فارسی:
{ "error": "invalid_api_key", "message": "کلید API معتبر نیست.", "api": "v1" }
| کد HTTP | معنی |
|---|---|
401 | کلید لازم است یا معتبر نیست (api_key_required, invalid_api_key). |
403 | کلید غیرفعال شده (api_key_revoked). |
404 | مسیر یا مکان پیدا نشد. |
405 | متد مجاز نیست؛ فقط GET/HEAD/OPTIONS. |
422 | پارامتر لازم نیست یا نامعتبر است. |
429 | سقف روزانه کلید تمام شده (quota_exceeded). |
503 | داده یا پیکربندی سرویس آماده نیست. |
محدودیتها و مجوز
- داده مکانها و کاشیها از OpenStreetMap است و تحت مجوز ODbL 1.0 عرضه میشود. نمایش عبارت
© OpenStreetMap contributorsو پیوند به/data/NOTICE.txtالزامی است. - پاسخها ETag و Cache-Control دارند؛ برای کاهش بار، نتایج تکراری را کش کنید و درخواست شرطی با
If-None-Matchبفرستید. - CORS برای همه مبدأها باز است؛ در فلاتر وب و مرورگر نیازی به پروکسی نیست.
- مسیرهای
/coverage,/style.jsonو/routeاطلاعاتی هستند و به کلید نیاز ندارند. - محدودیت روزانه پیشفرض هر کلید ۲۰ هزار درخواست است و مدیر میتواند آن را تغییر دهد.
پرسشهای متداول
آیا برای استفاده باید کلید بگیرم؟
خیر، در حالت پیشفرض نه. کلید برای شناسایی مصرف و مدیریت بهتر است. مدیر میزبان میتواند آن را اجباری کند.
چرا مسیریابی بهصورت HTTP نیست؟
چون شبکه جاده روی میزبان اشتراکی PHP در حافظه جا نمیشود. مسیریابی فعلی روی دستگاه کاربر و با همان داده محلی انجام میشود.
چطور مکان دقیق تراکنش را ذخیره کنم؟
مختصات lat/lon را همراه تراکنش نگه دارید و برای نمایش نام، /reverse را بزنید. شناسه مکان برگشتی را هم ذخیره کنید تا بعداً با /places/{id} جزئیات بگیرید.
آیا جستوجوی فارسی و عربی فرق میکند؟
نه؛ ی و ک عربی، اعداد فارسی و نیمفاصله در زمان جستوجو یکسانسازی میشوند.