7 - HTTP


Développement d'applications mobiles

Requêtes HTTP

Plan

  • Programmation asynchrone
  • Requêtes HTTP
  • Martha

Traitement asynchrone

2 mécanismes en JavaScript

  • Callbacks: then, catch
  • Promises: async | await
    • ATTENTION await est disponible uniquement dans un contexte asynchrone

📚 Asynchronous JS

ℹ️ Javascript.info Async

ℹ️ async, await VS then, catch

Exemples

// ASYNC
async function wait(delay) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (Math.random() > 0.5) {
                resolve(`{"name": "james", "age": 42}`);
            } else {
                reject();
            }
        }, delay);
    });
}


//
// Callbacks
//

wait(2000)
    .then((data) => {
        console.log('1- Yay!', data); 
        return JSON.parse(data); 
    })
    .then((obj) => console.log(obj))
    .catch(() => console.log('1- Nope'))
    .finally(() => console.log('1 ----'))

// !!!
console.log('Will print result in 2 seconds');


//
// Async, await
//

// !!!
console.log('Will print another result in 2 seconds');

try {
    const data = await wait(2000)
    console.log('2- Yay!', data);
    console.log(JSON.parse(data));
} catch {
    console.log('2- Nope')
}
finally {
    console.log('2 ----')
}

Requêtes HTTP

Protocole de communication entre un client(navigateur web, app mobile, AJAX, script, ...) et un serveur(serveur web, application PHP, application Ruby, ...)

JSON

Format de données facilitant le transfert d’information

  • Facile à comprendre pour les humains,
  • Rapide à manipuler par les machines
  • Représente des objets sous forme clé-valeur, supporte également les tableaux
  • Les clés sont de type string
  • Les valeurs de type string, nombre, booléen, objet, tableau, null

Fetch

Mécanisme moderne pour effectuer des requêtes HTTP en JavaScript.

//
// Fetch
//

const simple = await fetch('http://httpbin.org/uuid').then((r) => r.text());
console.log({ simple })

const complete = await fetch(
    `http://httpbin.org/anything/something?${new URLSearchParams({filter: 'category'})}`, 
    {
        method: 'PUT',
        headers: {
            'Content-Type': 'application/xml'
        },
        body: 'Hello world!!!'
    }
).then((r) => r.json());

console.log({ complete })

📚 Using Fetch

ℹ️ Javascript.info Fetch

Martha

Offre une couche d’abstraction entre la base de données et l’application client qui manipule les données.

  • Une interface web permet de gérer la base de données et les requêtes SQL à exécuter, qui seront accessibles via des requêtes HTTP.
  • http://martha.jh.shawinigan.info
  • Présentation sur Youtube

Martha API

http://martha.jh.shawinigan.info/queries/{QUERY NAME}/execute



🖥️ Démo!

Recipeasy ✖️ Martha

Auth.js

import { User } from '../models/User.js'

class AuthService {
    // ...

    async signUp(credentials) {
        const response = await fetch("http://martha.jh.shawinigan.info/queries/insert-user/execute", {
            method: 'POST',
            body: JSON.stringify(credentials),
            headers: {
                'auth': 'YTphbGxvbDNTVVBFUk1PTkRFIQ=='
            }
        }).then((r) => r.json());

        if (response.success)  {
            this.#currentUser = new User({ id: response.lastInsertId, username: credentials.username })
        }

        return !!this.#currentUser
    }

    async logIn(credentials) {
        const response = await fetch("http://martha.jh.shawinigan.info/queries/select-user-auth/execute", {
            method: 'POST',
            body: JSON.stringify(credentials),
            headers: {
                'auth': 'YTphbGxvbDNTVVBFUk1PTkRFIQ=='
            }
        }).then((r) => r.json());

        if (response.success && response.data.length == 1)  {
            const user = response.data[0];
            this.#currentUser = new User({ id: user.id, username: user.username });
            console.log(JSON.stringify(this.#currentUser));
        } else {
            this.#currentUser = null;
        }

        return !!this.#currentUser
    }

    // ...
}

const service = new AuthService();
export default service;

User.js

export class User {

    #id;

    constructor({ id, username }) {
        this.#id = id
        this.username = username;
    }

    get id() {
        return this.#id;
    }

    toJSON() {
        return {
            id: this.#id,
            ...this
        }
    }

}


🚨 Mettre à jour: Login et Signup 🚨


Recipes.js

import { useFocusEffect } from '@react-navigation/native';
import { useCallback } from 'react';

export default function Recipes({ navigation, route }) {

    const [recipes, setRecipes] = useState();

    const refresh = useCallback(() => {
        let cancelled = false;

        // On doit creer un contexte async 
        const refresh = async () => {

            const response = await fetch("http://martha.jh.shawinigan.info/queries/select-recipes/execute", {
                method: 'POST',
                body: JSON.stringify({ id: Auth.currentUser }),
                headers: {
                    'auth': 'YTphbGxvbDNTVVBFUk1PTkRFIQ=='
                }
            }).then((r) => r.json());

            if (!cancelled && response.success)  {
                setRecipes(response.data.map(r => new Recipe(r)));
                // data VS new Model()
            }
        };

        refresh();

        return () => { cancelled = true; } // Pour eviter une race condition https://react.dev/learn/synchronizing-with-effects#fetching-data
    }, []) // [] pour executer seulement onFocus, pas chaque re-render

    //
    // useEffect VS useFocusEffect ?
    //

    // https://reactnavigation.org/docs/use-focus-effect
    useFocusEffect(refresh); 

    // https://react.dev/reference/react/useEffect
    // useEffect(refresh, [])

    //
    // Afficher la liste uniquement une fois les données chargées
    // undefined VS []
    //
    //  {
    //      recipes &&
    //      <FlatList />
    //  }

    // ...
}


Observations?

  • Gestion d'erreurs
  • Répétition ++
  • Responsabilité des components par rapport aux requêtes HTTP


Il est possible d'inspecter les requêtes HTTP avec les outils de développement du navigateur en appuyant sur j dans la console du serveur Expo