Week 8

Testing back-end using a front-end

Back-end servers can be interacted with via API using HTTP requests from a website.


Express.js Back-End

Express.js makes creating a back-end API simple. Using CORS allows front-ends from different domains to make API requests.


    import express from "express";
    import cors from "cors";
    import { add } from "./math.js";

    const app = express();
    const PORT = 3000;

    // middleware
    app.use(cors());
    app.use(express.json());

    // helper functions
    function validateNumbers(a, b) {
        return (typeof a === "number" && typeof b === "number" && !isNaN(a) && !isNaN(b));
    }

    // endpoints

    // GET method
    // Request using query parameters to pass numbers
    // http://localhost:3000/add?a=10&b=4
    app.get("/add", (req, res) => {
        const a = parseFloat(req.query.a);
        const b = parseFloat(req.query.b);

        if (!validateNumbers(a, b)) {
            return res.status(400).json({ error: "Both values must be numbers" });
        }

        res.json({ result: add(a, b) });
    });

    // POST method
    // Request using body to pass numbers
    // http://localhost:3000/add?a=10&b=4
    app.post("/add", (req, res) => {
        const { a, b } = req.body;

        if (!validateNumbers(a, b)) {
            return res.status(400).json({ error: "Both values must be numbers" });
        }

        res.json({ result: add(a, b) });
    });

    // Start server
    app.listen(PORT, () => {
        console.log(`Server is running on http://localhost:${PORT}`);
    });
                

PHP Slim Back-End

PHP is an alternative to JavaScript for creating back-end APIs. The Slim framework simplifies this process by providing a simple and flexible way to handle HTTP requests.

Run composer require slim/slim:^4 slim/psr7 after creating the project.


<?php

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

use Slim\Factory\AppFactory;

$app = AppFactory::create();

// Middleware (like express.json())
$app->addBodyParsingMiddleware();

// Helper function
function validateNumbers($a, $b) {
    return is_numeric($a) && is_numeric($b);
}

// GET /add?a=1&b=2
$app->get('/add', function ($request, $response) {
    $params = $request->getQueryParams();

    $a = floatval($params['a'] ?? null);
    $b = floatval($params['b'] ?? null);

    if (!validateNumbers($a, $b)) {
        $response->getBody()->write(json_encode([
            "error" => "Both values must be numbers"
        ]));
        return $response->withStatus(400)
                        ->withHeader('Content-Type', 'application/json');
    }

    $response->getBody()->write(json_encode([
        "result" => $a + $b
    ]));

    return $response->withHeader('Content-Type', 'application/json');
});

// POST /add
$app->post('/add', function ($request, $response) {
    $data = $request->getParsedBody();

    $a = $data['a'] ?? null;
    $b = $data['b'] ?? null;

    print "Received POST data: " . json_encode($data) . "\n";

    if (!validateNumbers($a, $b)) {
        $response->getBody()->write(json_encode([
            "error" => "Both values must be numbers"
        ]));
        return $response->withStatus(400)
                        ->withHeader('Content-Type', 'application/json');
    }

    $response->getBody()->write(json_encode([
        "result" => $a + $b
    ]));

    return $response->withHeader('Content-Type', 'application/json');
});

$app->run();
                

JavaScript Object Notation

JSON allows data to be transferred between the front-end and back-end with minimal transformations.


    const myObject = {
        name: "John Smith",
        age: 25,
        address: "139 Carrington Rd, Mt Albert, Auckland 1024"
    }

    const objAsJSON = JSON.stringify(myObject);

    const objFromJSON = JSON.parse(objAsJSON);

    console.log(objFromJSON);
    // output:
    // myObject {
    //      name: "John Smith",
    //      age: 25,
    //      address: "139 Carrington Rd, Mt Albert, Auckland 1024"
    // }