翻译正在进行中。

到目前为止我们已经介绍的API是内置在浏览器中的,但并不是所有的API都是。许多大型网站和服务(例如Google地图,Twitter,Facebook,PayPal等)提供的API允许开发者使用他们的数据(例如在博客上显示您的Twitter流)或服务(例如在您的网站上显示自定义Google地图,或者使用Facebook登录来登录你的用户)。本文着眼于浏览器API和第三方API的区别,并展示了后者的一些典型用途。

先决条件: JavaScript 基础知识 (see first steps, building blocks, JavaScript objects), the basics of Client-side APIs
目的:  学习了解第三方API的运作方式,以及如何运用它们来提高你的网站性能

什么是第三方API?

第三方API是由第三方(通常是Facebook,Twitter或Google等公司)提供的API,允许您通过JavaScript访问其功能,并在您自己的站点上使用它。 正如我们在 introductory APIs article 所展示的, 最显著的例子就是运用 Google Maps APIs 在你的网页上展示自定义地图。

让我们再来瞧一眼这个地图的例子 (see the source code on GitHub; see it live also), 从这里可以知道第三方API和浏览器API的区别是怎么样的。

Note: You might want to just get all our code examples at once, in which case you can then just search the repo for the example files you need in each section.

它们植根于第三方服务器

浏览器API在浏览器构建之初就存在 — 用JavaScript就可以立即访问它们。例如, 例子中所使用的 Geolocation API 就是通过使用 Navigator 对象的属性 geolocation 来访问的, 它返回一个名为 Geolocation 的对象。 这个例子使用了这个对象的方法 getCurrentPosition() 来请求当前设备所处的地点:

navigator.geolocation.getCurrentPosition(function(position) { ... });

第三方API,从某种角度讲,是植根于第三方服务器上的。要通过 JavaScript获取它们,您首先需要链接到其功能接口上并使其在您的页面上生效。通常来说,这首先需要您通过一个 <script> 元素连接到第三方服务器所开放的JavaScript库,如下所示:

<script type="text/javascript" src="https://maps.google.com/maps/api/js?key=AIzaSyDDuGt0E5IEGkcE6ZfrKfUtE9Ko_de66pA"></script>

然后您便可使用该库中可用的对象了,如:

var latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
var myOptions = {
  zoom: 8,
  center: latlng,
  mapTypeId: google.maps.MapTypeId.TERRAIN,
  disableDefaultUI: true
}

var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

代码中我们用 google.maps.LatLng() 构造器创建了一个新的 LatLng 对象,它包含了我们想展示的地址的纬度和经度,作为一个Geolocation API返回。然后,我们创建了包含这个对象,和其他有关地图显示信息的选项对象(myOptions) 。最后,用 google.maps.Map() 构造器创建了map对象,它接受网页元素(地图展示处)和选项对象两个参数。

以上就是用 Google Maps API 建立一个简单地图所需要的所有信息。所有复杂的工作都全由你所连接的第三方服务器处理,包括展示正确地理位置的地图块,等等。

Note: Some APIs handle access to their functionality slightly differently, instead requiring the developer to make an HTTP request (see Fetching data from the server) to a specific URL pattern to retrieve specific data. These are called RESTful APIs, and we'll show an example of this later in the article.

Permissions are handled differently

Security for browser APIs tends to be handled by permission prompts, as discussed in our first article. The purpose of these is so that the user knows what is going on in the websites they visit, and is less likely to fall victim to someone using an API in a malicious way.

Third party APIs have a slightly different permissions system — they tend to use key codes to allow developers access to the API functionality. Look again at the URL of the Google Maps API library we linked to:

https://maps.google.com/maps/api/js?key=AIzaSyDDuGt0E5IEGkcE6ZfrKfUtE9Ko_de66pA

The URL parameter provided at the end of the URL is a developer key — the developer of the application must apply to get a key, and then include it in their code in a specific way to be allowed access to the API's functionality. In the case of Google Maps (and other Google APIs), you apply for a key at the Google Cloud Platform.

Other APIs may require that you include the key in a slightly different way, but the pattern is fairly similar for most of them.

The point of requiring a key is so that not just anybody can use API functionality without any kind of accountability. When the developer has registered for a key, they are then known to the API provider, and action can be taken if they start to do anything malicious with the API (such as tracking people's location, or trying to spam the API with loads of requests to stop it working, for example). The easiest action would be to just revoke their API privileges.

Extending the Google Maps example

Now we've examined the Google Maps API example and looked at how it works, let's add some more functionality to show how to use some other features of the API.

  1. To start off this section, make yourself a copy of the Google Maps starting file, in a new directory. If you've already cloned the examples repository, you'll already have a copy of this file, which you can find in the javascript/apis/third-party-apis/google-maps directory.

  2. Next, get your own developer key using the following steps:

    1. Go to the Google Cloud Platform API Manager dashboard.
    2. Create a new project if you've not already got one.
    3. Click the Enable API button.
    4. Choose Google Maps JavaScript API.
    5. Click the Enable button.
    6. Click Create credentials, then choose API key.
    7. Copy your API key and replace the existing key in the example's first <script> element with your own (the bit between ?key= and the attribute's closing quote mark (").)

    Note: Getting Google-related API keys can be a bit difficult — the Google Cloud Platform API Manager has a lot of different screens, and the workflow can differ slightly depending on things like whether you already have an account set up. If you have trouble with this step, we will be glad to help — Contact us.

  3. Open up your Google Maps starting file, find the string INSERT-YOUR-API-KEY-HERE, and replace it with the actual API key you got from the Google Cloud Platform API Manager dashboard.

Adding a custom marker

Adding a marker (icon) at a certain point on the map is easy — you just need to create a new marker using the google.maps.Marker() constructor, passing it an options object containing the position to display the marker at (as a LatLng object), and the Map object to display it on.

  1. Add the following just below the var map ... line:

    var marker = new google.maps.Marker({
      position: latlng,
      map: map
    });

    Now if you refresh your page, you'll see a nice little marker pop up in the center of the map. This is cool, but it is not exactly a custom marker — it is using the default marker icon.

  2. To use a custom icon, we need to specify it when we create the marker, using its URL. First of all, add the following line above the previous block you added:

    var iconBase = 'https://maps.google.com/mapfiles/kml/shapes/';

    This defines the base URL where all the official Google Maps icons are stored (you could also specify your own icon location if you wished).

  3. The icon location is specified in the icon property of the options object. Update the constructor like so:

    var marker = new google.maps.Marker({
      position: latlng,
      icon: iconBase + 'flag_maps.png',
      map: map
    });

    Here we specify the icon property value as the iconBase plus the icon filename, to create the complete URL. Now try reloading your example and you'll see a custom marker displayed on your map!

Note: See Customizing a Google Map: Custom Markers for more information.

Note: See Map marker or Icon names to find out what other icons are available, and see what their reference names are. Their file name will be the icon name they display when you click on them, with ".png" added on the end.

Displaying a popup when the marker is clicked

Another common use case for Google Maps is displaying more information about a place when its name or marker is clicked (popups are called info windows in the Google Maps API). This is also very simple to achieve, so let's have a look at it.

  1. First of all, you need to specify a JavaScript string containing HTML that will define the content of the popup. This will be injected into the popup by the API, and can contain just about any content you want. Add the following line below the google.maps.Marker() constructor definition:

    var contentString = '<div id="content"><h2 id="firstHeading" class="firstHeading">Custom info window</h2><p>This is a cool custom info window.</p></div>';
  2. Next, you need to create a new info window object using the google.maps.InfoWindow() constructor. Add the following below your previous line:

    var infowindow = new google.maps.InfoWindow({
      content: contentString
    });

    There are other properties available (see Info Windows), but here we are just specifying the content property in the options object, which points to the source of the content.

  3. Finally, to get the popup to display when the marker is clicked, we use a simple click event handler. Add the following below the google.maps.InfoWindow() constructor:

    marker.addListener('click', function() {
      infowindow.open(map, marker);
    });

    Inside the function we simply invoke the infowindow's open() function, which takes as parameters the map you want to display it on, and the marker you want it to appear next to.

  4. Now try reloading the example, and clicking on the marker!

Controlling what map controls are displayed

Inside the original google.maps.Map() constructor, you'll see the property disableDefaultUI: true specified. This disables all the standard UI controls you usually get on Google Maps.

  1. Try setting its value to false (or just removing the line altogether) then reloading your example, and you'll see the map zoom buttons, scale indicator, etc.

  2. Now undo your last change.

  3. You can show or hide the controls in a more granular fashion by using other properties that specify single UI features. Try adding the following underneath the disableDefaultUI: true (remember to put a comma after disableDefaultUI: true, otherwise you'll get an error):

    zoomControl: true,
    mapTypeControl: true,
    scaleControl: true,
  4. Now try reloading the example to see the effect these properties have. You can find more options to experiment with at the MapOptions object reference page.

That's it for now — have a look around the Google Maps APIs documentation, and have some more fun playing!

A RESTful API — NYTimes

Now let's look at another API example — the New York Times API. This API allows you to retrieve New York Times news story information and display it on your site. This type of API is known as a RESTful API — instead of getting data using the features of a JavaScript library like we did with Google Maps, we get data by making HTTP requests to specific URLs, with data like search terms and other properties encoded in the URL (often as URL parameters). This is a common pattern you'll encounter with APIs.

An approach for using third party APIs

Below we'll take you through an exercise to show you how to use the NYTimes API, which also provides a more general set of steps to follow that you can use as an approach for working with new APIs.

Find the documentation

When you want to use a third party API, it is essential to find out where the documentation is, so you can find out what features the API has, how you use them, etc. The New York Times API documentation is at https://developer.nytimes.com/.

Get a developer key

Most APIs require you to use some kind of developer key, for reasons of security and accountability. To sign up for an NYTimes API key, you need to go to https://developer.nytimes.com/signup.

  1. Let's request a key for the "Article Search API" — fill in the form, selecting this as the API you want to use.

  2. Next, wait a few minutes, then get the key from your email.

  3. Now, to start the example off, make copies of nytimes_start.html and nytimes.css in a new directory on your computer. If you've already cloned the examples repository, you'll already have a copy of these files, which you can find in the javascript/apis/third-party-apis/nytimes directory. Initially the <script> element contains a number of variables needed for the setup of the example; below we'll fill in the required functionality.

The app will end up allowing you to type in a search term and optional start and end dates, which it will then use to query the Article Search API and display the search results.

Connect the API to your app

First, you'll need to make a connection between the API, and your app. This is usually done either by connecting to the API's JavaScript (as we did in the Google Maps API), or by making requests to the correct URL(s).

In the case of this API, you need to include the API key as a get parameter every time you request data from it.

  1. Find the following line:

    var key = 'INSERT-YOUR-API-KEY-HERE';

    Replace INSERT-YOUR-API-KEY-HERE with the actual API key you got in the previous section.

  2. Add the following line to your JavaScript, below the "// Event listeners to control the functionality" comment. This runs a function called fetchResults() when the form is submitted (the button is pressed).

    searchForm.addEventListener('submit', fetchResults);
  3. Now add the fetchResults() function definition, below the previous line:

    function fetchResults(e) {
      // Use preventDefault() to stop the form submitting
      e.preventDefault();
    
      // Assemble the full URL
      url = baseURL + '?api-key=' + key + '&page=' + pageNumber + '&q=' + searchTerm.value;
    
      if(startDate.value !== '') {
        url += '&begin_date=' + startDate.value;
      };
    
      if(endDate.value !== '') {
        url += '&end_date=' + endDate.value;
      };
    
    }

This first calls preventDefault() on the event object, to stop the form actually submitting (which would break the example). Next, we use some string manipulation to assemble the full URL that we will make the request to. We start off by assembling the parts we deem as mandatory for this demo:

  • The base URL (taken from the baseURL variable).
  • The API key, which has to be specified in the api-key URL parameter (the value is taken from the key variable).
  • The page number, which has to be specified in the page URL parameter (the value is taken from the pageNumber variable).
  • The search term, which has to be specified in the q URL parameter (the value is taken from the value of the searchTerm text <input>).

Next, we use a couple of if() statements to check whether the startDate and endDate <input>s have had values filled in on them. If they do, we append their values to the URL, specified in begin_date and end_date URL parameters respectively.

So, a complete URL would end up looking something like this:

https://api.nytimes.com/svc/search/v2/articlesearch.json?api-key=4f3c267e125943d79b0a3e679f608a78&page=0&q=cats
&begin_date=20170301&end_date=20170312

Note: You can find more details of what URL parameters can be included at the Article Search API reference.

Note: The example has rudimentary form data validation — the search term field has to be filled in before the form can be submitted (achieved using the required attribute), and the date fields have pattern attributes specified, which means they won't submit unless their values consist of 8 numbers (pattern="[0-9]{8}"). See Form data validation for more details on how these work.

Requesting data from the api

Now we've constructed our URL, let's make a request to it. We'll do this using the Fetch API.

Add the following code block inside the fetchResults() function, just above the closing curly brace:

// Use fetch() to make the request to the API
fetch(url).then(function(result) {
  return result.json();
}).then(function(json) {
  displayResults(json);
});

Here we run the request by passing our url variable to fetch(), convert the response body to JSON using the json() function, then pass the resulting JSON to the displayResults() function so the data can be displayed in our UI.

Displaying the data

OK, let's look at how we'll display the data. Add the following function below your fetchResults() function.

function displayResults(json) {
  while (section.firstChild) {
      section.removeChild(section.firstChild);
  }

  var articles = json.response.docs;

  if(articles.length === 10) {
    nav.style.display = 'block';
  } else {
    nav.style.display = 'none';
  }

  if(articles.length === 0) {
    var para = document.createElement('p');
    para.textContent = 'No results returned.'
    section.appendChild(para);
  } else {
    for(var i = 0; i < articles.length; i++) {
      var article = document.createElement('article');
      var heading = document.createElement('h2');
      var link = document.createElement('a');
      var img = document.createElement('img');
      var para1 = document.createElement('p');
      var para2 = document.createElement('p');
      var clearfix = document.createElement('div');

      var current = articles[i];
      console.log(current);

      link.href = current.web_url;
      link.textContent = current.headline.main;
      para1.textContent = current.lead_paragraph;
      para2.textContent = 'Keywords: ';
      for(var j = 0; j < current.keywords.length; j++) {
        var span = document.createElement('span');
        span.textContent += current.keywords[j].value + ' ';
        para2.appendChild(span);
      }

      if(current.multimedia.length > 0) {
        img.src = 'http://www.nytimes.com/' + current.multimedia[0].url;
        img.alt = current.headline.main;
      }

      clearfix.setAttribute('class','clearfix');

      article.appendChild(heading);
      heading.appendChild(link);
      article.appendChild(img);
      article.appendChild(para1);
      article.appendChild(para2);
      article.appendChild(clearfix);
      section.appendChild(article);
    }
  }
};

There's a lot of code here; let's explain it step by step:

  • The while loop is a common pattern used to delete all of the contents of a DOM element, in this case the <section> element. We keep checking to see if the <section> has a first child, and if it does, we remove the first child. The loop ends when <section> no longer has any children.
  • Next, we set the articles variable to equal json.response.docs — this is the array holding all the objects that represent the articles returned by the search. This is done purely to make the following code a bit simpler.
  • The first if() block checks to see if 10 articles are returned (the API returns up to 10 articles at a time.) If so, we display the <nav> that contains the Previous 10/Next 10 pagination buttons. If less than 10 articles are returned, they will all fit on one page, so we don't need to show the pagination buttons. We will wire up the pagination functionality in the next section.
  • The next if() block checks to see if no articles are returned. If so, we don't try to display any — we just create a <p> containing the text "No results returned." and insert it into the <section>.
  • If some articles are returned, we first of all create all the elements that we want to use to display each news story, insert the right contents into each one, and then insert them into the DOM at the appropriate places. To work out which properties in the article objects contained the right data to show, we consulted the Article Search API reference. Most of these operations are fairly obvious, but a few are worth calling out:
    • We used a for loop (for(var j = 0; j < current.keywords.length; j++) { ... } ) to loop through all the keywords associated with each article, and insert each one inside its own <span>, inside a <p>. This was done to make it easy to style each one.
    • We used an if() block (if(current.multimedia.length > 0) { ... }) to check whether each article actually has any images associated with it (some stories don't.) We display the first image only if it actually exists (otherwise an error would be thrown).
    • We gave our <div> element a class of "clearfix", so we can easily apply clearing to it (this technique is needed at the time of writing to stop floated layouts from breaking.)

If you try the example now, it should work, although the pagination buttons won't work yet.

Wiring up the pagination buttons

To make the pagination buttons work, we will increment (or decrement) the value of the pageNumber variable, and then re-rerun the fetch request with the new value included in the page URL parameter. This works because the NYTimes API only returns 10 results at a time — if more than 10 results are available, it will return the first 10 (0-9) if the page URL parameter is set to 0 (or not included at all — 0 is the default value), the next 10 (10-19) if it is set to 1, and so on.

This allows us to easily write a simplistic pagination function.

  1. Below the existing addEventListener() call, add these two new ones, which cause the nextPage() and previousPage() functions to be invoked when the relevant buttons are clicked:

    nextBtn.addEventListener('click', nextPage);
    previousBtn.addEventListener('click', previousPage);
  2. Below your previous addition, let's define the two functions — add this code now:

    function nextPage(e) {
      pageNumber++;
      fetchResults(e);
    };
    
    function previousPage(e) {
      if(pageNumber > 0) {
        pageNumber--;
      } else {
        return;
      }
      fetchResults(e);
    };

    The first function is simple — we increment the pageNumber variable, then run the fetchResults() function again to display the next page's results.

    The second function works nearly exactly the same way in reverse, but we also have to take the extra step of checking that pageNumber is not already zero before decrementing it — if the fetch request runs with a minus page URL parameter, it could cause errors. If the pageNumber is already 0, we simply return out of the function, to avoid wasting processing power (If we are already at the first page, we don't need to load the same results again).

YouTube example

We also built another example for you to study and learn from — see our YouTube video search example. This uses two related APIs:

This example is interesting because it shows two related third party APIs being used together to build an app. The first one is a RESTful API, while the second one works more like Google Maps (with constructors, etc.). It is worth noting however that both of the APIs require a JavaScript library to be applied to the page. The RESTful API has functions available to handle making the HTTP requests and returning the results, so you don't have to write them out yourself using say fetch or XHR.

We are not going to say too much more about this example in the article — the source code has detailed comments inserted inside it to explain how it works.

Summary

This article has given you a useful introduction to using third party APIs to add functionality to your web sites.

 

In this module

文档标签和贡献者

 此页面的贡献者: Mal_akh, goodstudy, yuyx91
 最后编辑者: Mal_akh,