Développement d'applications mobiles

Développement d'applications mobiles


6- Listes

7- HTTP

8- Modèles

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

js
copier
//
// 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

js
copier
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
copier
http://martha.jh.shawinigan.info/queries/...NOM REQUETE.../execute
http
POST /queries/...NOM_REQUETE.../execute
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

Création de la BD

sql
copier
create table items (
id int unsigned auto_increment primary key,
name varchar(100)
);

insert into items(name)
values ('aaa'), ('bbb'), ('ccc'), ('ddd');

Une query select

sql
select-items
copier
select * from items;

Tester la requête HTTP

URL
copier
http://martha.jh.shawinigan.info/queries/QUERY/execute

  • Préciser le header d'authentification

bash
copier
echo -n 'username:password' | base64

ou

https://www.base64encode.com

bash
copier
# https://httpie.io/docs/cli/http-headers
http POST http://martha.jh.shawinigan.info/queries/select-items/execute auth:...

Une query statement

sql
insert-item
copier
insert into items(name) values ("?name");

  • Aller dans query detail pour expérimenter le Run Query

json
copier
{"name": "new item"}

Requête HTTP, suite

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

json
Body
copier
{"name": "new item http request"}

bash
copier
# https://httpie.io/docs/cli/json
http POST http://martha.jh.shawinigan.info/queries/insert-item/execute auth:... name='new item http'

  • Constater la requête dans les API Requests

Démo ReactNative
jsx
copier
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
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://maxrozen.com/race-conditions-fetching-data-react-with-useeffect
return () => { cancelled = true; }

}, []) // [] pour executer seulement 1 fois, 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 []
//
// {
// items &&
// <> ... </>
// }

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 par rapport aux requêtes HTTP? 👉 Services! Et modèles...

Il est possible d'inspecter les requêtes HTTP avec les outils de développement