当サイトは、アフィリエイト広告を利用しています
javascriptの非同期通信処理のFetch API
について調べたので忘備録として残す。
Fetch APIは、ブラウザのJavaScript環境で提供される
HTTPリクエストを行うためのネイティブなAPI。
Fetch APIは、従来のXMLHttpRequestよりもモダンで
直感的な方法でHTTPリクエストを処理することができる
中身的なことをいうとPromiseを使ってブラウザと WEBサーバ間でデータの送受信を行うことができる。
javascriptで非同期通信を行う方法はfetchAPIを使う他に
を使う方法がある
それぞれ下記でまとめています。
fetch('URL等',{option}).then(...);
fechの結果はPromiseオブジェクトで返却され、resolveにはResponseオブジェクトが 渡される。
オプションの詳細はFetch の使用参照
fetchAPIの戻り値のresolveに渡されるオブジェクト
通信結果ステータスや取得したdataなどを保持している
response.ok
ok:通信が成功したかどうか
response.status
status:レスポンスのステータスコード
などをもっている。
メソッドとしては
をもっておりこれらのメソッドは全てPromiseを返す。
fetchAPIのPromiseが解決されるのはレスポンスヘッダが全部返ってきたときのため
本文部分は別のPromiseで取得することになる。
HTTPのレスポンスは下記の順で返却され、
詳しくはResponseを参照
jsonplaceholderからのデータ取得をfechAPIを実装してみる
const fech = () =>fetch("https://jsonplaceholder.typicode.com/todos/1", {method: "GET"}).then((response) => {if (response.ok) {// jsonに変換する// Promiseで返却されるreturn response.json();} else {// rejectthrow new Error(response.status);}})// response.json()のresolve.then((res) => {// jsonに変換したresをログ表示console.log(JSON.stringify(res, null, 3));})// rejectの結果を処理.catch((status) => console.log(status));fech();// 実行結果// {// "userId": 1,// "id": 1,// "title": "delectus aut autem",// "completed": false// }
fetchをasync、awaitと組み合わせて使うことで下記のような利点がある
同期処理のように書ける
可読性が高い
.then()
チェーンよりもスッキリして読みやすい。エラーハンドリングを一箇所でできる
await
を try...catch
でまとめて安全に処理できる。fetch
の失敗も、response.json()
の失敗もまとめて対応できる。// 非同期関数として定義(fetchをawaitで使うため)const fechFunc = async () => {// 送信するデータ(JSON形式)const sendData = {title: "a1 test",body: "this is test by a1",userId: 1,};// fetchによる非同期通信(POSTリクエスト)// エラー処理は try-catch で行うtry {const response = await fetch("https://jsonplaceholder.typicode.com/posts", {method: "POST", // HTTPメソッド:POST(データ送信)headers: {"Content-Type": "application/json", // 送信データの形式を指定},body: JSON.stringify(sendData), // JavaScriptオブジェクトをJSON文字列に変換して送信});// レスポンスのステータスコードが成功(200台)以外の場合はエラーとして処理if (!response.ok) {throw new Error(response.status); // エラーステータスを例外として投げる}// レスポンスのJSONデータを取得(非同期処理)const data = await response.json();// 結果を整形してコンソールに出力(インデント3)console.log(JSON.stringify(data, null, 3));} catch (error) {// エラーが発生した場合にここで処理されるconsole.log("Error:", error.message);}};// 非同期関数を実行fechFunc();// 実行結果// {// "title": "a1 test",// "body": "this is test by a1",// "userId": 1,// "id": 101// }
reactでサンプル実装してみる
fetchAPIを使い、jsonplaceholderにPOSTでデータを登録し
登録したデータを取得、画面に表示する
/** @jsxImportSource @emotion/react */import { css } from '@emotion/react';import React, { useState } from 'react';export default function App() {const [post, setPosts] = useState([]);// POSTの登録処理const registData = async () => {// 送るデータconst sendData = [{title: 'a1 test',body: 'this is test by a1',userId: 1,},{title: 'a2 test',body: 'this is test by a2',userId: 2,},];try {// fetchで非同期通信処理const res = await fetch('https://jsonplaceholder.typicode.com/posts', {method: 'POST',// サーバに対してヘッダーで解析方法を指定するheaders: {'Content-Type': 'application/json',},// 送るデータbody: JSON.stringify(sendData),});if (!res.ok) {throw new Error(response.status);}// レスポンスのJSONデータを取得(非同期処理)const data = await res.json();// オブジェクトを表示用にListに変換if ('object' === typeof data) {//stateを更新setPosts(() =>Object.values(data).filter((prop) => typeof prop === 'object'));}} catch (status) {console.log(status);}};return (<div><h2>データ</h2><button type="button" onClick={() => registData()}>データ取得</button><div>{post &&post.map(({ userId, id, title }) => (<div css={Container} key={title}><div css={item}>{userId}</div><div css={item}>{title}</div></div>))}</div></div>);}const Container = () => [css`display: flex;justify-content: flex-start;`,];const item = () => [css`text-align: center;width: 100%;border: 1px solid black;`,];
fetchAPIを使い、jsonplaceholderにPOSTでデータを取得し、
画面の検索条件で絞り込む
/** @jsxImportSource @emotion/react */import { css } from '@emotion/react';import React, { useEffect, useRef, useState } from 'react';export default function App() {// 取得データstateconst [post, setPosts] = useState([]);// 検索条件const [query, setQuery] = useState();const queryRef = useRef(null);// 検索処理const search = () => {// useRefの値でqueryのstateを更新if (queryRef.current.value) {setQuery(() => Number(queryRef.current.value));}};useEffect(() => {//queryのstateが更新された場合にデータ取得registData(query);}, [query]);// データ取得処理const registData = async (query) => {try {const response = await fetch('https://jsonplaceholder.typicode.com/posts',{method: 'GET',});if (!response.ok) {throw new Error(response.status);}const data = await response.json();// 画面表示データをqueryで絞り込んだデータで更新setPosts(() => data.filter((record) => record.userId === query));} catch (error) {console.error('データ取得に失敗しました:', error);}};return (<div><h2>データ</h2><input ref={queryRef} placeholder="Please input Number Only" /><button type="button" onClick={() => search()}>検索</button><div>{post &&post.map(({ userId, id, title }) => (<div css={Container} key={title}><div css={item}>{userId}</div><div css={item}>{title}</div></div>))}</div></div>);}const Container = () => [css`display: flex;justify-content: flex-start;`,];const item = () => [css`text-align: center;width: 100%;border: 1px solid black;`,];
FetchAPIはモダンブラウザの標準機能のためライブラリのインストールなどは不要だが
使えないブラウザもあるため注意が必要
FetchAPIはサーバーからヘッダーまで帰ってきた時点で成功となるため
ステータスコードの404や500が帰ってきたとしてもエラーにならないため
responseオブジェクトのokプロパティで対応する必要がある