Comment utiliser l'API de recherche de Wikipedia pour créer une interface utilisateur avec RamdaJS

Dans ce didacticiel, nous allons créer une interface utilisateur à l'aide de l'API de recherche publique de Wikipédia avec du JavaScript + RamdaJS.

Commencer

Voici le lien GitHub et le lien Codesandbox. Ouvrez votre terminal et choisissez un répertoire pour le cloner.

git clone [//github.com/yazeedb/ramda-wikipedia-search](//github.com/yazeedb/ramda-wikipedia-search) cd ramda-wikipedia-search yarn install (or npm install) 

La masterbranche a le projet fini, alors vérifiez la startbranche si vous souhaitez coder.

git checkout start

Et lancez le projet!

npm start

Votre navigateur devrait ouvrir automatiquement localhost: 1234.

Obtenir la valeur d'entrée

Voici l'application initiale.

Pour capturer l'entrée de l'utilisateur au fur et à mesure de sa saisie, notre inputélément a besoin d'un écouteur d'événements.

Votre src/index.jsfichier est déjà connecté et prêt à être utilisé. Vous remarquerez que nous avons importé Bootstrap pour le style.

Ajoutons un écouteur d'événement factice pour faire avancer les choses.

import 'bootstrap/dist/css/bootstrap.min.css'; const inputElement = document.querySelector('input'); inputElement.addEventListener('keyup', (event) => { console.log('value:', event.target.value); }); 

Nous savons que c'est event.target.valuela manière standard d'accéder à la valeur d'une entrée. Maintenant, il montre la valeur.

Comment Ramda peut-il nous aider à atteindre les objectifs suivants?

  • Saisir event.target.value
  • Découper la sortie (espace blanc de début / de fin de bande)
  • Chaîne vide par défaut si undefined

La pathOrfonction peut en fait gérer les premier et troisième puces. Il prend trois paramètres: la valeur par défaut, le chemin et les données.

Donc, ce qui suit fonctionne parfaitement

import { pathOr } from 'ramda'; const getInputValue = pathOr('', ['target', 'value']); 

Si event.target.valuec'est le cas undefined, nous récupérerons une chaîne vide!

Ramda a également une trimfonction, ce qui résout notre problème d'espace blanc.

import { pathOr, trim } from 'ramda'; const getInputValue = (event) => trim(pathOr('', ['target', 'value'], event)); 

Au lieu d'imbriquer ces fonctions, utilisons pipe. Voir mon article sur la pipe s'il est nouveau pour vous.

import { pathOr, pipe, trim } from 'ramda'; const getInputValue = pipe( pathOr('', ['target', 'value']), trim ); 

Nous avons maintenant une fonction composée qui prend un eventobjet, le saisit, le prend par target.valuedéfaut ''et le rogne.

Magnifique.

Je recommande de stocker cela dans un fichier séparé. Appelez-le peut-être getInputValue.jset utilisez la syntaxe d'exportation par défaut.

Obtenir l'URL Wikipédia

Au moment d'écrire ces lignes, l'URL de recherche de l'API de Wikipedia est //en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=

Pour une recherche réelle, ajoutez simplement un sujet. Si vous avez besoin d'ours, par exemple, l'URL ressemble à ceci:

//en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=bears

Nous aimerions une fonction qui prend un sujet et renvoie l'URL de recherche Wikipedia complète. Au fur et à mesure que l'utilisateur tape, nous construisons l'URL en fonction de leur entrée.

Ramda concatfonctionne bien ici.

import { concat } from 'ramda'; const getWikipediaSearchUrlFor = concat( '//en.wikipedia.org/w/api.php?origin=*&action=opensearch&search=' ); 

concat, fidèle à son nom, concatène des chaînes et des tableaux. C'est curieux, donc fournir l'URL comme un argument renvoie une fonction qui attend une deuxième chaîne. Voir mon article sur le curry s'il est nouveau!

Mettez ce code dans un module appelé getUrl.js.

Maintenant, mettons à jour index.js. Importez nos deux nouveaux modules, avec pipeet tapdepuis Ramda.

import 'bootstrap/dist/css/bootstrap.min.css'; import { pipe, tap } from 'ramda'; import getInputValue from './getInputValue'; import getUrl from './getUrl'; const makeUrlFromInput = pipe( getInputValue, getUrl, tap(console.warn) ); const inputElement = document.querySelector('input'); inputElement.addEventListener('keyup', makeUrlFromInput); 

Ce nouveau code construit notre URL de requête à partir de l'entrée de l'utilisateur et la consignera via tap.

Vérifiez-le.

Faire la demande AJAX

L'étape suivante consiste à mapper cette URL sur une requête AJAX et à collecter la réponse JSON.

Remplacer makeUrlFromInputpar une nouvelle fonction searchAndRenderResults,.

const searchAndRenderResults = pipe( getInputValue, getUrl, (url) => fetch(url) .then((res) => res.json()) .then(console.warn) ); 

N'oubliez pas de changer votre auditeur d'événement aussi!

inputElement.addEventListener('keyup', searchAndRenderResults); 

Voici notre résultat.

Créer un composant de résultats

Maintenant que nous avons JSON, créons un composant qui le sublime.

Ajoutez Results.jsà votre annuaire.

Revenez à notre réponse JSON de recherche Wikipedia. Notez sa forme. C'est un tableau avec les indices suivants:

  1. Requête (ce que vous avez recherché)
  2. Tableau de noms de résultats
  3. Tableau de résumés
  4. Array of links to results

Our component can take an array of this shape and return a nicely formatted list. Through ES6 array destructuring, we can use that as our function signature.

Edit Results.js

export default ([query, names, summaries, links]) => ` 

Searching for "${query}"

    ${names.map( (name, index) => `
  • ${name}

    ${summaries[index]}

  • ` )}
`;

Let’s go step by step.

Original text


  • It’s a function that takes an array of our expected elements: query, names, summaries, and links.
  • Using ES6 template literals, it returns an HTML string with a title and a list.
  • Inside the
      we map names to
    • tags, so one for each.
    • Inside those are tags pointing to each result’s link. Each link opens in a new tab.
    • Below the link is a paragraph summary.

    Import this in index.js and use it like so:

    // ... import Results from './Results'; // ... const searchAndRenderResults = pipe( getInputValue, getUrl, (url) => fetch(url) .then((res) => res.json()) .then(Results) .then(console.warn) ); 

    This passes the Wikipedia JSON to Results and logs the result. You should be seeing a bunch of HTML in your DevTools console!

    All that’s left is to render it to the DOM. A simple render function should do the trick.

    const render = (markup) => { const resultsElement = document.getElementById('results'); resultsElement.innerHTML = markup; }; 

    Replace console.warn with the render function.

    const searchAndRenderResults = pipe( getInputValue, getUrl, (url) => fetch(url) .then((res) => res.json()) .then(Results) .then(render) ); 

    And check it out!

    Each link should open in a new tab.

    Removing Those Weird Commas

    You may have noticed something off about our fresh UI.

    It has extra commas! Why??

    Template Literals

    It’s all about how template literals join things. If you stick in an array, it’ll join it using the toString() method.

    See how this becomes joined?

    const joined = [1, 2, 3].toString(); console.log(joined); // 1,2,3 console.log(typeof joined); // string 

    Template literals do that if you put arrays inside of them.

    const nums = [1, 2, 3]; const msg = `My favorite nums are ${nums}`; console.log(msg); // My favorite nums are 1,2,3 

    You can fix that by joining the array without commas. Just use an empty string.

    const nums = [1, 2, 3]; const msg = `My favorite nums are ${nums.join('')}`; console.log(msg); // My favorite nums are 123 

    Edit Results.js to use the join method.

    export default ([query, names, summaries, links]) => ` 

    Searching for "${query}"

      ${names .map( (name, index) => `
    • ${name}

      ${summaries[index]}

    • ` ) .join('')}
    `;

    Now your UI’s much cleaner.

    Fixing a Little Bug

    I found a little bug while building this. Did you notice it?

    Emptying the input throws this error.

    That’s because we’re sending an AJAX request without a search topic. Check out the URL in your Network tab.

    That link points to a default HTML page. We didn’t get JSON back because we didn’t specify a search topic.

    To prevent this from happening we can avoid sending the request if the input's empty.

    We need a function that does nothing if the input's empty, and does the search if it’s filled.

    Let’s first create a function called doNothing. You can guess what it looks like.

    const doNothing = () => {}; 

    This is better known as noOp, but I like doNothing in this context.

    Next remove getInputValue from your searchAndRenderResults function. We need a bit more security before using it.

    const searchAndRenderResults = pipe( getUrl, (url) => fetch(url) .then((res) => res.json()) .then(Results) .then(render) ); 

    Import ifElse and isEmpty from Ramda.

    import { ifElse, isEmpty, pipe, tap } from 'ramda'; 

    Add another function, makeSearchRequestIfValid.

    const makeSearchRequestIfValid = pipe( getInputValue, ifElse(isEmpty, doNothing, searchAndRenderResults) ); 

    Take a minute to absorb that.

    If the input value’s empty, do nothing. Else, search and render the results.

    You can gather that information just by reading the function. That’s expressive.

    Ramda’s isEmpty function works with strings, arrays, objects.

    This makes it perfect to test our input value.

    ifElse fits here because when isEmpty returns true, doNothing runs. Otherwise searchAndRenderResults runs.

    Lastly, update your event handler.

    inputElement.addEventListener('keyup', makeSearchRequestIfValid); 

    And check the results. No more errors when clearing the input!

    This tutorial was from mycompletely freecourse on Educative.io, Functional Programming Patterns With RamdaJS!

    Please consider taking/sharing it if you enjoyed this content.

    It’s full of lessons, graphics, exercises, and runnable code samples to teach you a basic functional programming style using RamdaJS.

    Thank you for reading ❤️