Développement d'applications mobiles

Avant d'explorer les mécanismes de requêtes HTTP, on doit d'abord comprendre le traitement asynchrone en JavaScript que ceux-ci utiliserons.

JS Asynchrone

  • 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

//
// ASYNC
//

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


//
// Callbacks
//

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

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


//
// await
//

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

try {
const data = await sleep(3000)

console.log('2 ----')
console.log('2 Yay!', data);
console.log(JSON.parse(data));
} catch {
console.log('2 ----')
console.log('2 Nope')
}
finally {
console.log('2 ----\n')
}

Requêtes HTTP

Protocole de communication entre un client(navigateur web, app mobile, AJAX, script, ...) et un serveur(serveur web, application PHP, application Ruby, ...)
Requête
Réponse

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

json
{
"first_name": "John",
"last_name": "Smith",
"is_alive": true,
"spouse": null,
"age": 27,
"address": {
"street_address": "21 2nd Street",
"city": "New York",
"state": "NY",
"postal_code": "10021-3100"
},
"phone_numbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [
"Catherine",
"Thomas",
"Trevor"
]
}

Fetch

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

📚 Using Fetch

ℹ️ Javascript.info 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': 'text/plain'
},
body: 'Hello world!!!'
}
).then((r) => r.json());

console.log({ complete })

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

API Martha

URL du service
http://martha.jh.shawinigan.info/queries/...NOM REQUETE.../execute
http
POST /queries/...NOM_REQUETE.../execute HTTP/1.1
auth: base64(username:password)

...JSON BODY?...

=== Statement SUCCES

{
success: true
}

=== Select SUCCES

{
success: true,
data: [
{ ... },
{ ... },
{ ... },
...
]
}

=== Insert auto-increment(statement) SUCCES

{
success: true,
lastInsertId: ...id...
}

~~~ Select/Statement ERREUR

{
success: false,
error: "Message..."
}
Démo Martha
md
#
# Create table
#

CREATE TABLE items (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100)
);

INSERT INTO items(name)
VALUES ('aaa'), ('bbb'), ('ccc'), ('ddd');


#
# New query, select
#

select-items

SELECT * from items;


#
# HTTP Client
#

http://martha.jh.shawinigan.info/queries/select-items/execute

add auth header

https://www.base64encode.com/

username:password


#
# New query, insert
#

insert-item

INSERT INTO items(name) VALUES ("?name");

Aller dans query detail pour demo payload test
{"name": "new item"}


#
# HTTP Client, suite
#

http://martha.jh.shawinigan.info/queries/insert-item/execute

Body JSON payload
{"name": "new item http request"}

Voir API Requests log

Démo ReactNative
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, ScrollView, View, Button } from 'react-native';
import { useCallback, useState, useEffect } from 'react';

export default function App() {
const [items, setItems] = useState()

const AUTH = "ZGVtbzpSZWFjdE5hdGl2ZTIwMjQh"

// useCallback ?
// https://react.dev/reference/react/useCallback
// https://react.dev/reference/react/useCallback#preventing-an-effect-from-firing-too-often
const refresh = useCallback(() => {
let cancelled = false;

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

const response = await fetch("http://martha.jh.shawinigan.info/queries/select-items/execute", {
method: 'POST',
headers: {
'auth': AUTH
}
}).then((r) => r.json());

if (!cancelled && response.success) {
setItems(response.data);
}
};

asyncRefresh();

// Pour eviter une race condition
// https://react.dev/learn/synchronizing-with-effects#fetching-data
return () => { cancelled = true; }

}, []) // [] pour executer seulement onFocus, pas chaque re-render


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

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

async function handleAdd() {
const response = await fetch("http://martha.jh.shawinigan.info/queries/insert-item/execute", {
method: 'POST',
body: JSON.stringify({name: `Item ${Math.random().toString(16).substring(2)}`}),
headers: {
'auth': AUTH
}
}).then((r) => r.json())

console.log(response)

refresh()
}

//
// Affichage, undefined VS []
//
// {
// recipes &&
// <> ... </>
// }

return (
<View style={{ flex: 1, paddingTop: StatusBar.currentHeight }}>

<ScrollView style={{ flexGrow: 1 }}>
<Text style={{ flexGrow: 1 }}>{ JSON.stringify(items, null, 2) }</Text>
</ScrollView>

<Button title="Add" onPress={ handleAdd }/>
</View>
);
}

Observations?

  • Gestion d'erreurs
  • Répétition ++
  • Responsabilité des components/service/modèles 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