19. API

An API is a system of communication between languages or machines. It will help us receive JSONs and generate a response filtering by verbs and sending special headers.

It is essential in any backend if you are looking to process AJAX requests received from the frontend. Besides, JSON is currently the universal language for communicating with any other language.

Serving a JSON as an API

Let's see a simple example where we return a JSON from a dictionary.

<?php
// Information
$relojes = [
[
    'marca' => 'Marea',
    'origen' => 'Spain'
],
[
    'marca' => 'Rolex',
    'origen' => 'Suiza'
],
[
    'marca' => 'Omega',
    'origen' => 'Suiza'
],
[
    'marca' => 'Casio',
    'origen' => 'Japón'
]
];

// Header that indicates the type of content to serve
header('Content-Type: application/json');

// Converts to JSON and prints it
echo json_encode($relojes);

Generating content that is ideal for feeding JavaScript or other languages.

[
  {
    "marca": "Marea",
    "origen": "Spain"
  },
  {
    "marca": "Rolex",
    "origen": "Suiza"
  },
  {
    "marca": "Omega",
    "origen": "Suiza"
  },
  {
    "marca": "Casio",
    "origen": "Japón"
  }
]

Collecting a JSON from an API

To obtain the JSON we must use an HTTP client that handles the headers, verbs and other technical elements. Within the PHP ecosystem it is highly standardized to invoke curl, in other words, to leave the responsibility outside the code. In the vast majority of PHP configurations, the extension that lets us run it is enabled.

Below you can see an example function that may be helpful:

/**
 * Obtains a JSON from a url
 * @param {string} $url
 * @param {string} $method - GET by default.
 * @param {array} $body - Dictionary with elements to send. [] by default.
 * @return {array}
 */
function getJSON(string $url, string $method = 'GET', array $body = []): array {
    $curl = curl_init();
    $json = json_encode($body);
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $json);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        'Content-Length: ' . strlen($json))
    );
    $result = curl_exec($curl);
    curl_close($curl);
    return json_decode($result, $assoc = true) ;
}

Here you can see another example where it is called.

$data = getJSON('https://dominio.com/api/v1/dinosaurios/', 'POST', array('email' => 'juana@my.email'));

Method control

At some point we will have to watch which method we are receiving (GET, POST, PUT, DELETE, etc). And otherwise return an appropriate error code.

<?php

// We filter by the POST method
if ($_SERVER['REQUEST_METHOD'] == 'POST') {

    // Header that indicates the type of content to serve
    header('Content-Type: application/json');
    // We indicate in the header which types of methods are available
    header("Access-Control-Allow-Methods: POST, OPTIONS");
    // We indicate the code we will return. 200 if everything is correct.
    http_response_code(200);

    // We print a JSON response with code 200
    echo json_encode([
        'status' => 'ok'
    ]);

} else {

    // We indicate the code we will return. 405: method not allowed
    http_response_code(405);

    // We print a JSON response.
    echo json_encode([
        'status' => 'ok'
    ]);

}

Contact form example

Using what we learned in the E-mails lesson, let's see how we can create an API that makes the asynchronous sending of a contact form easier. A very common problem where many developers end up using a service out of ignorance.

We will send the following request.

curl -XPOST -H "Content-type: application/json" -d '{
    "nombre": "Juana",
    "apelldios": "De Arco",
    "email": "juana@my.email",
    "nacionalidad": "francia",
    "mensaje": "Freedom!"
}' http://localhost:8000/api-contacto.php

The API will take care of:

  1. Capturing the received JSON.
  2. Rendering a <p> for each element.
  3. Sending an email with the generated HTML to a specific SMTP server.
<?php

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
require_once('vendor/autoload.php');

if ($_SERVER['REQUEST_METHOD'] == 'POST') {

    function getJSON() {
        $inputJSON = file_get_contents('php://input');
        return json_decode($inputJSON, true);
    }

    function getHTMLMessage($data) {
        return array_reduce(array_keys($data), function ($carry, $key) use ($data) {
            $carry .= "<p><strong>$key:</strong> $data[$key]</p>";
            return $carry;
        });
    }

    function responseJSON($data, $code=200) {
        header('Content-Type: application/json');
        header("Access-Control-Allow-Methods: POST, OPTIONS");
        http_response_code($code);
        echo json_encode($data);
    }

    // Create object
    $mail = new PHPMailer();

    try {

        // SMTP server configuration
        $mail->isSMTP();
        $mail->Host       = 'smtp.correo.com';
        $mail->SMTPAuth   = true;
        $mail->Username   = 'usuario@correo.com';
        $mail->Password   = 'contraseña';
        $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
        $mail->Port       = 587;

        $mail->setFrom('emisor@correo.es', 'Sender name');
        // Who receives it
        $mail->addAddress('receptor@correo.es', 'Recipient name');

        // Content
        $mail->isHTML(true);
        $mail->Subject = 'My subject';
        $mail->Body    = getHTMLMessage(getJSON());

        // Send
        $mail->send();
    } catch (Exception $e) {
        responseJSON([
            'status' => 'ko'
        ], 500);
    }

    // Correct response with code 200
    responseJSON([
        'status' => 'ok'
    ]);

} else {

    // Error response with code 405
    responseJSON([
        'status' => 'ko'
    ], 405);
}

Route structure

Before building your API you must give it a logical structure so that developers quickly grasp how to make calls. In the following table you can see an example of a hypothetical library with routes using a widely used format called REST API.

{: .table .table-responsive .text-center} | Route | Method | Functionality | |------|--------|---------------| | /signup | POST | Registration | | /auth/login | POST | Log in | | /auth/logout | GET | Log out | | /biblioteca | GET | Lists all libraries | | /biblioteca | POST | Creates a new library | | /biblioteca/45 | GET | Obtains the library | | /biblioteca/45 | PUT | Updates the library | | /biblioteca/45 | DELETE | Deletes the library | | /biblioteca/45/libros | GET | Lists all the books in the library | | /biblioteca/45/libros/21 | GET | Obtains the book from the library | | /biblioteca/45/libros/21 | PUT | Updates the book in the library | | /biblioteca/45/libros/21 | DELETE | Deletes the book from the library |

Interesting headers

Send JSON content

header('Content-Type: application/json');

Enable CORS

header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header('Access-Control-Allow-Credentials: true');

Indicate cache

Measured in seconds. Example of one day.

header('Access-Control-Max-Age: 86400');

Available methods

header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
Activity 1

You must send the following information via GET.

  • Body weight.
  • Height.

You will return a JSON with the calculation of the index plus some extra data such as whether the weight is appropriate.

Pro: Generate a test for the Endpoint you have just created.

Activity 2

Design a database so that the runners of a race can register.

You will need the following Endpoints.

  • Register.
  • Obtain runner information.
  • Obtain all runners.

Pro: Generate a test for the Endpoint you have just created.

Activity 3

Search the internet for a CSV with all the information about the Simpsons episodes.

1. Read the file from PHP and generate an Endpoint that returns a JSON.

2. Generate an HTML table from JavaScript consuming the Endpoint.

3. Modify the Endpoint to allow pagination.

4. Create a new Endpoint to filter by name.

5. Modify JavaScript so that it uses the paginator, adding buttons to move between pages, and a field to search by name consuming the filter Endpoint.

Activity 4

Create an API, with its corresponding Endpoints, to build a message feed similar to Slack but aimed at penguins.

  • The HTML will be generated by JavaScript via AJAX.
  • The message scroll will be infinite.
  • A message can be added.
  • You can delete your own messages.

This work is under a Attribution-NonCommercial-NoDerivatives 4.0 International license.

Desafíos de programación atemporales y multiparadigmáticos

Desafíos de programación atemporales y multiparadigmáticos

Te encuentras ante un librillo de actividades, divididas en 2 niveles de dificultad. Te enfrentarás a los casos más comunes que te puedes encontrar en pruebas técnicas o aprender conceptos elementales de programación.

Buy the book

Will you buy me a coffee?

This is how I keep writing without ads or paywalls.

Comments

There are no comments yet.