archi api

Base de données

réaliser une base de données patisserie avec une table gateau. Cette table possédera comme champs un id et un nom.
insérer 10 sortes de gâteaux

API

Permettre à votre API de répondre aux routes suivantes grâce à SLIM dans un seul fichier index.php.

  1. gateau en POST pour insérer un gateau
  2. gateau/{id} en GET pour afficher un gateau
  3. gateaux en GET pour lister tous les gateaux
  4. gateau/{id} en DELETE pour supprimer un gateau
  5. gateau/{id} en PUT pour modifier un gateau

Réaliser le fichier htacess qui permet de regiriger les URI vers index.php
Implémenter les routes, dans un premier temps, elle répondront seulement “ok”
Ecrire une fonction qui se connecte à la base de données.
Relier chaque route à une fonction qui execute le service demandé.

Client

Réaliser une interface cliente uniquement en HTML, JQuery et Ajax pour utiliser les routes précédentes.
Afficher tous les boutons sur une seul page.
Appeler les routes grâce à JQuery qui lance une fonction Ajax au click du bouton. Les parametres seront transmis en dur dans l’URL dans un premier temps.
Permettre à l’utilisateur de saisir les informations du gateau pour la route 1, et l’id du gateau pour 3,4 et 5.

Mise en forme

Utiliser Boostrap pour mettre en forme l’interface.
Mettre en forme les boutons et les champs de saisis.

On pourra utiliser bootstrap-table pour la mise en forme de tableau JSON.

Documentation

Utiliser Swagger pour réaliser une documentation de votre API.

Documenter votre index.php avec les balises nécessaires.
Ajouter la dépendance zircote dans composer si cela n’est pas fait.
Lancer un script qui permet de parcourir index.php et de générer un fichier JSON de documentation
Afficher la documentation grâce à l’editeur Swagger.

https://editor.swagger.io
https://github.com/zircote/swagger-php

 

Correction

 

Base de données

CREATE DATABASE patisserie CHARACTER SET utf8 COLLATE utf8_general_ci;
USE patisserie;
CREATE TABLE gateau (
 id int(20) NOT NULL,
 nom varchar(20) NOT NULL,
 PRIMARY KEY (id)
) ENGINE=InnoDB ;

INSERT INTO gateau (id, nom) VALUES
(1, 'Alléluia'),
(2, 'Apfelstrudel'),
(3, 'Baba au rhum'),
(4, 'Bredele'),
(5, 'Crumble'),
(6, 'Cupcake'),
(7, 'Financier'),
(8, 'Galette des rois'),
(9, 'Gâteau Saint-Epvre'),
(10, 'Kouign');

 

API SLIM

Les URI 4 et 5 ne sont pas corrigées.

https://github.com/cherryclass/api-gateau-slim

.htaccess, permet de rediriger les URL vers index.php, à défaut utiliser http://mondomaine/index.php/urn

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept"

composer.json permet à composer de charger les dépendances sur le serveur, à utiliser sur une instance IBM Cloud ou AWS.
https://getcomposer.org/

{
    "require": {
        "php": "7.1.*",
        "ext-mbstring": "*",
        "ext-mysqli": "*",
        "ext-json": "*",
        "ext-pdo": "*",
        "ext-pdo_mysql": "*",
        "slim/slim": "3.8.*",
        "zircote/swagger-php": "^2.0",
        "firebase/php-jwt": "^5.0"
    }        
}

 

index.php

<?php
require 'vendor/autoload.php';

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use \Firebase\JWT\JWT;


/**
 * @SWG\Swagger(
 *     schemes={"https"},
 *    host="mybluemix.net",
 *    basePath="/gateau",
 *     @SWG\Info(
 *         version="1.1.0",
 *         title="API Gatêau",
 *         description="Enregistrement et affichage de Gâteaux",
 *         @SWG\Contact(
 *             email="zaza"
 *         ),
 *         @SWG\License(
 *             name="Apache 2.0",
 *             url="http://www.apache.org/licenses/LICENSE-2.0.html"
 *         )
 *     ),
 * )
 */

/**
 * @SWG\Tag(
 *   name="gateau",
 *   description="Operations about gateau",
 * )
 */

$app = new \Slim\App;
error_reporting(E_ALL);
ini_set('display_errors', 1);

/**
 * @SWG\Post(
 *   path="/gateau",
 * tags={"gateau"},
 *   summary="Inserer un gateau",
 *   description="Inserer un gateau",
 *    @SWG\Parameter(
 *         name="id",
 *         in="header",
 *         required=true,
 *         type="integer"
 *     ),
 *    @SWG\Parameter(
 *         name="nom",
 *         in="header",
 *         required=true,
 *         type="string"
 *     ),
 *   @SWG\Response(
 *     response=200,
 *     description="successful operation",
 *		@SWG\Schema(
 *       type="object"
 *     ),
 *   )
 * )
 */
$app->post('/gateau', function (Request $request, Response $response) {
    //$gateau = json_decode($request->getBody());
    $id = $request->getQueryParam('id');
    $nom = $request->getQueryParam('nom');
    return setGateau($id, $nom);
});
/**
 * @SWG\Get(
 *   path="/gateau/{id}",
 * tags={"gateau"},
 *   summary="Obtenir un gateau",
 *   description="Obtenir un gateau",
 *    @SWG\Parameter(
 *         name="id",
 *         in="path",
 *         required=true,
 *         type="integer"
 *     ),
 *   @SWG\Response(
 *     response=200,
 *     description="successful operation"
 *    )
 * )
 */
$app->get('/gateau/{id}', function (Request $request, Response $response) {
    $id = $request->getAttribute('id');
    return getGateau($id);
});

$app->get('/gateaux', function (Request $request, Response $response) {
    return getGateaux();
});

function connexion()
{
    /*IBM Cloud
     * $vcap_services = json_decode($_ENV['VCAP_SERVICES'], true);
     * $uri = $vcap_services['compose-for-mysql'][0]['credentials']['uri'];
     * $db_creds = parse_url($uri);
     * $dbname = "patisserie";
     * $dsn = "mysql:host=" . $db_creds['host'] . ";port=" . $db_creds['port'] . ";dbname=" . $dbname;
     * return $dbh = new PDO($dsn, $db_creds['user'], $db_creds['pass'],array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
     * */
    //autre
    return $dbh = new PDO("mysql:host=localhost;dbname=patisserie", 'root', '', array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
}

function getGateau($id)
{
    $sql = "SELECT * FROM gateau WHERE id=:id";
    try {
        $dbh = connexion();
        $statement = $dbh->prepare($sql);
        $statement->bindParam(":id", $id);
        $statement->execute();
        $result = $statement->fetchAll(PDO::FETCH_CLASS);
        return json_encode($result, JSON_PRETTY_PRINT);
    } catch (PDOException $e) {
        return '{"error":' . $e->getMessage() . '}}';
    }
}

function setGateau($id, $nom)
{
    $sql = "INSERT INTO gateau VALUES(:id, :nom))";
    try {
        $dbh = connexion();

        $req = $dbh->prepare($sql);
        $res = $req->execute(array(
            ':id' => $id,
            ':nom' => $nom,
        ));
        return $res;
    } catch (PDOException $e) {
        return '{"error":' . $e->getMessage() . '}}';
    }
}

function getGateaux()
{
    $sql = "SELECT * FROM gateau";
    try {
        $dbh = connexion();
        $statement = $dbh->prepare($sql);
        $statement->execute();
        $result = $statement->fetchAll(PDO::FETCH_CLASS);
        return json_encode($result, JSON_PRETTY_PRINT);
    } catch (PDOException $e) {
        return '{"error":' . $e->getMessage() . '}}';
    }
}

$app->run();

Client & mise en forme

index.html et index.js

$(document).ready(function () {
    $('#btn-insert-gateau').click(function () {
        let id = $('#id').val();
        let nom = $('#nom').val();
        $.ajax({
            type: "POST",
            contentType: 'application/json; charset=utf-8',
            url: "http://localhost/api-gateau/gateau?id=" + id + "&nom=" + nom,
            success: function (data) {
                //gateau enregistré, on préférera l'ajout d'un messaqge dans un div
                alert("gateau enregistré");
            }
        });
    });
    $('#btn-get-gateau').click(function () {
        let idx = $('#idx').val();
        $.getJSON("http://localhost/api-gateau/gateau/" + idx, function (data) {
            $('#result').html(data[0].nom);

        });
    });

    $('#btn-get-gateaux').click(function () {
        $('#table-gateau').bootstrapTable({
            url: 'http://localhost/api-gateau/gateaux',
            columns: [{
                field: 'id',
                title: 'Item ID'
            }, {
                field: 'nom',
                title: 'Item Name'
            },]
        });
    });
});
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="client de l'API gateau">
    <meta name="author" content="M. Frébourg">
    <title>API Gateau</title>


    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
          integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
            integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
            crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
            integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
            crossorigin="anonymous"></script>

    <!--tables-->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.12.1/bootstrap-table.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.12.1/bootstrap-table.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.12.1/locale/bootstrap-table-zh-CN.min.js"></script>


</head>

<body class="mesforms">
<div class="page container">

    <header class="header" id="top">
        <div class="row justify-content-md-center">
            <div class="col-12 col-md-auto">
                <h1>API Gâteau </h1>
            </div>
        </div>
    </header>


    <h3>Insertion en POST</h3>
    <div class="form-group">
        <label for="id" class=" col-md-8 col-lg-6 col-form-label">Identifiant du gâteau</label>
        <div class="col-md-8 col-lg-6">
            <input class="form-control" required="required" type="text" value="" id="id">
        </div>
        <label for="nom" class=" col-md-8 col-lg-6 col-form-label">Nom du gâteau</label>
        <div class=" col-md-8 col-lg-6">
            <input class="form-control" required="required" type="text" value="" id="nom">
        </div>
    </div>
    <div class="col-md-8 col-lg-6">
        <button class="btn btn-primary" id="btn-insert-gateau">Valider</button>
    </div>
    <br><br>
    <h3>Affichage en GET</h3>
    <div class="form-group form-group-nom ">
        <label for="idx" class=" col-md-8 col-lg-6 col-form-label">Afficher le gâteau avec l'identifiant :</label>
        <div class=" col-md-8 col-lg-6">
            <input class="form-control" required="required" type="text" value="" id="idx">
        </div>
    </div>
    <div class="col-md-8 col-lg-6">
        <button class="btn btn-primary" id="btn-get-gateau">Valider</button>
    </div>
    <br>
    <div class="col-md-8 col-lg-6">
        <div id="result"></div>
    </div>
    <br><br>
    <h3>Affichage d'une liste en GET</h3>
    <div class="form-group form-group-nom ">
        <label for="result2" class=" col-md-8 col-lg-6 col-form-label">Afficher les gâteaux</label>
    </div>
    <div class="col-md-8 col-lg-6">
        <button class="btn btn-primary" id="btn-get-gateaux">Valider</button>
    </div>
    <br>
    <div class="col-md-8 col-lg-6">
        <div id="result2"></div>
        <table id="table-gateau"></table>
    </div>

</div>

<footer>
    <div class="container ">
        <div class="row">
            <div class="col-lg-10 mx-auto text-center">
                <hr class="small">
                <p class="text-muted">v1.1 - &copy; M. Frébourg - <span class="yearCopy"></span></p>
            </div>
        </div>
    </div>
</footer>
<script src="js/index.js?v=1"></script>
</body>
</html>
  

Documentation avec SLIM

index.php

<?php 
require 'vendor/autoload.php';

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use \Firebase\JWT\JWT;


/**
 * @SWG\Swagger(
 *     schemes={"https"},
 *    host="mybluemix.net",
 *   	basePath="/gateau",
 *     @SWG\Info(
 *         version="1.1.0",
 *         title="API Gatêau",
 *         description="Enregistrement et affichage de Gâteaux",
 *         @SWG\Contact(
 *             email="zaza"
 *         ),
 *         @SWG\License(
 *             name="Apache 2.0",
 *             url="http://www.apache.org/licenses/LICENSE-2.0.html"
 *         )
 *     ),
  * )
 */

/**
 * @SWG\Tag(
 *   name="gateau",
 *   description="Operations about gateau",
 * )
 */

$app = new \Slim\App;

error_reporting(E_ALL);
ini_set('display_errors', 1);


/**
 * @SWG\Post(
 *   path="/gateau",
   * tags={"gateau"},
 *   summary="Inserer un gateau",
 *   description="Inserer un gateau",
 *    @SWG\Parameter(
     *         name="id",
     *         in="header",
     *         required=true,
     *         type="integer"
     *     ),
  *    @SWG\Parameter(
     *         name="nom",
     *         in="header",
     *         required=true,
     *         type="string"
     *     ),
 *   @SWG\Response(
 *     response=200,
 *     description="successful operation",
 *		@SWG\Schema(
 *       type="object"
 *     ),
*   )
 * )
 */
$app->post('/gateau', function(Request $request, Response $response){
	//$gateau = json_decode($request->getBody());
	$id = $request->getQueryParam('id');	
	$nom = $request->getQueryParam('nom');	
	return setGateau($id, $nom);
});
/**
 * @SWG\Get(
 *   path="/gateau/{id}",
   * tags={"gateau"},
 *   summary="Obtenir un gateau",
 *   description="Obtenir un gateau",
 *    @SWG\Parameter(
     *         name="id",
     *         in="path",
     *         required=true,
     *         type="integer"
     *     ),
 *   @SWG\Response(
 *     response=200,
 *     description="successful operation"		
 *   	)
 * )
 */ 
$app->get('/gateau/{id}', function(Request $request, Response $response){
	$id = $request->getAttribute('id');
	return getGateau($id);
});
function connexion(){ 
		//IBM Cloud
		$vcap_services = json_decode($_ENV['VCAP_SERVICES'], true);
		$uri = $vcap_services['compose-for-mysql'][0]['credentials']['uri'];
		$db_creds = parse_url($uri);
		$dbname = "patisserie";
		$dsn = "mysql:host=" . $db_creds['host'] . ";port=" . $db_creds['port'] . ";dbname=" . $dbname;

		return $dbh = new PDO($dsn, $db_creds['user'], $db_creds['pass'],array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
		//normal
		//$dsn ="mysql:host=182.18.57.5;port=3306;dbname='patisserie'";
		//return $dbh = new PDO($dsn, 'wawa', 'wiwi',array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));	 
}

function getGateau($id)
{
$id = $request->getAttribute('id');
	return getGateau($id);
	$sql = "SELECT * FROM gateau WHERE id=:id";
	try{
		$dbh=connexion();
		$statement = $dbh->prepare($sql);
		$statement->bindParam(":id", $id);
		$statement->execute();
		$result = $statement->fetchObject();
		return json_encode($result, JSON_PRETTY_PRINT);
	} catch(PDOException $e){
		return '{"error":'.$e->getMessage().'}}';
	}
}
function setGateau($id, $nom)
{
$dbh=connexion(); 
	$req=$dbh->prepare('INSERT INTO gateau VALUES(:id, :nom)');
	$res=$req->execute(array(
		':id'=> $id,
		':nom' => $nom,
	));
	return $res;
}
$app->run();

Swagger.php

<?php
require("vendor/autoload.php");
$swagger = \Swagger\scan('index.php');
header('Content-Type: application/json');
echo $swagger;

Appel de api-gateau.mybluemix.net/swagger.php, retourne du JSON à editer dans l’éditeur swagger.io

{
    "swagger": "2.0",
    "info": {
        "title": "API Gat\u00eaau",
        "description": "Enregistrement et affichage de G\u00e2teaux",
        "contact": {
            "email": "zaza"
        },
        "license": {
            "name": "Apache 2.0",
            "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
        },
        "version": "1.1.0"
    },
    "host": "mybluemix.net",
    "basePath": "/gateau",
    "schemes": [
        "https"
    ],
    "paths": {
        "/gateau": {
            "post": {
                "tags": [
                    "gateau"
                ],
                "summary": "Inserer un gateau",
                "description": "Inserer un gateau",
                "parameters": [
                    {
                        "name": "id",
                        "in": "header",
                        "required": true,
                        "type": "integer"
                    },
                    {
                        "name": "nom",
                        "in": "header",
                        "required": true,
                        "type": "string"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "successful operation",
                        "schema": {
                            "type": "object"
                        }
                    }
                }
            }
        },
        "/gateau/{id}": {
            "get": {
                "tags": [
                    "gateau"
                ],
                "summary": "Obtenir un gateau",
                "description": "Obtenir un gateau",
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "type": "integer"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "successful operation"
                    }
                }
            }
        }
    },
    "definitions": {},
    "tags": [
        {
            "name": "gateau",
            "description": "Operations about gateau"
        }
    ]
}