」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 透過 REST API 上的 GraphQL 增強 React 應用程式

透過 REST API 上的 GraphQL 增強 React 應用程式

發佈於2024-11-07
瀏覽:357

In the rapidly changing world of web development, optimizing and scaling applications is always an issue. React.js had an extraordinary success for frontend development as a tool, that provides a robust way to create user interfaces. But it gets complicated with growing applications, especially when it comes to multiple REST API endpoints. Concerns such as over-fetching, where excessive data than required can be a source of performance bottleneck and a poor user experience.

Among the solutions to these challenges is adopting the use of GraphQL with React applications. If your backend has multiple REST endpoints, then introducing a GraphQL layer that internally calls your REST API endpoints can enhance your application from overfetching and streamline your frontend application. In this article, you will find how to use it, the advantages and disadvantages of this approach, various challenges; and how to address them. We will also dive deeper into some practical examples of how GraphQL can help you improve the ways you work with your data.

Overfetching in REST APIs

In REST APIs, Over-fetching occurs when the amount of data that the API delivers to the client is more than what the client requires. This is a common problem with REST APIs, which often returns a fixed Object or Response Schema. To better understand this problem let us consider an example.

Consider a user profile page where the it is only required to show the user’s name and email. With a typical REST API, fetching the user data might look like this:

fetch('/api/users/1')
  .then(response => response.json())
  .then(user => {
    // Use the user's name and profilePicture in the UI
  });

The API response will include unnecessary data:

{
  "id": 1,
  "name": "John Doe",
  "profilePicture": "/images/john.jpg",
  "email": "[email protected]",
  "address": "123 Denver St",
  "phone": "111-555-1234",
  "preferences": {
    "newsletter": true,
    "notifications": true
  },
  // ...more details
}

Although the application only requires the name and email fields of the user, the API returns the whole user object. This additional data often increases the payload size, take more bandwidth and can eventually slow down the application when used on a device with limited resources or a slow network connection.

GraphQL as a Solution

GraphQL addresses the overfetching problem by allowing clients to request exactly the data they need. By integrating a GraphQL server into your application, you can create a flexible and efficient data-fetching layer that communicates with your existing REST APIs.

How It Works

  1. GraphQL Server Setup: You introduce a GraphQL server that serves as an intermediary between your React frontend and the REST APIs.
  2. Schema Definition: You define a GraphQL schema that specifies the data types and queries your frontend requires.
  3. Resolvers Implementation: You implement resolvers in the GraphQL server that fetch data from the REST APIs and return only the necessary fields.
  4. Frontend Integration: You update your React application to use GraphQL queries instead of direct REST API calls.

This approach allows you to optimize data fetching without overhauling your existing backend infrastructure.

Implementing GraphQL in a React Application

Let’s look at how to set up a GraphQL server and integrate it into a React application.

Install Dependencies:

npm install apollo-server graphql axios

Define the Schema

Create a file called schema.js:

const { gql } = require('apollo-server');

const typeDefs = gql`
  type User {
    id: ID!
    name: String
    email: String  // Ensure this matches exactly with the frontend query
  }

  type Query {
    user(id: ID!): User
  }
`;

module.exports = typeDefs;

This schema defines a User type and a user query that fetches a user by ID.

Implement Resolvers

Create a file called resolvers.js:

const resolvers = {
  Query: {
    user: async (_, { id }) => {
      try {
        const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
        const user = await response.json();

        return {
          id: user.id,
          name: user.name,
          email: user.email,  // Return email instead of profilePicture
        };
      } catch (error) {
        throw new Error(`Failed to fetch user: ${error.message}`);
      }
    },
  },
};

module.exports = resolvers;

The resolver for the user query fetches data from the REST API and returns only the required fields.

We will use https://jsonplaceholder.typicode.com/for our fake REST API.

Set Up the Server

Create a server.js file:

const { ApolloServer } = require('apollo-server');
const typeDefs = require('./schema');
const resolvers = require('./resolvers');

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.listen({ port: 4000 }).then(({ url }) => {
  console.log(`GraphQL Server ready at ${url}`);
});

Start the server:

node server.js

Your GraphQL server is live at http://localhost:4000/graphql and if you query your server, it will take you to this page.

Enhancing React Applications with GraphQL Over REST APIs

Integrating with the React Application

We will now change the React application to use the GraphQL API.

Install Apollo Client

npm install @apollo/client graphql

Configure Apollo Client

import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://localhost:4000', 
  cache: new InMemoryCache(),
});

Write the GraphQL Query

const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

Now integrate the above pieces of codes with your react app. Here is a simple react app below which lets a user select the userId and displays the information:

import { useState } from 'react';
import { ApolloClient, InMemoryCache, ApolloProvider, gql, useQuery } from '@apollo/client';
import './App.css';  // Link to the updated CSS

const client = new ApolloClient({
  uri: 'http://localhost:4000',  // Ensure this is the correct URL for your GraphQL server
  cache: new InMemoryCache(),
});

const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

const User = ({ userId }) => {
  const { loading, error, data } = useQuery(GET_USER, {
    variables: { id: userId },
  });

  if (loading) return 

Loading...

; if (error) return

Error: {error.message}

; return (

{data.user.name}

Email: {data.user.email}

); }; const App = () => { const [selectedUserId, setSelectedUserId] = useState("1"); return (

GraphQL User Lookup

); }; export default App;

Result:

Simple User

Enhancing React Applications with GraphQL Over REST APIs

Working with Multiple Endpoints

Imagine a scenario where you need to retrieve a specific user’s posts, along with the individual comments on each post. Instead of making three separate API calls from your frontend React app and dealing with unnecessary data, you can streamline the process with GraphQL. By defining a schema and crafting a GraphQL query, you can request only the exact data your UI requires, all in one efficient request.

We need to fetch user data, their posts, and comments for each post from the different endpoints. We’ll use fetch to gather data from the multiple endpoints and return it via GraphQL.

Update Resolvers

const fetch = require('node-fetch');

const resolvers = {
  Query: {
    user: async (_, { id }) => {
      try {
        // fetch user
        const userResponse = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
        const user = await userResponse.json();

        // fetch posts for a user
        const postsResponse = await fetch(`https://jsonplaceholder.typicode.com/posts?userId=${id}`);
        const posts = await postsResponse.json();

        // fetch comments for a post
        const postsWithComments = await Promise.all(
          posts.map(async (post) => {
            const commentsResponse = await fetch(`https://jsonplaceholder.typicode.com/comments?postId=${post.id}`);
            const comments = await commentsResponse.json();
            return { ...post, comments };
          })
        );

        return {
          id: user.id,
          name: user.name,
          email: user.email,
          posts: postsWithComments,
        };
      } catch (error) {
        throw new Error(`Failed to fetch user data: ${error.message}`);
      }
    },
  },
};

module.exports = resolvers;

Update GraphQL Schema

const { gql } = require('apollo-server');

const typeDefs = gql`
  type Comment {
    id: ID!
    name: String
    email: String
    body: String
  }

  type Post {
    id: ID!
    title: String
    body: String
    comments: [Comment]
  }

  type User {
    id: ID!
    name: String
    email: String
    posts: [Post]
  }

  type Query {
    user(id: ID!): User
  }
`;

module.exports = typeDefs;

Server setup in server.js remains same. Once we update the React.js code, we get the below output:

Detailed User

Enhancing React Applications with GraphQL Over REST APIs

Benefits of This Approach

Integrating GraphQL into your React application provides several advantages:

Eliminating Overfetching

A key feature of GraphQL is that it only fetches exactly what you request. The server only returns the requested fields and ensures that the amount of data transferred over the network is reduced by serving only what the query demands and thus improving performance.

Simplifying Frontend Code

GraphQL enables you to get the needful information in a single query regardless of their origin. Internally it could be making 3 API calls to get the information. This helps to simplify your frontend code because now you don’t need to orchestrate different async requests and combine their results.

Improving Developer’s Experience

A strong typing and schema introspection offer better tooling and error checking than in the traditional API implementation. Further to that, there are interactive environments where developers can build and test queries, including GraphiQL or Apollo Explorer.

Addressing Complexities and Challenges

This approach has some advantages but it also introduces some challenges that have to be managed.

Additional Backend Layer

The introduction of the GraphQL server creates an extra layer in your backend architecture and if not managed properly, it becomes a single point of failure.

Solution: Pay attention to error handling and monitoring. Containerization and orchestration tools like Docker and Kubernetes can help manage scalability and reliability.

Potential Performance Overhead

The GraphQL server may make multiple REST API calls to resolve a single query, which can introduce latency and overhead to the system.

Solution: Cache the results to avoid making several calls to the API. There exist some tools such as DataLoader which can handle the process of batching and caching of requests.

Conclusion

"Simplicity is the ultimate sophistication" — Leonardo da Vinci

Integrating GraphQL into your React application is more than just a performance optimization — it’s a strategic move towards building more maintainable, scalable, and efficient applications. By addressing overfetching and simplifying data management, you not only enhance the user experience but also empower your development team with better tools and practices.

While the introduction of a GraphQL layer comes with its own set of challenges, the benefits often outweigh the complexities. By carefully planning your implementation, optimizing your resolvers, and securing your endpoints, you can mitigate potential drawbacks. Moreover, the flexibility that GraphQL offers can future-proof your application as it grows and evolves.

Embracing GraphQL doesn’t mean abandoning your existing REST APIs. Instead, it allows you to leverage their strengths while providing a more efficient and flexible data access layer for your frontend applications. This hybrid approach combines the reliability of REST with the agility of GraphQL, giving you the best of both worlds.

If you’re ready to take your React application to the next level, consider integrating GraphQL into your data fetching strategy. The journey might present challenges, but the rewards — a smoother development process, happier developers, and satisfied users — make it a worthwhile endeavor.

Full Code Available

You can find the full code for this implementation on my GitHub repository: GitHub Link.

版本聲明 本文轉載於:https://dev.to/shreyam_duttagupta/enhancing-react-applications-with-graphql-over-rest-apis-91p?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 在PHP中如何高效檢測空數組?
    在PHP中如何高效檢測空數組?
    在PHP 中檢查一個空數組可以通過各種方法在PHP中確定一個空數組。如果需要驗證任何數組元素的存在,則PHP的鬆散鍵入允許對數組本身進行直接評估:一種更嚴格的方法涉及使用count()函數: if(count(count($ playerList)=== 0){ //列表為空。 } 對...
    程式設計 發佈於2025-07-15
  • Java中Lambda表達式為何需要“final”或“有效final”變量?
    Java中Lambda表達式為何需要“final”或“有效final”變量?
    Lambda Expressions Require "Final" or "Effectively Final" VariablesThe error message "Variable used in lambda expression shou...
    程式設計 發佈於2025-07-15
  • PHP陣列鍵值異常:了解07和08的好奇情況
    PHP陣列鍵值異常:了解07和08的好奇情況
    PHP數組鍵值問題,使用07&08 在給定數月的數組中,鍵值07和08呈現令人困惑的行為時,就會出現一個不尋常的問題。運行print_r($月份)返回意外結果:鍵“ 07”丟失,而鍵“ 08”分配給了9月的值。 此問題源於PHP對領先零的解釋。當一個數字帶有0(例如07或08)的前綴時,PHP...
    程式設計 發佈於2025-07-15
  • 在細胞編輯後,如何維護自定義的JTable細胞渲染?
    在細胞編輯後,如何維護自定義的JTable細胞渲染?
    在JTable中維護jtable單元格渲染後,在JTable中,在JTable中實現自定義單元格渲染和編輯功能可以增強用戶體驗。但是,至關重要的是要確保即使在編輯操作後也保留所需的格式。 在設置用於格式化“價格”列的“價格”列,用戶遇到的數字格式丟失的“價格”列的“價格”之後,問題在設置自定義單元...
    程式設計 發佈於2025-07-15
  • Go語言如何動態發現導出包類型?
    Go語言如何動態發現導出包類型?
    與反射軟件包中的有限類型的發現能力相反,本文探討了在運行時發現所有包裝類型(尤其是struntime go import( “ FMT” “去/進口商” ) func main(){ pkg,err:= incorter.default()。導入(“ time”) ...
    程式設計 發佈於2025-07-15
  • 如何從PHP中的Unicode字符串中有效地產生對URL友好的sl。
    如何從PHP中的Unicode字符串中有效地產生對URL友好的sl。
    為有效的slug生成首先,該函數用指定的分隔符替換所有非字母或數字字符。此步驟可確保slug遵守URL慣例。隨後,它採用ICONV函數將文本簡化為us-ascii兼容格式,從而允許更廣泛的字符集合兼容性。 接下來,該函數使用正則表達式刪除了不需要的字符,例如特殊字符和空格。此步驟可確保slug僅包...
    程式設計 發佈於2025-07-15
  • 如何克服PHP的功能重新定義限制?
    如何克服PHP的功能重新定義限制?
    克服PHP的函數重新定義限制在PHP中,多次定義一個相同名稱的函數是一個no-no。嘗試這樣做,如提供的代碼段所示,將導致可怕的“不能重新列出”錯誤。 但是,PHP工具腰帶中有一個隱藏的寶石:runkit擴展。它使您能夠靈活地重新定義函數。 runkit_function_renction_...
    程式設計 發佈於2025-07-15
  • Java中如何使用觀察者模式實現自定義事件?
    Java中如何使用觀察者模式實現自定義事件?
    在Java 中創建自定義事件的自定義事件在許多編程場景中都是無關緊要的,使組件能夠基於特定的觸發器相互通信。本文旨在解決以下內容:問題語句我們如何在Java中實現自定義事件以促進基於特定事件的對象之間的交互,定義了管理訂閱者的類界面。 以下代碼片段演示瞭如何使用觀察者模式創建自定義事件: args...
    程式設計 發佈於2025-07-15
  • Python環境變量的訪問與管理方法
    Python環境變量的訪問與管理方法
    Accessing Environment Variables in PythonTo access environment variables in Python, utilize the os.environ object, which represents a mapping of envir...
    程式設計 發佈於2025-07-15
  • 如何簡化PHP中的JSON解析以獲取多維陣列?
    如何簡化PHP中的JSON解析以獲取多維陣列?
    php 試圖在PHP中解析JSON數據的JSON可能具有挑戰性,尤其是在處理多維數組時。 To simplify the process, it's recommended to parse the JSON as an array rather than an object.To do...
    程式設計 發佈於2025-07-15
  • C++20 Consteval函數中模板參數能否依賴於函數參數?
    C++20 Consteval函數中模板參數能否依賴於函數參數?
    [ consteval函數和模板參數依賴於函數參數在C 17中,模板參數不能依賴一個函數參數,因為編譯器仍然需要對非contexexpr futcoriations contim at contexpr function進行評估。 compile time。 C 20引入恆定函數,必須在編譯時進...
    程式設計 發佈於2025-07-15
  • Python中何時用"try"而非"if"檢測變量值?
    Python中何時用"try"而非"if"檢測變量值?
    使用“ try“ vs.” if”來測試python 在python中的變量值,在某些情況下,您可能需要在處理之前檢查變量是否具有值。在使用“如果”或“ try”構建體之間決定。 “ if” constructs result = function() 如果結果: 對於結果: ...
    程式設計 發佈於2025-07-15
  • eval()vs. ast.literal_eval():對於用戶輸入,哪個Python函數更安全?
    eval()vs. ast.literal_eval():對於用戶輸入,哪個Python函數更安全?
    稱量()和ast.literal_eval()中的Python Security 在使用用戶輸入時,必須優先確保安全性。強大的Python功能Eval()通常是作為潛在解決方案而出現的,但擔心其潛在風險。 This article delves into the differences betwee...
    程式設計 發佈於2025-07-15
  • 為什麼儘管有效代碼,為什麼在PHP中捕獲輸入?
    為什麼儘管有效代碼,為什麼在PHP中捕獲輸入?
    在php ;?>" method="post">The intention is to capture the input from the text box and display it when the submit button is clicked.但是,輸出...
    程式設計 發佈於2025-07-15
  • Python高效去除文本中HTML標籤方法
    Python高效去除文本中HTML標籤方法
    在Python中剝離HTML標籤,以獲取原始的文本表示Achieving Text-Only Extraction with Python's MLStripperTo streamline the stripping process, the Python standard librar...
    程式設計 發佈於2025-07-15

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3