JavaScript/TypeScript REST SDK Developers Guide (preview)
The Azure Maps JavaScript/TypeScript REST SDK (JavaScript SDK) supports searching using the Azure Maps Search service, like searching for an address, searching for boundary of a city or country, and searching by coordinates. This article helps you get started building location-aware applications that incorporate the power of Azure Maps.
Note
Azure Maps JavaScript SDK supports the LTS version of Node.js. For more information, see Node.js Release Working Group.
Prerequisites
- Azure Maps account.
- Subscription key or other form of Authentication with Azure Maps.
- Node.js.
Tip
You can create an Azure Maps account programmatically, Here's an example using the Azure CLI:
az maps account create --kind "Gen2" --account-name "myMapAccountName" --resource-group "<resource group>" --sku "G2"
Create a Node.js project
The following example creates a new directory then a Node.js program named mapsDemo using npm:
mkdir mapsDemo
cd mapsDemo
npm init
Install the search package
To use Azure Maps JavaScript SDK, you need to install the search package. Each of the Azure Maps services including search, routing, rendering and geolocation are each in their own package.
npm install @azure-rest/maps-search
Once the package is installed, create a search.js
file in the mapsDemo
directory:
mapsDemo
+-- package.json
+-- package-lock.json
+-- node_modules/
+-- search.js
Azure Maps services
Create and authenticate a MapsSearchClient
You need a credential
object for authentication when creating the MapsSearchClient
object used to access the Azure Maps search APIs. You can use either a Microsoft Entra credential or an Azure subscription key to authenticate. For more information on authentication, see Authentication with Azure Maps.
Tip
TheMapsSearchClient
is the primary interface for developers using the Azure Maps search library. See Azure Maps Search client library to learn more about the search methods available.
Using a Microsoft Entra credential
You can authenticate with Microsoft Entra ID using the Azure Identity library. To use the DefaultAzureCredential provider, you need to install the @azure/identity
package:
npm install @azure/identity
You need to register the new Microsoft Entra application and grant access to Azure Maps by assigning the required role to your service principal. For more information, see Host a daemon on non-Azure resources. The Application (client) ID, a Directory (tenant) ID, and a client secret are returned. Copy these values and store them in a secure place. You need them in the following steps.
Set the values of the Application (client) ID, Directory (tenant) ID, and client secret of your Microsoft Entra application, and the map resource’s client ID as environment variables:
Environment Variable | Description |
---|---|
AZURE_CLIENT_ID | Application (client) ID in your registered application |
AZURE_CLIENT_SECRET | The value of the client secret in your registered application |
AZURE_TENANT_ID | Directory (tenant) ID in your registered application |
MAPS_CLIENT_ID | The client ID in your Azure Map account |
You can use a .env
file for these variables. You need to install the dotenv package:
npm install dotenv
Next, add a .env
file in the mapsDemo directory and specify these properties:
AZURE_CLIENT_ID="<client-id>"
AZURE_CLIENT_SECRET="<client-secret>"
AZURE_TENANT_ID="<tenant-id>"
MAPS_CLIENT_ID="<maps-client-id>"
Once your environment variables are created, you can access them in your JavaScript code:
const MapsSearch = require("@azure-rest/maps-search").default;
const { DefaultAzureCredential } = require("@azure/identity");
require("dotenv").config();
const credential = new DefaultAzureCredential();
const client = MapsSearch(credential, process.env.MAPS_CLIENT_ID);
Using a subscription key credential
You can authenticate with your Azure Maps subscription key. Your subscription key can be found in the Authentication section in the Azure Maps account as shown in the following screenshot:
You need to pass the subscription key to the AzureKeyCredential
class provided by the Azure Core Authentication Package. For security reasons, it's better to specify the key as an environment variable than to include it in your source code.
Use a .env
file to store the subscription key variable to accomplish this. You need to install the dotenv package to retrieve the value:
npm install dotenv
Next, add a .env
file in the mapsDemo directory and specify the property:
MAPS_SUBSCRIPTION_KEY="<subscription-key>"
Once your environment variable is created, you can access it in your JavaScript code:
const MapsSearch = require("@azure-rest/maps-search").default;
const { AzureKeyCredential } = require("@azure/core-auth");
require("dotenv").config();
const credential = new AzureKeyCredential(process.env.MAPS_SUBSCRIPTION_KEY);
const client = MapsSearch(credential);
Using a Shared Access Signature (SAS) Token Credential
Shared access signature (SAS) tokens are authentication tokens created using the JSON Web token (JWT) format and are cryptographically signed to prove authentication for an application to the Azure Maps REST API.
You can get the SAS token using AzureMapsManagementClient.accounts.listSas
package. Follow the section Create and authenticate a AzureMapsManagementClient
to setup first.
Second, follow Managed identities for Azure Maps to create a managed identity for your Azure Maps account. Copy the principal ID (object ID) of the managed identity.
Next, install Azure Core Authentication Package package to use AzureSASCredential
:
npm install @azure/core-auth
Finally, you can use the SAS token to authenticate the client:
const MapsSearch = require("@azure-rest/maps-search").default;
const { AzureSASCredential } = require("@azure/core-auth");
const { DefaultAzureCredential } = require("@azure/identity");
const { AzureMapsManagementClient } = require("@azure/arm-maps");
const subscriptionId = "<subscription ID of the map account>"
const resourceGroupName = "<resource group name of the map account>";
const accountName = "<name of the map account>";
const mapsAccountSasParameters = {
start: "<start time in ISO format>", // e.g. "2023-11-24T03:51:53.161Z"
expiry: "<expiry time in ISO format>", // maximum value to start + 1 day
maxRatePerSecond: 500,
principalId: "<principle ID (object ID) of the managed identity>",
signingKey: "primaryKey",
};
const credential = new DefaultAzureCredential();
const managementClient = new AzureMapsManagementClient(credential, subscriptionId);
const {accountSasToken} = await managementClient.accounts.listSas(
resourceGroupName,
accountName,
mapsAccountSasParameters
);
if (accountSasToken === undefined) {
throw new Error("No accountSasToken was found for the Maps Account.");
}
const sasCredential = new AzureSASCredential(accountSasToken);
const client = MapsSearch(sasCredential);
Geocoding
The following code snippet demonstrates how, in a simple console application, to import the @azure-rest/maps-search
package and get the coordinates of an address using GetGeocoding query:
const MapsSearch = require("@azure-rest/maps-search").default;
const { isUnexpected } = require("@azure-rest/maps-search");
const { AzureKeyCredential } = require("@azure/core-auth");
require("dotenv").config();
async function main() {
const credential = new AzureKeyCredential(
process.env. MAPS_SUBSCRIPTION_KEY
);
const client = MapsSearch(credential);
const response = await client.path("/geocode", "json").get({
queryParameters: {
query: "1301 Alaskan Way, Seattle, WA 98101, US",
},
});
if (isUnexpected(response)) {
throw response.body.error;
}
const [ lon, lat ] = response.body.features[0].geometry.coordinates;
console.log(`The coordinate is: (${lat}, ${lon})`);
}
main().catch((err) => {
console.error(err);
});
This code snippet shows how to use the MapsSearch
method from the Azure Maps Search client library to create a client
object with your Azure credentials. You can use either your Azure Maps subscription key or the Microsoft Entra credential. The path
parameter specifies the API endpoint, which in this case is "/geocode". The get
method sends an HTTP GET request with the query parameters. The query searches for the coordinate of "1301 Alaskan Way, Seattle, WA 98101, US". The SDK returns the results as a GeocodingResponseOutput object and writes them to the console. The results are ordered by confidence score in this example and only the first result is displayed to the screen. For more information, see GetGeocoding.
Run search.js
with Node.js:
node search.js
Batch reverse geocoding
Azure Maps Search also provides some batch query methods. The following example demonstrates how to call batched reverse search method:
const batchItems = [
// This is an invalid query
{ coordinates: [2.294911, 148.858561] },
{
coordinates: [-122.34255, 47.6101],
},
{ coordinates: [-122.33817, 47.6155] },
];
const response = await client.path("/reverseGeocode:batch").post({
body: { batchItems },
});
In this example, three coordinates are included in the batchItems
of the request body. The first item is invalid, see Handling failed requests for an example showing how to handle the invalid item.
Once you get the response, you can log it:
function logResponseBody(resBody) {
const { summary, batchItems } = resBody;
const { totalRequests, successfulRequests } = summary;
console.log(`${successfulRequests} out of ${totalRequests} requests are successful.`);
batchItems.forEach(({ response }, idx) => {
if (response.error) {
console.log(`Error in ${idx + 1} request: ${response.error.message}`);
} else {
console.log(`Results in ${idx + 1} request:`);
response.features.forEach((feature) => {
console.log(` ${feature.properties.address.freeformAddress}`);
});
}
});
}
Handling failed requests
Handle failed requests by checking for the error
property in the response batch item. See the logResponseBody
function in the completed batch reverse search following example.
Completed batch reverse search example
The complete code for the reverse address batch search example:
const MapsSearch = require("@azure-rest/maps-search").default,
{ isUnexpected } = require("@azure-rest/maps-search");
const { AzureKeyCredential } = require("@azure/core-auth");
require("dotenv").config();
async function main() {
const credential = new AzureKeyCredential(process.env.MAPS_SUBSCRIPTION_KEY);
const client = MapsSearch(credential);
const batchItems = [
// This is an invalid query
{ coordinates: [2.294911, 148.858561] },
{
coordinates: [-122.34255, 47.6101],
},
{ coordinates: [-122.33817, 47.6155] },
];
const response = await client.path("/reverseGeocode:batch").post({
body: { batchItems },
});
if (isUnexpected(response)) {
throw response.body.error;
}
logResponseBody(resumeResponse.body);
}
function logResponseBody(resBody) {
const { summary, batchItems } = resBody;
const { totalRequests, successfulRequests } = summary;
console.log(`${successfulRequests} out of ${totalRequests} requests are successful.`);
batchItems.forEach(({ response }, idx) => {
if (response.error) {
console.log(`Error in ${idx + 1} request: ${response.error.message}`);
} else {
console.log(`Results in ${idx + 1} request:`);
response.features.forEach((feature) => {
console.log(` ${feature.properties.address.freeformAddress}`);
});
}
});
}
main().catch(console.error);
Use V1 SDK
We are working to make all V1 features available in V2, until then, install the following V1 SDK packages if needed:
npm install @azure-rest/map-search-v1@npm:@azure-rest/map-search@^1.0.0
npm install @azure-rest/map-search-v2@npm:@azure-rest/map-search@^2.0.0
Then, you can import the two packages:
const MapsSearchV1 = require("@azure-rest/map-search-v1").default;
const MapsSearchV2 = require("@azure-rest/map-search-v2").default;
The following example demonstrates creating a function that accepts an address and search POIs around it. Use V2 SDK to get the coordinates of the address(/geocode) and V1 SDK to search POIs around it(/search/nearby).
const MapsSearchV1 = require("@azure-rest/map-search-v1").default;
const MapsSearchV2 = require("@azure-rest/map-search-v2").default;
const { AzureKeyCredential } = require("@azure/core-auth");
const { isUnexpected: isUnexpectedV1 } = require("@azure-rest/maps-search-v1");
const { isUnexpected: isUnexpectedV2 } = require("@azure-rest/maps-search-v2");
require("dotenv").config();
/** Initialize the MapsSearchClient */
const clientV1 = MapsSearchV1(new AzureKeyCredential(process.env.MAPS_SUBSCRIPTION_KEY));
const clientV2 = MapsSearchV2(new AzureKeyCredential(process.env.MAPS_SUBSCRIPTION_KEY));
async function searchNearby(address) {
/** Make a request to the geocoding API */
const geocodeResponse = await clientV2
.path("/geocode")
.get({ queryParameters: { query: address } });
/** Handle error response */
if (isUnexpectedV2(geocodeResponse)) {
throw geocodeResponse.body.error;
}
const [lon, lat] = geocodeResponse.body.features[0].geometry.coordinates;
/** Make a request to the search nearby API */
const nearByResponse = await clientV1.path("/search/nearby/{format}", "json").get({
queryParameters: { lat, lon },
});
/** Handle error response */
if (isUnexpectedV1(nearByResponse)) {
throw nearByResponse.body.error;
}
/** Log response body */
for(const results of nearByResponse.body.results) {
console.log(
`${result.poi ? result.poi.name + ":" : ""} ${result.address.freeformAddress}. (${
result.position.lat
}, ${result.position.lon})\n`
);
}
}
async function main(){
searchNearBy("15127 NE 24th Street, Redmond, WA 98052");
}
main().catch((err) => {
console.log(err);
})