使用 Fetch 创建一个很棒的 JS API 接口(少于 50 行)

2025-05-24

使用 Fetch 创建一个很棒的 JS API 接口(少于 50 行)

在本教程中,我们将创建一个可复用的模块,用不到 50 行代码即可完成所有 API 调用! (点击此处查看最终模块代码)。如果您熟悉 fetch API,您就会明白,由于使用了各种 Promise 链,它看起来会变得多么丑陋和难以理解。

fetch(url)
  .then((response) => response.json())
  .then(data => {
    console.dir(data);
  });
})
Enter fullscreen mode Exit fullscreen mode

呃。你肯定不想在应用中每次 API 调用时都这么做。我们应该把它抽象成一个模块,这样你的调用会更清晰、更容易。这样 API 调用就会像这样:

async function getArticles(userId) {
  const articles = await Fetch.get('/articles/' + userId);
  articles.forEach(item => {
   // iterate through results here...
  });
}
Enter fullscreen mode Exit fullscreen mode

本教程将使用 ES6 模块。开始吧!(注意 async 和 await 关键字)。

创建 Fetch.js 模块骨架

首先,让我们定义用于与模块交互的公共 CRUD 方法并定义 API 主机:

// Fetch.js
const _apiHost = 'https://api.service.com/v1';

export default {
  get,
  create,
  update,
  remove
};
Enter fullscreen mode Exit fullscreen mode

创建主获取方法

接下来,我们在模块内部创建一个私有方法来执行实际的获取操作。这个通用方法应该能够处理读取和写入 API 调用。该方法将接受 3 个参数:

  1. url - API 端点 - 例如:'/articles'
  2. params - 作为 GET 的查询字符串或 POST、UPDATE 和 DELETE 调用的请求主体数据传递给端点的附加参数
  3. 方法- GET(默认)、POST、PUT、DELETE
// Fetch.js
// ...

async function request(url, params, method = 'GET') {

}

// ...
Enter fullscreen mode Exit fullscreen mode

注意函数开头的async 。我们需要它,因为我们要处理Promises

添加选项并确保使用“await”

// Fetch.js
const _apiHost = 'https://api.service.com/v1';

async function request(url, params, method = 'GET') {

  // options passed to the fetch request
  const options = {
    method
  };

  // fetch returns a promise, so we add keyword await to wait until the promise settles
  const response = await fetch(_apiHost + url, options);
  const result = await response.json(); // convert response into JSON

  // returns a single Promise object
  return result;

}

// ...
Enter fullscreen mode Exit fullscreen mode

处理所有请求类型的参数

我们希望此方法能够处理 API 请求中可能需要包含的任何参数。对于GET请求,我们需要支持查询字符串。对于所有其他与写入相关的请求,我们需要能够在请求中包含正文。

我们希望我们的模块超级易用,因此我们将标准化所有情况下的对象处理方式。然后,我们可以将对象转换为GET请求的查询字符串,并将其作为 JSON 格式包含在所有其他类型的请求正文中。

让我们创建对象来查询字符串转换方法:

// Fetch.js

// ...

// converts an object into a query string
// ex: {authorId : 'abc123'} -> &authorId=abc123
function objectToQueryString(obj) {
  return Object.keys(obj).map(key => key + '=' + obj[key]).join('&');
}

// ...
Enter fullscreen mode Exit fullscreen mode

现在我们可以添加一些代码来处理参数(如果存在)。让我们在请求方法中的选项定义之后添加这些代码:

// Fetch.js
const _apiHost = 'https://api.service.com/v1';

async function request(url, params, method = 'GET') {

  const options = {
    method,
    headers: {
      'Content-Type': 'application/json' // we will be sending JSON
    }
  };

  // if params exists and method is GET, add query string to url
  // otherwise, just add params as a "body" property to the options object
  if (params) {
    if (method === 'GET') {
      url += '?' + objectToQueryString(params);
    } else {
      options.body = JSON.stringify(params); // body should match Content-Type in headers option
    }
  }

  const response = await fetch(_apiHost + url, options);
  const result = await response.json();

  return result;

}

function objectToQueryString(obj) {
  return Object.keys(obj).map(key => key + '=' + obj[key]).join('&');
}

// ...
Enter fullscreen mode Exit fullscreen mode

创建公共方法

太棒了!现在让我们创建四个公共方法,用于发出不同的请求。我们将在模块的最底部导出一个引用这四个方法的对象。

// Fetch.js
// ...
function get(url, params) {
  return request(url, params);
}

function create(url, params) {
  return request(url, params, 'POST');
}

 function update(url, params) {
  return request(url, params, 'PUT');
}

function remove(url, params) {
  return request(url, params, 'DELETE');
}
Enter fullscreen mode Exit fullscreen mode

错误处理

在我们的模块中添加一些错误处理是一个好主意。一种方法是检查响应的状态码。如果不是 200,那么我们应该返回某种错误消息。

您可以按照自己想要的方式处理错误。在本例中,我们将返回一个包含状态和消息的对象。让我们在获取请求后立即检查状态:

// Fetch.js

// ...

  const response = await fetch(_apiHost + url, options);

  // show an error if the status code is not 200
  if (response.status !== 200) {
    return generateErrorResponse('The server responded with an unexpected status.');
  }

  const result = await response.json();

  return result;

}

// A generic error handler that just returns an object with status=error and message
function generateErrorResponse(message) {
  return {
    status : 'error',
    message
  };
}
Enter fullscreen mode Exit fullscreen mode

我们做到了!

现在我们可以使用单个模块发出所有四种类型的 API 请求!

异步/等待

我们的 Fetch 调用返回一个 Promise,因此我们需要在调用前使用 await 关键字。此外,await 关键字在顶层代码中不起作用,因此必须将它们包装在异步函数中。这些请求可能如下所示:

import Fetch from './Fetch.js';

// GET
async function getAllBooks() {
  const books = await Fetch.get('/books');
}

// POST
async function createBook() {
  const request = await Fetch.create('/books', {
    title: 'Code and Other Laws of Cyberspace',
    author: 'Lawrence Lessig'
  });
}

// PUT
async function updateBook(bookId) {
  const request = await Fetch.update('/books/' + bookId, {
    title: 'How to Live on Mars',
    author: 'Elon Musk'
  });
}

// DELETE
async function removeBook(bookId) {
  const request = await Fetch.remove('/books/' + bookId);
}
Enter fullscreen mode Exit fullscreen mode

我们完成了 API 接口模块! - 后续步骤

我希望您喜欢本教程并且可以利用它来提高工作效率!

您可以向此模块以及 fetch 请求本身添加各种其他选项。例如,您需要在 fetch 方法中添加哪些参数来支持 CORS 请求?

您将如何处理文件上传

祝您取物愉快!

// Fetch.js
const _apiHost = 'https://api.service.com/v1';

async function request(url, params, method = 'GET') {

  const options = {
    method,
    headers: {
      'Content-Type': 'application/json'
    }
  };

  if (params) {
    if (method === 'GET') {
      url += '?' + objectToQueryString(params);
    } else {
      options.body = JSON.stringify(params);
    }
  }

  const response = await fetch(_apiHost + url, options);

  if (response.status !== 200) {
    return generateErrorResponse('The server responded with an unexpected status.');
  }

  const result = await response.json();

  return result;

}

function objectToQueryString(obj) {
  return Object.keys(obj).map(key => key + '=' + obj[key]).join('&');
}

function generateErrorResponse(message) {
  return {
    status : 'error',
    message
  };
}

function get(url, params) {
  return request(url, params);
}

function create(url, params) {
  return request(url, params, 'POST');
}

 function update(url, params) {
  return request(url, params, 'PUT');
}

function remove(url, params) {
  return request(url, params, 'DELETE');
}

export default {
  get,
  create,
  update,
  remove
};

Enter fullscreen mode Exit fullscreen mode
文章来源:https://dev.to/eaich/create-an-awesome-js-api-interface-using-fetch-in-less-than-50-lines-3d65
PREV
一个人/一本书改变了我的生活并让我成为了更好的开发人员
NEXT
启动网站前您应该了解的 6 个基本工具