🎃

LWCでPokeAPIを使った簡単なポケモン図鑑を作る

2023/09/29に公開

はじめに

LWCを学習中ですが、
日業務で外部APIを使って様々な情報を取得していくことが求められてきます。
そこで、キャッチアップも兼ねて、LWCでPoleAPIを使った簡単なポケモン図鑑を作ってみようと思いました。

この記事でわかること

  1. LWCとApexを繋げてRESTコールアウトを実行する。
  2. PokeAPIを使ったデータの取得方法。

完成イメージ


数字を入れて、Let's Go!を押下すると、

該当のポケモンのデータが表示される様になります。

ファイル関係イメージ

手順

①ApexClassを作成

PokemonParent.cls

public with sharing class PokemonParent {

    @AuraEnabled
    static public Map<String, String> getName(String inputValue) {
        Http http = new Http();
        Http imgHttp = new Http();
        HttpRequest request = new HttpRequest();
        System.debug(inputValue);
        request.setEndpoint('https://pokeapi.co/api/v2/pokemon-species/'+inputValue);
        request.setMethod('GET');

        HttpResponse response = http.send(request);

        //名前を取得するメソッド
        if (response.getStatusCode() == 200) {
            Map<String, Object> results = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());

            Map<String, String> apexResult = new Map<String, String>();

            apexResult.put('name',getName(results));
            apexResult.put('flavorText',getFlavors(results));
            apexResult.put('img',inputValue);
            return apexResult;
        } else {
            return null;
        }
    }

    static String getName(Map<String, Object> results){
        list<Object> names = (list<Object>) results.get('names');

        String japaneseName = null;


        for (Object nameInfo: names) {
            Map<String, Object> nameMap = (Map<String, Object>) nameInfo;

            Map<String, Object> nameLanguage = (Map<String, Object>)nameMap.get('language');
            String name = (String)nameMap.get('name');
            if(nameLanguage.get('name')=='ja') {
                japaneseName = name;
                break;
            }
        }
        if (japaneseName==null) {
            japaneseName = '該当なし';
        }
        return japaneseName;
    }
    static String getFlavors(Map<String, Object> results){
        String japaneseText = null;
        list<Object> flavors = (list<Object>) results.get('flavor_text_entries');
        for (Object flavor: flavors ) {
            Map<String, Object> flavorMap = (Map<String, Object>)flavor;
            Map<String, Object> flavorLanguage = (Map<String, Object>)flavorMap.get('language');
            String flavorText = (String)flavorMap.get('flavor_text');
            if(flavorLanguage.get('name')=='ja') {
                japaneseText = flavorText;
                break;
            }
        }
        if(japaneseText==null){
            japaneseText = '不明';
        }
        return japaneseText;
    }
}



②HTMLを作成

pokemonParent.html

<template>
  <div class="slds-section slds-is-open">
    <div class="header-component">
      <div class="header-child1">
        <h3 class="slds-section__title">
          <button class="slds-button slds-section__title-action">
            <span class="slds-truncate" title="Section Title"
              >ポケモン図鑑</span
            >
          </button>
        </h3>
      </div>
      <div class="header-child2">
        <button class="slds-button slds-button_neutral" onclick={handleClick}>
          Les's Go!!
        </button>
      </div>
    </div>
    <div class="body-component">
      <div class="form-row">
        <label class="label">ポケモン図鑑No.:</label>
        <input
          id="inputField"
          type="number"
          value={inputValue}
          onchange={handleInputChange}
          min="1"
          max="1010"
        />
      </div>
      <div class="form-row">
        <label class="label">ポケモンの名前:</label>
        <label id="nameField">{pokeName}</label>
      </div>
      <div class="form-row">
        <label class="label" for="flavorTextField">ポケモンの説明:</label>
        <label class="input-flavor-text">{flavorText}</label>
      </div>
      <template if:true={imageUrl}>
        <div class="form-row">
          <img src={imageUrl} alt="Pokemon Image" />
        </div>
      </template>
    </div>
  </div>
</template>


③CSSを作成

pokemonParent.css

.header-component {
    background-color: #f3f4f6;
    display: flex;
    justify-content: space-between;
}

.label-preview {
    width: 180px;
    margin: 5px;
}

.header-child2 {
    margin: 0 10px;
}

.body-component {
    background-color: #fff;
}

.form-row {
    display: flex;
    align-items: center;
}

.label {
    width: 150px;
    margin: 5px;
}

.input {
    width: 180px;
    margin: 5px;
}

.input-flavor-text {
    display: flex;
    flex-direction: column;
    justify-content: center;
    width: 600px;
    height: 30px;
    margin: 5px;
}


④JavaScriptを作成

pokemonParent.js

import { LightningElement, track } from "lwc";
import getPokeName from "@salesforce/apex/PokemonParent.getName";

export default class PokemonParent extends LightningElement {
  @track pokeName = null;
  @track flavorText = null;
  @track inputValue = null;
  @track imageUrl = null;
  @track inputError = false;

  handleInputChange(event) {
    const regex = /^(1000|100[0-9]|[1-9][0-9]{0,2}|[1-9])$/;
    if (regex.test(event.target.value)) {
      console.log(event.target.value);
      this.inputValue = event.target.value;
    } else {
      alert("不正な値です。");
    }
  }

  handleClick() {
    getPokeName({ inputValue: this.inputValue })
      .then((result) => {
        this.pokeName = result.name;
        this.flavorText = result.flavorText;
        const imgId = this.inputValue; // ポケモンのIDに応じて設定
        this.imageUrl = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/${imgId}.png`;
      })
      .catch((error) => {
        console.error("handleClick error: ", error);
      });
  }
}


挙動確認


動きました。

Discussion