Avant d'explorer les mécanismes de requêtes HTTP, on doit d'abord comprendre le traitement asynchrone en JavaScript que ceux-ci utiliserons.
//
// 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')
}
Format de données facilitant le transfert d’information
{
"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"
]
}
Mécanisme moderne pour effectuer des requêtes HTTP en JavaScript.
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 })
Offre une couche d’abstraction entre la base de données et l’application client qui manipule les données.
http://martha.jh.shawinigan.info/queries/...NOM REQUETE.../execute
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..."
}
#
# 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
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>
);
}
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