Using third-party APIs

That was enough theory about REST APIs; it is time to dive into a real world example. In this section, we will write a small PHP application that interacts with Twitter's REST API; that includes requesting developer credentials, authenticating, and sending requests. The goal is to give you your first experience in working with REST APIs, and showing you that it is easier than you could expect. It will also help you to understand better how they work, so it will be easier to build your own later.

Getting the application's credentials

REST APIs usually have the concept of application. An application is like an account on their development site that identifies who uses the API. The credentials that you will use to access the API will be linked to this application, which means that you can have multiple applications linked to the same account.

Assuming that you have a Twitter account, go to https://apps.twitter.com in order to create a new application. Click on the Create New App button in order to access the form for application details. The fields are very self-explanatory—just a name for the application, the description, and the website URL. The callback URL is not necessary here, since that will be used only for applications that require access to someone else's account. Agree with the terms and conditions in order to proceed.

Once you have been redirected to your application's page, you will see all sort of information that you can edit. Since this is just an example, let's go straight to what matters: the credentials. Click on the Keys and Access Tokens tab to see the values of Consumer key (API key) and Consumer Secret (API secret). There is nothing else that we need from here. You can save them on your filesystem, as ~/.twitter_php7.json, for example:

{
    "key": "iTh4Mzl0EAPn9HAm98hEhAmVEXS",
    "secret": "PfoWM9yq4Bh6rGbzzJhr893j4r4sMIAeVRaPMYbkDer5N6F"
}

Tip

Securing your credentials

Securing your REST API credentials should be taken seriously. In fact, you should take care of all kinds of credentials, like the database ones. But the difference is that you will usually host your database in your server, which makes things slightly more difficult to whoever wants to attack. On the other hand, the third-party REST API is not part of your system, and someone with your credentials can use your account freely on your behalf.

Never include your credentials in your code base, especially if you have your code in GitHub or some other repository. One solution would be to have a file in your server, outside your code, with the credentials; if that file is encrypted, that is even better. And try to refresh your credentials regularly, which you can probably do on the provider's website.

Setting up the application

Our application will be extremely simple. It will consist of one class that will allow us to fetch tweets. This will be managed by our app.php script.

As we have to make HTTP requests, we can either write our own functions that use cURL (a set of PHP native functions), or make use of the famous PHP library, Guzzle. This library can be found in Packagist, so we will use Composer to include it:

$ composer require guzzlehttp/guzzle

We will have a Twitter class, which will get the credentials from the constructor, and one public method: fetchTwits. For now, just create the skeleton so that we can work with it; we will implement such methods in later sections. Add the following code to src/Twitter.php:

<?php

namespace TwitterApp;

class Twitter {

    private $key;
    private $secret;

    public function __construct(String $key, String $secret) {
        $this->key = $key;
        $this->secret = $secret;
    }

    public function fetchTwits(string name, int $count): array {
        return [];
    }
}

Since we set the namespace TwitterApp, we need to update our composer.json file with the following addition. Remember to run composer update to update the autoloader.

"autoload": {
    "psr-4": {"TwitterApp\": "src"}
}

Finally, we will create a basic app.php file, which includes the Composer autoloader, reads the credentials file, and creates a Twitter instance:

<?php

use TwitterAppTwitter;

require __DIR__ . '/vendor/autoload.php';

$path = $_SERVER['HOME'] . '/.twitter_php7.json';
$jsonCredentials = file_get_contents($path);
$credentials = json_decode($jsonCredentials, true);

$twitter = new Twitter($credentials['key'], $credentials['secret']);

Requesting an access token

In a real world application, you would probably want to separate the code related to authentication from the one that deals with operations like fetching or posting data. To keep things simple here, we will let the Twitter class know how to authenticate by itself.

Let's start by adding a $client property to the class which will contain an instance of Guzzle's Client class. This instance will contain the base URI of the Twitter API, which we can have as the constant TWITTER_API_BASE_URI. Instantiate this property in the constructor so that the rest of the methods can make use of it. You can also add an $accessToken property which will contain the access token returned by the Twitter API when authenticating. All these changes are highlighted here:

<?php

namespace TwitterApp;

use Exception;
use GuzzleHttpClient;

class Twitter {

    const TWITTER_API_BASE_URI = 'https://api.twitter.com';

    private $key;
    private $secret;
    private $accessToken;
    private $client;

    public function __construct(String $key, String $secret) {
        $this->key = $key;
        $this->secret = $secret;

        $this->client = new Client(
            ['base_uri' => self::TWITTER_API_BASE_URI]
        );
    }

    //...
}

The next step would be to write a method that, given the key and secret are provided, requests an access token to the provider. More specifically:

  • Concatenate the key and the secret with a :. Encode the result using Base64.
  • Send a POST request to /oauth2/token with the encoded credentials as the Authorization header. Also include a Content-Type header and a body (check the code for more information).

We now invoke the post method of Guzzle's client instance sending two arguments: the endpoint string (/oauth2/token) and an array with options. These options include the headers and the body of the request, as you will see shortly. The response of this invocation is an object that identifies the HTTP response. You can extract the content (body) of the response with getBody. Twitter's API response is a JSON with some arguments. The one that you care about the most is the access_token, the token that you will need to include in each subsequent request to the API. Extract it and save it. The full method looks as follows:

private function requestAccessToken() {
    $encodedString = base64_encode(
        $this->key . ':' . $this->secret
    );
    $headers = [
        'Authorization' => 'Basic ' . $encodedString,
        'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'
    ];
    $options = [
        'headers' => $headers,
        'body' => 'grant_type=client_credentials'
    ];

    $response = $this->client->post(self:: OAUTH_ENDPOINT, $options);
    $body = json_decode($response->getBody(), true);

    $this->accessToken = $body['access_token'];
}

You can already try this code by adding these two lines at the end of the constructor:

$this->requestAccessToken();
var_dump($this->accessToken);

Run the application in order to see the access token given by the provider using the following command. Remember to remove the preceding two lines in order to proceed with the section.

$ php app.php

Keep in mind that, even though having a key and secret and getting an access token is the same across all OAuth authentications, the specific way of encoding, the endpoint used, and the response received from the provider are exclusive from Twitter's API. It could be that several others are exactly the same, but always check the documentation for each one.

Fetching tweets

We finally arrive to the section where we actually make use of the API. We will implement the fetchTwits method in order to get a list of the last N number of tweets for a given user. In order to perform requests, we need to add the Authorization header to each one, this time with the access token. Since we want to make this class as reusable as possible, let's extract this to a private method:

private function getAccessTokenHeaders(): array {
    if (empty($this->accessToken)) {
        $this->requestAccessToken();
    }

    return ['Authorization' => 'Bearer ' . $this->accessToken];
}

As you can see, the preceding method also allows us to fetch the access token from the provider. This is useful, since if we make more than one request, we will just request the access token once, and we have one unique place to do so. Add now the following method implementation:

const GET_TWITS = '/1.1/statuses/user_timeline.json';
//...
public function fetchTwits(string $name, int $count): array {
    $options = [
        'headers' => $this->getAccessTokenHeaders(),
        'query' => [
            'count' => $count,
            'screen_name' => $name
        ]
    ];

    $response = $this->client->get(self::GET_TWITS, $options);
    $responseTwits = json_decode($response->getBody(), true);

    $twits = [];
    foreach ($responseTwits as $twit) {
        $twits[] = [
            'created_at' => $twit['created_at'],
            'text' => $twit['text'],
            'user' => $twit['user']['name']
        ];
    }

    return $twits;
}

The first part of the preceding method builds the options array with the access token headers and the query string arguments—in this case, with the number of tweets to retrieve and the user. We perform the GET request and decode the JSON response into an array. This array contains a lot of information that we might not need, so we iterate it in order to extract those fields that we really want—in this example, the date, the text, and the user.

In order to test the application, just invoke the fetchTwits method at the end of the app.php file, specifying the Twitter ID of one of the people you are following, or yourself.

$twits = $twitter->fetchTwits('neiltyson', 10);
var_dump($twits);

You should get a response similar to ours, shown in the following screenshot:

Fetching tweets

One thing to keep in mind is that access tokens expire after some time, returning an HTTP response with a 4xx status code (usually, 401 unauthorized). Guzzle throws an exception when the status code is either 4xx or 5xx, so it is easy manage these scenarios. You could add this code when performing the GET request:

try {
    $response = $this->client->get(self::GET_TWITS, $options);
} catch (ClientException $e) {
    if ($e->getCode() == 401) {
        $this->requestAccessToken();
        $response = $this->client->get(self::GET_TWITS, $options);
    } else {
        throw $e;
    }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.195.111