Fórum nápovědy

Seznam

Jak se spojit s REST API

Jan Horinek

17.5.2024 v 10:17

Omlouvám se za ryze začátečnický dotaz. Nikdy jsem s API nepracoval a odpověď jsem nenašel ani v "Co je REST API Mapy.cz", ani ve FAQ.
Mám vytvořený projekt, chápu systém plateb a mám vytvořený klíč.

Předpokládám, že klíč bude v konstantě API_KEY na začátku JavaScriptu.

A teď to, čemu nerozumím:
1. Klíč je viditelný pro veřejnost ve výpisu kódu. Je to tak, že si ho musím zabezpečit aby ho nezačal používat někdo jiný?
2. Jak se spojím s novým API? V předchozím API byl v hlavičce stránky odkaz na loader. js. Předpokládám, že tím se načte JS soubor s balíkem funkcí, které pak lze volat a ty se provedou přes API.

Jak se ze souboru umístěném na mém PC spojím s novým API? To jsem ve FAQ nenašel.

Pokud jsem výše uvedl nějaký šokující nesmysl, omlouvám se, teprve do toho pronikám.
Ve svém projektu nebudu vykreslovat mapy, pouze budu načítat výšková data a vykteslovat přes JS výškový profil do vlastníhoi grafu.

Jan Buriánek

25.5.2024 v 14:19

Trochu jdsem se vecer upsal, -1 nestaci, elevace muze byt zaporna. Kdyz uz porovnavat, tak priradit treba -1000 a kdyz je tam jina hodnota, je vracena.

Jan Horinek

25.5.2024 v 14:26

Dík, já se nad tím zamyslím a nechám si to usadit v hlavě, s tímhle jsem se nikdy nesetkal a tak mám tendenci myslet synchronně. Každopádně, když dám kód dovnitř tak všechno funguje skvěle, jen je to pak takové hůř čitelné, kdybych se k tomu za čas vracel. Zkusím vykoumat jak to nechat uložit do globální proměnné až se to vrátí a pracovat s ní normálně. Kdyžtak bych se s dovolením ještě zeptal :)

Jan Kuchař reagoval na příspěvek od Jan Horinek

25.5.2024 v 16:23

Ano s tím Alertem to nebyl dobrý nápad pro tuto ukázku
Pozastavit kod se ale dá pomocí vytvořené funkce sleep(), ale stejně to funguje jen uvnitř nějaké funkce, navíc by jste musel pozastavit na dobu která bude třeba zbytečně dlouhá protože nikdy nevíte za jak dlouho se to vrátí ze serveru
ukázka takového kodu, zkuste nejdříve nastavit hodnotu sleep třeba 20 a pak zvyšujte a uvidíte zak se změní pořadí ve výpisu v konzole

let nadm_vyska_paty=-99;
nactiAPI()
async function nactiAPI() {
getElevation(lng_end + ',' + lat_end).then( function(value) {nadm_vyska_paty=value;console.log("X1",nadm_vyska_paty)})
await sleep(100)
console.log("X2"nadm_vyska_paty);
}

function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}



Jan Buriánek

25.5.2024 v 16:39

Myslite uvnitr, tedy komplet kod v .tnen(data ...?
Ven to vyvedete funkci, jak jsem psal, vykonejNeco(data), proste misto jen jedne souradniceposlete promennou data, a ve funkci si z ni vytahnete, co potrebujete.
Jinak opisovani hodnot do globalni promenne se dela pomoci pod-poli s postupnym indexovanim, takze v globalu pak mate dostupne vsechny predchozi poptavky.

A s temi async funkcemi to skutecne chce vstrebat, taky jsem stim bojoval, kdyz jsem zacinal :)

Jan Horinek

25.5.2024 v 17:12

Testuji tenhle kód

let nadm_vyska_paty = 0;

async function NajdiNadmorskouVysku(souradnice, pocet)
{
let vysky = []; // pole do ktereho uložím nadmořské výšky v bodech

const apiUrl = 'https://api.mapy.cz/v1/elevation?lang=cs&positions=' + souradnice + '&apikey=' + API_KEY;
const response = await fetch(apiUrl);
const data = await response.json();

if (pocet > 1) pocet++;

for(let i = 0; i < pocet; i++)
{
vysky.push(data.items[i].elevation);
}

nadm_vyska_paty = data.items[0].elevation;
console.log("uvnitr: "+nadm_vyska_paty);

if (pocet == 1) return data.items[0].elevation;
else return vysky;
}


// a teď to volám max. 1000x a nechávám si vypisovat hodnoty nadm_vyska_paty uvnitř a venku.


for (let i = 0; i < 1000; i++)
{
NajdiNadmorskouVysku(lng_end + ',' + lat_end, 1).then((value) => {});

if ( nadm_vyska_paty > 0) i = 1000;
console.log(i, nadm_vyska_paty);

}

// výsledek vypadá tak, že se 1000x vypíše i a nula (to vnější volání) a pak 1000 x uvnitr: 458,77 (vznitřní volání) z čehož jsem jelen.
// nakonec jsem si pro jistotu nechal vypsat stav document.getElementById("test").innerHTML += "pata: " + nadm_vyska_paty; a vrátilo to opět nulu.
// přišel jsem asi o 250.000 kreditů, takže to určitě volalo :))

Jan Kuchař reagoval na příspěvek od Jan Horinek

25.5.2024 v 19:40

No toho jsem se trochu obával, že postavíte funkci pro načtení jedné nadm. výšky a pak tím proženete jednotlivě tisíce souřadnic.
Ale už to tu bylo psáno a dokonce Honza B. vám psal jak sestavit parametr pro URL s vice souřadnic. Naráz můžete poptat až 256 souřadnic pokud jsou v rozsahu jednoho stupně. Takže teď si týden odpočinete než se vám obnoví kredit a můžete začít znovu a lépe jak se říká :)
Zkusím se do toho vašeho kodu trochu zakoukat jestli z toho bude něho použitelné

EDIT 19:48
Letmým pohledem mi přijde že tam posíláte 1000x stejné souřadnice ?

Jan Horinek

26.5.2024 v 14:40

Ne. Já jsem to sestavil záměrně pro jednu souřadnici, kterou jsem nechal vypisovat 1000x, abych tak nasimuloval časovou prodlevu a mohl sledovat, co se děje. S alertem to nefungovalo, zkusil jsem to takto. Čekal jsem, že po dobu co nebude Promise naplněn, to bude vypisovat nulu, pak se Promise naplní a nula přejde na nadmořskou výšku a tím se cyklus ukončí. Účelem nebylo získat 1000 souřadnic, což jak správně říkáte, ani nelze. Účelem bylo zjistit co se tam děje a jak to funguje, protože to se mi stále nedaří a jakmile mám dojem, že to chápu, stane se něco neočekávaného :)

Co mě překvapuje je, že to nejprve vypsalo 1000x ze vnějšku a pak 1000x ze vnitřku. To nechápu a to bych potřeboval vysvětlit. Očekával jsem, že se bude na střídačku vypisovat vniřek a vnějšek, jen předaná hodnota se v čase změní a cyklus se ukončí.

Kreditů mi ubylo jen 200.000, takže experimentovat stále můžu, jen méně opulentně :)

EDIT: To, co mi poradil pan Buriánek mám už implementované a všechno to skvěle funguje. Ale to jen za podmínky, že ten kód vložím dovnitř. Teď se pokouším přijít na to, jak dostat hodnotu z naplněného Promisu do do globální proměnné. Teoreticky to nepořebuji, ale rád bych se to naučil.

Jan Kuchař reagoval na příspěvek od Jan Horinek

26.5.2024 v 17:59

No od ten for cyklus který 1000x otáčíte proběhne celý během 5 ms ale první odpověď na požadavek nadmořské výšky přišel za 37 ms což se sice relativně krátká doba ale pořád je to později než for cyklus skončí. proto nejdřív v konzole ( 1000x 0 a pak teprve vrácená výška.
Vy se pořád snažíte to asynchronní volání nějak očůrat ale ono to jednak nejde a jednak to ani není potřeba.
Programuji webový gpxeditor kde se načítá nadmořská výška pro desetitísice souřadnic a problém s tím není, jen se s tím člověk musí naučit žít. Takto fungují i ostatní funkce mapy.cz routování, geokodování.
Buďtě rád že nemusíte používat staré API. tam se nadmořská výška musela poptávat po jedné takže když jste poslal 1000 požadavků (tím jste jim zahltil server) vrátilo se jich třeba jen 800 tak jste to musel projít a které se nenačetly tak poptat znovu, navíc odpovědí se nevrací ve stejném pořadí takže pak uhlídat ke které souřadnici ta nadmořská výška patří.
V novém REST API jestli jste si toho všimnul tak se vrací nejen nadmořská výška ale i souřadnice ze které jste to poptával, takže je v tom pořádek
Asi by bylo dobré napsat co vlastně s tím zamýšlíte a podle toho vás navést na správný postup

Jan Buriánek

26.5.2024 v 20:26

Synchronní script se provede celý okamžitě, na tom je to založeno, a má to tak být. Co nejrychlejší zpracování, po té, co přišel nějaký uživatelský vstup. A taky to nemá trvat dlouho, složité dlouhé výpočty se řeší jinak.

Uživatel klikne a script se okamžitě celý provede, to jsou skutečně millisec. Javascript v prohlížečích je jednovláknový, to znamená, že když počítá nějaký vás synchronní (běžný) script, nedělá nic jiného, ani neaktualizuje stránku (nepřekresluje DIVy).
No a přijde-li mezitím nějaký jiný vstup, pokud třeba script něco počítá déle a uživatel mezi tím klikne, nebo se během počítání vrátí hodnota z promise a pod., tak se zařadí do fronty. A vykoná se v pořadí, jak se zařadila do fronty.

Když třeba potřebujete spustit funkcí jinou funkci, ale aby se vykonala až po dokončení té, ze které to voláte, tak se na to používá setTimeout s nulou. Funkce se zařadí do fronty, protože nulový čas se splní okamžitě, ale nemůže se vykonat, je přes timeout spuštěna asynchronně, nikoli hned, v aktuálně běžící funkci se tedy nevykoná, vykoná se až po dokončení aktuální funkce. Takže např. zná globální hodnoty, vypočítané zbytkem funkce po jejím volání.

Ale klidně tam může být už mezi tím vřazena spousta dalších funkcí, jak si to na pozadí žije vlastním životem...
Například pokud daná funkce před tím voláním jiné přes timeout změnila hodnotu v DIV okně, tak je to už taky ve frontě, a až pak je ve frontě přes timeout volaná funkce, takže DIV na stránce se změní po dokončení běhu aktuálního scriptu, tedy dané funkce, a až pak se vykoná volaná funkce. Bude-li např. váš script něco dlouho počítat, a budete si to chtít průběžně vykreslovat na stránce, tak to synchronně nejde.

Zde tvoří výjimku console.log(), která vám to vypíše. Zdržuje script (hodně), ale vypíše. Pro ladění OK. Ale může Vás to zmást, protože třeba do DIV se to pak v plynulém běhu nezapíše, jak byste třeba očekával, když do konzole se to přece psalo...

Tedy i synchronní funkce mohou být spouštěny asynchronně. Vlastně uživatelské kliknutí je asynchronní spuštění synchronní funkce...

No a ten fetch() funguje podobně, script ve smyčce okamžitě (i při 1000x v řádu max jednotek ms celkem) zařadí do fronty požadavky na zpracování. Ale ne samotné odeslání! To se zase provádí asynchronně podle pořadí vřazení do fronty, do nějakého bufferu interně v prohlížeči, na to váš script nemá vliv. Váš script (smyčka 1000x) je hotov (máte vypsáno 1000x to, co smyčka znala, tedy nulu), a v podstatě teprve začínají odcházet postupně požadavky po síti, podle rychlosti sítě.
No a při takto velkém počtu už to odesílání trvá tak dlouho, že se mezi tím začnou již některé vracet!, a spouštějí zpracování .then, což zařadí také do fronty.

Čili jakákoli snaha toto časově analyzovat je ztráta vašeho času, nebudete to potřebovat, protože internet je u každého uživatele jinak rychlý, a to, co by na vašem PC trvalo třeba spolehlivě do 1sec, tak jinde stoprocentně ne. Nebo i na vašem PC v jinou dobu. A pod.

Jediná správná (a nejrychlejší) metoda je používat návraty k spouštění potřebných procesů.

EDIT: ještě: jak píšu "Váš script (smyčka 1000x) je hotov", to tak bude vždy, pokud to není async funkce, kde to čeká await.
Prostě synchronní funkce se provede celá a nic jí nepřeruší, všechno, co není třeba jen přímý výpočet, zařadí jako požadavky do fronty a ty se vykonávají až po dokončení to jednoho scriptu. Takže spustíte script, ten jde řádek za řádkem, ale obsah třeba fetch() jen pošle do fronty, ale nepočítá ho! (jen ho jakoby nadefinuje), pak třeba něco vypíše do konzole, pak tam můžete mít třeba setTimeout(), jeho obsah taky zařadí do fronty a takto provede všechny řádky a opakuje smyčku. Rychlostí stojového běhu...
Tedy jak píšete "uvnitř" funkce, tak to prostě jen rychle proběhne smyčka, klidně několik vnořených smyček v sobě.
Jinak řečeno, volání jiné standard funkce (synchronní), tak tu samozřejmě vždy celou provede, a pak pokračuje nadřazenou funkcí. Jenže vše velmi rychle, jen výpočty, volaná funkce taky jen vše vřadí do fronty a provede jen přímé výpočty a vrací zpracování zpět.
Je jedno, jestli to uděláte jako smyčku ve smyčce, nebo smyčku, v níž voláte funkci se smyčkou. To je jen jiný zápis téhož.

Jan Buriánek

26.5.2024 v 23:53

Předchozí text jsem psal obecně...
Ještě jsem tedy kouknul na ten kód, co testujete.

V hlavním scriptu (tělo souboru) spustíte smyčku 1000x. To je identické spuštěné funkci, prostě se to jednou spustí startem.
První řádek smyčky přejde do podprogramu, asynchronní funkce NajdiNadmorskouVysku() kterou začne vykonávat opět řádek po řádku. Jakmile doputuje k ...await fetch(apiUrl) tak provede fetch, které zařadí do fronty, a jelikož to je asynchronní a má to počkat await, zastaví podprogram! a vrátí zpracování do nadřazené funkce, čili do výchozí smyčky.
Tam je další řádek porovnání, zda je nadm_vyska_paty větší než nula, ale to nebude, je nadefinována jako nula. Takže else vypíše 0 a 0 a pokračuje ve smyčce podruhé s i=1, zase zavolá podprogram, vytvoří jeho další instanci, a zase se to ihned vrátí za await. A nadm_vyska_paty je stále nula, ještě ani neodešly požadavky na server, natož aby se něco vrátilo..., takže else vypíše 1, 0. A i kdyby se již něco vrátilo, třeba u konce smyčky, byla-li by opravdu dlouhá, tak se to zde ve "vnější" smyčce neprojeví! protože hodnoty jsou vraceny pak do složených uvozovek, které máte v ukázce prázdné, a vykonávat se po návratech bude pouze kód, který bude v těch aktuálně prázdných {}. Nikoli pokračování smyčky. A hlavně: až po dokončení aktuálního scriptu, což je ta synchronní smyčka!!! Tu nic nepřeruší, ani případné návraty, protože ty jsou zařazeny do fronty, kde se bude pokračovat po! dokončení aktuálního scriptu, tedy jak to nazýváte "vnější" smyčky.

Takže smyčka proběhne celá rychlostí strojáku, tedy v rámci max jednotek ms, přičemž nejvíc to zdržuje to console.log()...
Skončí to tedy výpisem 999,0.
A synchronní script skončí. Hotovo. Nyní se chvilku ve vašem kódu nic neděje, čeká se.

No a pak, jak se odesílají požadavky a různě vracejí hodnoty, tak se spouští ty jednotlivé instance podprogramu, kde vždy za prvním await se provede nejprve to json, a zase to zařadí do fronty, jakmile na to přijde řada, tak se provede zbytek podprogramu za druhým await. To už je pak jasné.

Podstatné je to slovo instance. Smyčka vytvoří v paměti PC 1000x stejný "objekt", podprogram, pokaždé s jinými hodnotami a identifikátory, které vnitřně prohlížeč zná, mi programátoři to nepotřebujeme, a prohlížeč je prostě zpracovává, jak přijdou na řadu. A podle těch nějakých vnitřních identifikátorů ví, kterému objektu náleží návrat, tedy když server vrátí promise, tak ví, kterému "objektu", náleží vrácené hodnoty, tedy že návrat je např. k volání ze smyčky s číslem 123, spustí se tedy kód za await vytvořený 123tím voláním ze smyčky, a to si jako ten "objekt" pamatuje všechny hodnoty uvnitř {}, které tam byly do daného await vloženy nebo spočítány. Podprogram po obou awaitech doběhne, vypíše hodnotu, a return vrátí do .then funkce jako value, kterou máte v ukázce dále nevyužitou.

.then((value) => { _ zde je tedy známa hodnota value a i příslušné "i", třeba těch 123 _}
jelikož jste (naštěstí) použil ve smyčce přiřazení let.

Kdybyste tam dal var, tak byste měl ve všech návratech poslední hodnotu "i" 999, ale to je jiný příběh...

Jan Buriánek

27.5.2024 v 9:12

Např. takto se vám to vypíše postupně, vnější smyčka se udělá async a přes await čeká na vrácení hodnoty, pak teprve pokračuje smyčka:
(pro otestování jsem použil souřadnice 15,50 a smyčka jen 10x)

let nadm_vyska_paty = 0;

async function NajdiNadmorskouVysku(souradnice, pocet){
let vysky = []; // pole do ktereho uložím nadmořské výšky v bodech
const apiUrl = 'https://api.mapy.cz/v1/elevation?lang=cs&positions=' + souradnice + '&apikey=' + API_KEY;
const response = await fetch(apiUrl);
const data = await response.json();
if (pocet > 1) pocet++;
for(let i = 0; i < pocet; i++){vysky.push(data.items[i].elevation)}
nadm_vyska_paty = data.items[0].elevation;
console.log("uvnitr: "+nadm_vyska_paty);
if (pocet == 1) return data.items[0].elevation;
else return vysky;
}

async function vnejsiSmycka(){
for (let i = 0; i < 10; i++){
await NajdiNadmorskouVysku(15 + ',' + 50, 1).then((value) => {console.log(i, value, nadm_vyska_paty)})}
}

vnejsiSmycka()

Jan Buriánek

27.5.2024 v 9:33

A ještě jednou, globální proměnná nadm_vyska_paty je pak za await již ve smyčce známa:

async function vnejsiSmycka(){
for (let i = 0; i < 10; i++){
await NajdiNadmorskouVysku(15 + ',' + 50, 1).then((value) => {console.log(i, value, nadm_vyska_paty)})
console.log(i, nadm_vyska_paty) //value zde není definováno!
}
}

Jinak řečeno: chcete-li pokračovat v programu až s vrácenou hodnotou, musíte na ni počkat všude, ve všech nadřazených funkcích / scriptech.

Nový dotaz

Přiložené přílohy

    Zbývá 12MB (z 12MB)

    Jak se spojit s REST API

    Přiložené přílohy

      Zbývá 12MB (z 12MB)