In this post we will be integrating multiple mapbox api's like Search, Retrieve, Geocoding, Reverse Geocoding, POIs, Directions.
React Native is a popular framework for building mobile applications using JavaScript and the Mapbox API is a set of APIs and SDKs for building custom maps and location-based applications. Mapbox provides several APIs that allow developers to add map functionality to their applications, including search, retrieve, geocoding, reverse geocoding, POIs, and directions. Here's a brief overview of each API:
Search API: Mapbox's Search API allows you to query for places based on a search term or location. You can search for places such as businesses, landmarks, and addresses. The Search API returns a list of suggested places that match your query.
Retrieve API: Mapbox's Retrieve API allows you to retrieve detailed information about a specific place. You can retrieve information such as the place's address, phone number, website, and hours of operation.
Geocoding API: Mapbox's Geocoding API allows you to convert an address or place name into geographic coordinates (latitude and longitude). This API can be used to geocode addresses for use in mapping applications.
Reverse Geocoding API: Mapbox's Reverse Geocoding API allows you to convert geographic coordinates into an address or place name. This API can be used to display the name of a location on a map or to find the nearest address to a set of coordinates.
POI (Point of Interest) API: Mapbox's POI API allows you to search for and display points of interest on a map. You can search for POIs such as restaurants, gas stations, and parks.
Directions API: Mapbox's Directions API allows you to get directions between two or more locations. You can specify the mode of transportation (driving, walking, cycling, or transit) and the API will return turn-by-turn directions and estimated travel time.
To use these APIs in your React Native application, you will need to install the Mapbox SDK and obtain an API key from Mapbox. You can then make API requests using the Mapbox SDK's APIs or by using an HTTP client library such as Axios.
Directions
The Mapbox Directions API will show you how to get where you're going. With the Directions API, you can:
Calculate optimal driving, walking, and cycling routes using traffic- and incident-aware routing
Produce turn-by-turn instructions
Produce routes with up to 25 coordinates for the driving, driving-traffic, walking, and cycling profiles
Calculate routes for electric vehicles to reach destinations with optimal charging stops as well as battery prediction
https://docs.mapbox.com/api/navigation/directions/
Search
The Mapbox Search Service includes two APIs: the Mapbox Geocoding API and the Mapbox Search API(to enable mapbox search feature dev need to connect with mapbox sales for enabling it).
https://docs.mapbox.com/api/search/
1. Geocoding
The Mapbox Geocoding API allows you to do forward and reverse geocoding operations. Forward Geocoding takes text in the form of an address or place and converts it to geographic coordinates (latitude/longitude). Reverse geocoding takes geographic coordinates (latitude/longitude) and converts it into an address or place in text form.
https://docs.mapbox.com/api/search/geocoding/
2. Search
The Mapbox Search API enables search suggestions and feature retrieval for an interactive Search experience.
The Search API includes six different endpoints: /suggest, /retrieve, /forward, /permanent/forward, /reverse, and /permanent/reverse.
https://docs.mapbox.com/api/search/search/
API COLLECTION:
- GET(Direction api)
curl --location --request GET 'https://api.mapbox.com/directions/v5/mapbox/driving/-122.42,37.78;-77.03,38.91?geometries=geojson&access_token=pk.eyJ1IjoiZGVlcGFrMTIyMSIsImEiOiJjbDhiZXQ5cmEwcXhzM3FvNTFhNDNpNms3In0.x6FPXW7P3lIWTKPs6PMaJA'
- GET(Gives suggestion list of inputted text)
curl --location --request GET 'https://api.mapbox.com/search/v1/suggest/mec?language=ar&session_token=&country=SA&access_token=sk.eyJ1Ijoid2FzYWx0bWFwcyIsImEiOiJjbGM2OXUzODkwMjhhM3BtZ2x4dmtvd21hIn0.uLcik68kLtKKCqKvpLzD6A'
- POST(Retrieve suggested item's more info)
curl --location -g --request POST 'https://api.mapbox.com/search/v1/retrieve?session_token=[GENERATED-UUID]&access_token=pk.eyJ1Ijoid2FzYWx0bWFwcyIsImEiOiJjbDlkdHhtOW8xbjVzM3dwOGFzcm0xbmI1In0.aKPN7qWIPGX8hbKcOV_hbA' \
--header 'Content-Type: application/json' \
--data-raw '{
"id": "GpLnHR-w8BMB2AxARJ1nZYvXueJQn4PQ1GKu3mT11_5uLytWHFBsI7LnCBhFmrtosuecy3HLMPRTbcte0bBJYqe4XmLO3DCCJoeqcrJwzBeK_n1Hrfq5zBS034KiwOObxR1Wmv4MTKFW0vanZjPlO3j9QOJZJLjrIaW2Olfdc91WmEAqB7yv2TxTpZFfOMmrvqhVWtRJyB_tgq5NzndtDxlG1wsXAl_1urUn0VsmEe3VpBkyOm6MnBZwUKWMq3RELeTduG4jG1zNElVvjjS_aiZfg_VXsfbhit5J4efCwiResxecDKrLlaDbLRuDGOeFOC8XCb5_eM1O35zZEi7U_HujRi_v5bMinyfvnQfo0kWJTIVmgvHyfUS5eyzOzdaaEWwoblfFfo4MxQA-j_wdFOMmsDvyHL9BwOaGufjaWuN-6gW0eZBqrY3tJnwfYgY9liRlUMdc8FxCuzg0D0QDCduFp8H2nUXI8ALZV2wIN510XgJAg3r80T85quTp80dBRyXvP4R7_9XG5mFXcflsRTeCZsjaRDBVC400ff-06rHPVBKtHtuIGqjWE7p9AEjf17RX9fwY8MFocA1JZrRrTDwHQFFBCV-wbcbUGL4s50BLn2jkkClPNr0-yiDt14AJg3JP0NDPJa73hjRtC2i5Jm74VqPy_XK632rgeMHKB8IDyabJjKPJvQk-EPE0LL3YgR-JH4wC4UCOMOxPciuBoZ4hxF3GChra-fiQRVF6M6c4N5r323922nyIYIv9sX1RS3c7DcnWRZ0KsXc5PWD-hd8ZR2uLN8nMVwwak2u0axjh2WzrUeD27Yk_5ZIhNxxWsH8VNNyVfMT5Ig2FT3_FYJj-Hb-KwSv629ohr1kEWeNWH4LhI_jmCAIzzleoVk3j7XrRKtUb8lUqWye4ah7f5GceHl4gANhPM2fdDMZDbO8tUOuepEWoO5BQRGJiChM4h-85cJ5JO7zDSzsaA1WwFQf9EyPdhEaJB8tN8UNAmpF4vtpM3HsvGmnv7AY63oLj0VkusigK-UEPvxu4_3bixk6PDCTwZXsJEpYB_TcXwKXmrPnKbrYmDqt9psvWG8SlziKs3YYyMIs5HoP1eVQpQGmR06YQ8hxw8O2XFQdRUKvptHYDiwuY03R2YGDspiYu1UD2fj7muraZNZsk-VWFjRfuztunsTe-vtuJtqdyilyXGpWgft9t14GXOl-F5HfnMqYP_tzlCW1CedCchrRG_WdDL0IWfxF_LhkK4BjSoh7o2-pb4gLxEJ-k0--xYRIxPZgpRZ9YrHdNi8hXYsPQFwv6x91nw7jSPAZXcwvgYb8VCOgJrca9D6BHzXAD1VXXKi-9h9LnYkUA1cGKQ1p_o4sQU2OLslOD3jgNTOVRzePfkvbqkjXeiIdWlzuz2o2fvdyaxym7jWR-1qiIFzeXIaCeT746pEmLBw=="
}'
- GET(Gives list of POIs)
curl --location --request GET 'https://api.mapbox.com/geocoding/v5/mapbox.places/fast food;college;university.json?type=poi&proximity=-74.70850,40.78375&access_token=pk.eyJ1IjoiZGVlcGFrMTIyMSIsImEiOiJjbDhiZXQ5cmEwcXhzM3FvNTFhNDNpNms3In0.x6FPXW7P3lIWTKPs6PMaJA'
- GET(Gives info about inputed text))
curl --location --request GET 'https://api.mapbox.com/geocoding/v5/mapbox.places/Los%20Angeles.json?access_token=pk.eyJ1Ijoid2FzYWx0bWFwcyIsImEiOiJjbDlkdHhtOW8xbjVzM3dwOGFzcm0xbmI1In0.aKPN7qWIPGX8hbKcOV_hbA'
- GET(Gives info about provided coordinates)
curl --location --request GET 'https://api.mapbox.com/search/v1/reverse/13.329048,52.51258?language=en&access_token=pk.eyJ1Ijoid2FzYWx0bWFwcyIsImEiOiJjbDlkdHhtOW8xbjVzM3dwOGFzcm0xbmI1In0.aKPN7qWIPGX8hbKcOV_hbA&country=SA'
Code:
Mapview.js
import MapboxGL, {Camera, PointAnnotation, MarkerView} from '@rnmapbox/maps';
import {MAP_BOX_ACCESS_TOKEN} from '../../utils/constants/constants';
import * as turf from '@turf/turf';
import SearchLocationInput from './SearchLocationInput';
MapboxGL.setAccessToken(MAP_BOX_ACCESS_TOKEN);
const ANNOTATION_SIZE = 30;
const MAP_VIEW = ({navigation}) => {
let _map = useRef(null);
let camera = useRef(null);
let pointAnnotation = useRef(null);
const [poiList, setpoiList] = useState([]);
const [currentPinCoordinate, setcurrentPinCoordinate] = useState([
46.6753, 24.7136,
]);
// const [currentSelectedPoi, setCurrentSelectedPoi] = useState({});
const [routeGeoJOSN, setrouteGeoJOSN] = useState();
const [centerOfLineString, setcenterOfLineString] = useState();
useEffect(() => {
if (currentPinCoordinate && currentPinCoordinate.length > 0) {
console.log('currentPinCoordinate', currentPinCoordinate);
}
}, [currentPinCoordinate]);
const defaultCamera = {
centerCoordinate: [46.6753, 24.7136],
zoomLevel: 15,
};
const onPressInterestSite = async name => {
let response = await fetch(
'https://api.mapbox.com/geocoding/v5/mapbox.places/mosque.json?' +
new URLSearchParams({
type: 'poi',
proximity: '46.6753,24.7136',
access_token: MAP_BOX_ACCESS_TOKEN,
limit: 10,
}),
);
let data = await response.json();
console.log('onPressInterestSite', data);
setpoiList(data);
};
const onSelectPoiFunc = async payload => {
console.log('poi:', payload);
let coords = payload?.center;
// setCurrentSelectedPoi(payload);
let response = await fetch(
`https://api.mapbox.com/directions/v5/mapbox/driving/${currentPinCoordinate[0]},${currentPinCoordinate[1]};${coords[0]},${coords[1]}?` +
new URLSearchParams({
geometries: 'geojson',
access_token: MAP_BOX_ACCESS_TOKEN,
}),
);
let data = await response.json();
let lineStringGeoJSON = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: data?.routes[0]?.geometry,
},
],
};
setrouteGeoJOSN(lineStringGeoJSON);
let allCoordinates = lineStringGeoJSON?.features[0]?.geometry?.coordinates;
console.log(
'onPressInterestSiteDirection',
data,
lineStringGeoJSON,
allCoordinates[Math.round(allCoordinates.length / 2)],
);
let featuresCenter = turf.points(allCoordinates);
let center = turf.center(featuresCenter);
setcenterOfLineString(center?.geometry?.coordinates);
};
const RouteLineString = () => (
<MapboxGL.ShapeSource id="routeLine" shape={routeGeoJOSN}>
<MapboxGL.LineLayer id="lines" style={styles.mapBox} />
</MapboxGL.ShapeSource>
);
const CustomCalloutView = ({message}) => {
return (
<View style={styles.callOutContainer}>
<View style={styles.callOutInner} />
<View style={[styles.triangle, styles.arrowDown]} />
</View>
);
};
const onDragEnd = payload => {
let centerCoordinate = payload?.geometry?.coordinates;
setcurrentPinCoordinate(centerCoordinate);
camera?.current?.setCamera({
centerCoordinate,
zoomLevel: defaultCamera?.zoomLevel,
animationDuration: 1000,
animationMode: 'flyTo',
});
};
const selectedItemResDropdown = payload => {
console.log('SELECTED_DROPDOWN_ITEM_RESPONSE', payload);
let centerCoordinate = payload?.geometry?.coordinates;
setcurrentPinCoordinate(centerCoordinate);
camera?.current?.setCamera({
centerCoordinate,
zoomLevel: defaultCamera?.zoomLevel,
animationDuration: 3000,
animationMode: 'flyTo',
});
};
return (
<View style={styles.page}>
<TouchableOpacity
style={styles.tempGoback}
onPress={() => navigation.goBack()}
/>
{/* REUSABLE MARKER SEARCH COMPONENT */}
<SearchLocationInput
textInputText={''}
selectedItemRes={res => selectedItemResDropdown(res)}
currentPinCoordinate={currentPinCoordinate}
/>
{/* REUSABLE MARKER SEARCH COMPONENT */}
<View style={styles.container}>
<MapboxGL.MapView
ref={_map}
style={styles.map}
styleURL={MapboxGL.StyleURL.Street}
localizeLabels={true}
attributionEnabled={false}
logoEnabled={false}>
<Camera ref={camera} defaultSettings={defaultCamera} />
<PointAnnotation
key={1}
id={'1'}
coordinate={currentPinCoordinate}
draggable
onDragEnd={onDragEnd}
ref={pointAnnotation}>
<View style={styles.annotationContainer}>
<Image
source={{uri: 'https://reactnative.dev/img/tiny_logo.png'}}
style={styles.imgStyle}
onLoad={() => pointAnnotation.current?.refresh()}
/>
</View>
</PointAnnotation>
{poiList?.features && poiList?.features.length > 0
? poiList?.features.map((value, index) => (
<MarkerView key={value.id} coordinate={value?.center}>
<Pressable onPress={() => onSelectPoiFunc(value)} key={index}>
<View style={styles.marker} />
</Pressable>
</MarkerView>
))
: null}
{routeGeoJOSN && <RouteLineString />}
{centerOfLineString && (
<MapboxGL.MarkerView
id="selectedFeatureMarkerView"
coordinate={centerOfLineString}>
<CustomCalloutView />
</MapboxGL.MarkerView>
)}
</MapboxGL.MapView>
</View>
<View style={styles.bottomContainer}>
<Button title={'SHOPPING'} onPress={onPressInterestSite} />
<Button title={'RESTAURANT'} onPress={onPressInterestSite} />
<Button title={'MOSQUE'} onPress={onPressInterestSite} />
<Button title={'HOSPITAL'} onPress={onPressInterestSite} />
</View>
</View>
);
};
export default MAP_VIEW;
const styles = StyleSheet.create({});
SearchLocationInput.js
import React, {useEffect, useState} from 'react';
import {
View,
Text,
FlatList,
TextInput,
StyleSheet,
TouchableOpacity,
} from 'react-native';
import {MAP_BOX_ACCESS_TOKEN} from '../../../utils/constants/constants';
import {isRTL} from '../../../i18n';
import {useFirstRender} from '../../newTabsGallery/galleryComponents/reusableHooks';
const SearchLocationInput = ({
textInputText = '',
selectedItemRes,
currentPinCoordinate = [],
}) => {
const [resultList, setresultList] = useState([]);
const [inputText, setinputText] = useState(textInputText);
const firstRender = useFirstRender();
useEffect(() => {
if (!firstRender) {
reverseGeocodingData();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentPinCoordinate]);
const reverseGeocodingData = async (bool = true) => {
// bool true = poi, bool false = region
let searchParams = new URLSearchParams({
access_token: MAP_BOX_ACCESS_TOKEN,
language: isRTL() ? 'ar' : 'en',
country: 'SA',
limit: 1,
// type: 'poi',
});
let response = await fetch(
bool
? `https://api.mapbox.com/geocoding/v5/mapbox.places/${currentPinCoordinate[0]},${currentPinCoordinate[1]}.json?` +
searchParams
: `https://api.mapbox.com/search/v1/reverse/${currentPinCoordinate[0]},${currentPinCoordinate[1]}?` +
searchParams,
);
let result = await response.json();
let resData = bool
? result?.features[0]?.text
: result?.features[0]?.properties?.feature_name;
console.log('reverseGeocodingData', resData);
setinputText(resData);
};
const searchItems = async text => {
try {
setinputText(text);
if (text.length > 2) {
let response = await fetch(
`https://api.mapbox.com/search/v1/suggest/${text}?` +
new URLSearchParams({
access_token: MAP_BOX_ACCESS_TOKEN,
session_token: '',
language: isRTL() ? 'ar' : 'en',
country: 'SA',
// types:
// 'country, region, prefecture, postcode, district, place, city, locality, oaza, neighborhood, chome, block, street, address',
}),
);
let result = await response.json();
setresultList(
result?.suggestions.length > 0 ? result?.suggestions : [],
);
} else {
setresultList([]);
}
} catch ({message}) {
setinputText('');
setresultList([]);
console.log('searchItemsSiteERROR', message);
}
};
const onPressListItem = async item => {
try {
let options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(item?.action?.body),
};
let response = await fetch(
'https://api.mapbox.com/search/v1/retrieve?' +
new URLSearchParams({
access_token: MAP_BOX_ACCESS_TOKEN,
session_token: '',
}),
options,
);
let result = await response.json();
selectedItemRes(result?.features[0]);
setinputText(result?.features[0]?.properties?.feature_name);
setresultList([]);
} catch ({message}) {
console.log('onPressListItemERROR', message);
}
};
const renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '100%',
backgroundColor: '#CED0CE',
}}
/>
);
};
return (
<View
style={{
flex: 1,
width: '98%',
position: 'absolute',
top: 100,
zIndex: 1,
backgroundColor: 'white',
}}>
<TextInput
style={{height: 60, borderColor: '#000', borderWidth: 1}}
placeholder=" Type Here...Key word"
onChangeText={searchItems}
value={inputText}
/>
{inputText && (
<FlatList
data={resultList}
renderItem={({item}) => (
<TouchableOpacity onPress={() => onPressListItem(item)}>
<Text style={{padding: 10}}>{item?.feature_name} </Text>
</TouchableOpacity>
)}
keyExtractor={(item, index) => index + ''}
ItemSeparatorComponent={renderSeparator}
/>
)}
</View>
);
};
export default SearchLocationInput;
const styles = StyleSheet.create({});
Top comments (2)
Does this API is free for development?
Yes but there can be some limitation in free version . Read doc