Diferencia entre revisiones de «PHP Promise e Fetch»

De MediaWiki
Ir a la navegación Ir a la búsqueda
Línea 122: Línea 122:
 
==Funcionamento==
 
==Funcionamento==
  
−
* Máis información en: https://developer.mozilla.org/es/docs/Web/API/Fetch_API/Using_Fetch
+
* Máis información en:  
 +
:* https://developer.mozilla.org/es/docs/Web/API/Fetch_API/Using_Fetch
 +
:* Para entender todo o contido é necesario que teñades feito o indicado na [https://wiki.cifprodolfoucha.es/index.php?title=PHP_Servizos_Web UD6 - Servizos Web]
 +
 
 +
 
  
 
* '''<u>IMPORTANTE:</u>''' Tedes que ter claro que este código se executa no cliente (no navegador). Polo tanto a información se obtén directamente da fonte sen necesidade de volver a cargar a páxina, como fixemos ata o de agora. Isto ten vantaxes e desvantaxes.
 
* '''<u>IMPORTANTE:</u>''' Tedes que ter claro que este código se executa no cliente (no navegador). Polo tanto a información se obtén directamente da fonte sen necesidade de volver a cargar a páxina, como fixemos ata o de agora. Isto ten vantaxes e desvantaxes.
Línea 307: Línea 311:
 
: Nos imos empregalo para obter datos empregando GET e peticións a unha API RestFul aberta que non necesite token de acceso, pero poderíamos empregalo para moito máis.
 
: Nos imos empregalo para obter datos empregando GET e peticións a unha API RestFul aberta que non necesite token de acceso, pero poderíamos empregalo para moito máis.
  
 +
 +
'''Exemplo de solicitude POST''':
 +
:<syntaxhighlight lang="java" enclose="div" highlight="">
 +
fetch('https://jsonplaceholder.typicode.com/posts', {
 +
  method: 'POST', // Método HTTP
 +
  headers: {
 +
    'Content-Type': 'application/json', // Indica o tipo de contido que se está enviando
 +
  },
 +
  body: JSON.stringify({ // Convirte o obxecto JavaScript nunha cadea JSON
 +
    title: 'foo',
 +
    body: 'bar',
 +
    userId: 1,
 +
  }),
 +
})
 +
  .then(response => response.json())
 +
  .then(data => console.log(data));
 +
 +
</syntaxhighlight>
 +
 +
 +
 +
 +
'''Exemplo de emprego de headers personalizados'''
 +
: Neste exemplo, un suposta API Restful pide un token de autenticación.
 +
:<syntaxhighlight lang="java" enclose="div" highlight="">
 +
fetch('https://jsonplaceholder.typicode.com/posts/1', {
 +
  headers: {
 +
    'Authorization': 'Bearer o teu_token_de_acceso_aquí',
 +
  },
 +
})
 +
  .then(response => response.json())
 +
  .then(data => console.log(data));
 +
 +
</syntaxhighlight>
 +
 +
 +
 +
 +
 +
<br />
 +
==Recuperar datos dende unha ApiRestFul feita por nos==
  
  
  
 +
<br />
 +
==Recuperar datos dende unha ApiRestFull de Internet==
  
 
:<syntaxhighlight lang="java" enclose="div" highlight="">
 
:<syntaxhighlight lang="java" enclose="div" highlight="">

Revisión del 16:39 29 mar 2024

Introdución

  • Unha promise ven ser unha petición que realizamos de forma asíncrona a un servidor e que permite que o código do cliente continúe a súa execución.
Una promesa ten tres estados:
  • Resolved: Unha promesa normalmente vai solicitar unha información a un servidor. Cando dispón de dita información pasa ao estado resolved.
  • Rejected: Cando a promesa non devolve un valor ou cando se produce unha excepción debido a que o valor devolto non ten o formato correcto.
  • Pending: Cando xa iniciamos a petición e aínda non tivemos resposta.
Unha promesa pode pasar do estado pending a resolved ou rejected e non pode ter transaccións entre os estados.


  • Fetch tamén realiza unha operación asíncrona e devolve unha promesa xa preparada para o seu uso. Ten asociados tres métodos:
  • .then(): Onde se reciben os datos.
  • .catch(): Se se produce algunha excepción
  • .finally(): Un código que podemos executar tanto se foi ben (then) como se foi mal (catch) a chamada a obtención de datos de forma asíncrona.


  • Se os dous fan o mesmo, en que se diferencian ?
Digamos que promise, que é parte da linguaxe JavaScript, é mais de 'proposito xeral'. Permite facer calquera tipo de petición asíncronas e permite executar múltiples operacións asíncronas e executalas en orde, unha despois de outra.
Fetch pola súa parte, é unha función da API Fetch que está orientada a ser empregada para facer peticións de rede e recibir información de ditas solicitudes (por exemplo empregando HTTP Requests).


  • Nos imos ver fetch xa que o imos empregar para realizar peticións a API Rest e obter os resultados.



Preparación

Aínda que se pode probar dende calquera proxecto, eu parto de que tedes un proxecto Laravel 10 có seguinte:
Arquivo: /routes/web/web.php
Route::get('/probas', function () {
    return view('probas');
})->name('probas');
Fixádevos que a ruta vai directamente á vista e non pasa por un controlador. Isto é debido a que os datos que vou amosar os vou cargar dende o cliente empregando fetch. Isto non quita que nos vosos proxectos pasedes por un controlador para facer unha xestión ou recuperar datos dunha base de datos.


Arquivo: /resources/views/principal.blade.php
<html>
    <head>
        <meta charset="UTF-8">
        <link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet" />
        <script src="{{ asset('js/bootstrap.min.js') }}"></script>
    </head>
    <body>
<nav class="navbar navbar-expand-lg bg-primary" data-bs-theme="dark">
  <div class="container-fluid">
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarColor01">
      <ul class="navbar-nav me-auto">
        <li class="nav-item">
            <a class="nav-link" href="{{route('probas')}}">Probas</a>
        </li>

      </ul>
   </div>
  </div>
</nav>


        @yield('content')

        @yield('antesdefinbody')
    </body>

</html>
  • Fixarse que creo dúas seccións:
  • 'content' onde irán os contidos da páxina
  • 'antesdefinbody': onde irán os arquivos javascript que farán o fetch dos datos.


Arquivo: /resource/views/probas.blade.php
@extends('principal')


@section('content')

<h3>Probas</h3>
<div class="container text-center mt-5">
    <input type="button" value="CARGAR DATOS DE INTERNET" onclick="javascript:cargarProbas()"/>
    <h5>Cargando datos dende internet</h5>
    <div id='idProbaImaxe'></div>
</div>

@endsection

@section('antesdefinbody')
    <script src="{{asset('js/cargarProba1.js')}}"></script>
@endsection
  • Fixarse como na sección 'antesdefinbody' cargo os arquivos javascript. Isto poderíamos facelo localmente pero desta forma, a nivel de mantemento e claridade queda mellor.


Arquivo: /public/js/cargarProba1.js
function cargarProbas(){
}
  • Aquí irá o código javascript que iremos poñendo en cada proba que fagamos.



Funcionamento

  • Máis información en:


  • IMPORTANTE: Tedes que ter claro que este código se executa no cliente (no navegador). Polo tanto a información se obtén directamente da fonte sen necesidade de volver a cargar a páxina, como fixemos ata o de agora. Isto ten vantaxes e desvantaxes.
Vantaxes:
  • Liberade carga de traballo do servidor, sempre que a información a recuperar se atope noutro servidor diferente.
  • Non se ten que volver a cargar a páxina enteira, soamente aquelas partes nas que queirades actualizar a información.
  • Latencia de carga menor xa que accedes directamente á información sen pasar polo servidor.
Desvantaxes:
  • Non podedes empregar métodos de validación para obter a información xa que os token's estarían visibles para todo o mundo.
  • Política do Mesmo Orixen (CORS): Restriccións de CORS se o servizo externo non permite explicitamente solicitudes dende o teu dominio.
  • Xestión de Erros: Debes manexar os posibles erros de rede e os casos no que o servizo externo estea inaccesible.


  • O funcionamento é moi sinxelo.
Recordar que isto é javascript, e polo tanto o código terá que ir entre etiquetas <script> </script> ou ben poñer o código nun arquivo separado e facer un <script src="arquivo.js"></script>


Retorna 4 campos. Imos visualizar na consola o que nos devolve.
  • Imos facelo empregando o proxecto de Laravel anterior.


Arquivo: /public/js/cargarProba1.js
function cargarProba1(){
    const url = 'https://jsonplaceholder.typicode.com/posts/1';
    fetch(url)
        .then(function(response) {
                if(response.ok){
                    console.log(response);
                }
                else{
                    console.log("Resposta de rede OK pero resposta HTTP no ok")
                }

            }
        )
        .catch(function(error) {
            console.error('Erro ao cargar:', error);
        });
}


Arquivo: /resources/views/probas.blade.php
@extends('principal')


@section('content')

<h3>Probas</h3>
<div class="container text-center mt-5">
    <input type="button" value="CARGAR DATOS DE INTERNET" onclick="javascript:cargarProba1()"/>
    <h5>Cargando datos dende internet</h5>
    <div id='idProba1'></div>
</div>

@endsection

@section('antesdefinbody')
    <script src="{{asset('js/cargarProbas.js')}}"></script>
@endsection


  • Temos que ter o proxecto laravel en funcionamento coa orde: php artisan serve
Isto fai que o servidor web local estea escoitando no porto 8000. Cargamos páxina de probas poñendo no navegador: http://localhost:8000/probas






  • Agora imos facer algunha mellora ao código anterior.
Como vemos, dentro do then, imos a executar unha función anónima que recibe como parámetro un obxecto da clase Response, que chamamos response: .then(function(response) {}
Nota: Lembrar recargar a páxina para que cargue o novo código.


Iso é equivalente a poñer isto:
function cargarProba1(){
    const url = 'https://jsonplaceholder.typicode.com/posts/1';
    fetch(url)
        .then(response => {
                if(response.ok){
                    console.log(response);
                }
                else{
                    console.log("Resposta de rede OK pero resposta HTTP no ok")
                }

            }
        )
        .catch(error => {
            console.error('Erro ao cargar:', error);
        });
}


  • Agora imos avanzar un pouco máis.
A nos o que nos interesa é o corpo da resposta e non o obxecto response que engloba a resposta e outra información, como o estado da resposta (propiedade status).
Para obtela, imos convertir a resposta en un obxecto javascript o array de javascript (dependendo do tipo de resposta).
Nota: Lembrar recargar a páxina para que cargue o novo código.
function cargarProba1(){
    const url = 'https://jsonplaceholder.typicode.com/posts/1';
    fetch(url)
        .then(response => {
                if(response.ok){
                    return response.json();
                }
                else{
                    console.log("Resposta de rede OK pero resposta HTTP no ok")
                }

            }
        )
        .then(datos => {
            console.log(datos);
            console.log('TITULO:' + datos.title);
            console.log(`body:${datos.body}`);
        }
        )
        .catch(error => {
            console.error('Erro ao cargar:', error);
        });
}


Fixarse o que estamos a facer neste código. Unha vez recuperamos o obxecto response, facemos un return de response.json().
O que vai facer .json() é extraer o corpo da mensaxe e pasalo a un obxecto javascript. Isto o vai facer retornando unha promesa. Isto quere dicir que para obter o corpo o vai facer de forma asíncrona e agora por tanto, necesitamos facer un 'then' para obter a resposta (segundo then da liña 14).
Ao igual que có fetch, o resultado (then) vai vir nunha variable que chamo 'datos' e amoso dito dato en consola.
Fixarse como para obter un dato concreto poñemos punto e o nome do campo. Podemos empregar o máis para concatenar ou a comilla orientada cara a dereita e empregar dentro de ditas comillas a formato: ${variable}


  • Agora o que necesitamos é visualizar dito contido na páxina HTML. Para iso imos obter un obxecto que vai representar o div con id='idProba1' e imos engadirlle contido dinamicamente.
Nota: Lembrar recargar a páxina para que cargue o novo código.
function cargarProba1(){
    const url = 'https://jsonplaceholder.typicode.com/posts/1';
    fetch(url)
        .then(response => {
                if(response.ok){
                    return response.json();
                }
                else{
                    console.log("Resposta de rede OK pero resposta HTTP no ok")
                }

            }
        )
        .then(datos => {
            const contenedor = document.getElementById('idProba1');
            contenedor.innerHTML=`TITULO: <strong>${datos.title}</strong>`;
        }
        )
        .catch(error => {
            console.error('Erro ao cargar:', error);
        });
}
Liña 15: Obtemos nunha constante o div en forma de obxecto javascript.
Liña 16: Cambiamos a propiedade innerHTML xa que imos engadir código html (strong neste caso) ao seu contido. Se fora soamente texto poderíamos empregar innerText


  • Pois isto é a base de calquera petición que fagades empregando fetch.
Nos imos empregalo para obter datos empregando GET e peticións a unha API RestFul aberta que non necesite token de acceso, pero poderíamos empregalo para moito máis.


Exemplo de solicitude POST:

fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST', // Método HTTP
  headers: {
    'Content-Type': 'application/json', // Indica o tipo de contido que se está enviando
  },
  body: JSON.stringify({ // Convirte o obxecto JavaScript nunha cadea JSON
    title: 'foo',
    body: 'bar',
    userId: 1,
  }),
})
  .then(response => response.json())
  .then(data => console.log(data));



Exemplo de emprego de headers personalizados

Neste exemplo, un suposta API Restful pide un token de autenticación.
fetch('https://jsonplaceholder.typicode.com/posts/1', {
  headers: {
    'Authorization': 'Bearer o teu_token_de_acceso_aquí',
  },
})
  .then(response => response.json())
  .then(data => console.log(data));




Recuperar datos dende unha ApiRestFul feita por nos


Recuperar datos dende unha ApiRestFull de Internet





Volver á UD7



-- Ángel D. Fernández González -- (2024).