惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News and Events Feed by Topic
Malwarebytes
Malwarebytes
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
Cybersecurity and Infrastructure Security Agency CISA
F
Future of Privacy Forum
C
Cisco Blogs
T
The Exploit Database - CXSecurity.com
A
Arctic Wolf
S
Securelist
K
Kaspersky official blog
S
Schneier on Security
T
ThreatConnect
T
Tenable Blog
Spread Privacy
Spread Privacy
T
True Tiger Recordings
AWS News Blog
AWS News Blog
F
Fox-IT International blog
量子位
T
Threatpost
V
Vulnerabilities – Threatpost
C
CERT Recently Published Vulnerability Notes
Cisco Talos Blog
Cisco Talos Blog
GbyAI
GbyAI
宝玉的分享
宝玉的分享
腾讯CDC
G
Google Developers Blog
aimingoo的专栏
aimingoo的专栏
Cyberwarzone
Cyberwarzone
有赞技术团队
有赞技术团队
S
SegmentFault 最新的问题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Visual Studio Blog
U
Unit 42
雷峰网
雷峰网
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
O
OpenAI News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
The Register - Security
The Register - Security
MyScale Blog
MyScale Blog
小众软件
小众软件
A
About on SuperTechFans
Last Week in AI
Last Week in AI
Y
Y Combinator Blog
博客园 - 三生石上(FineUI控件)
美团技术团队
Google Online Security Blog
Google Online Security Blog
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog

DEV Community

Building an Autonomous SRE Agent: From Raw Telemetry to Safe, AI-Driven Remediation The EU AI Act in 2026: Reading the Law After the Omnibus I had zero coding knowledge. Here is "RetroTube", a 2010 YouTube sandbox prototype I built using AI! How to Validate Environment Variables in TypeScript (and Why You Should) I Built a CLI Tool That Writes Better Git Commits Than I Do Transfer Fees, Metadata, and Soulbound Tokens: My First Real Token Experiments on Solana Creando un Tetris con JavaScript VI: Complicando el juego. DeepSeek's API Price Cut Changed My Claude Code and ChatGPT Math [Boost] Perl 🐪 Weekly #774 - Perl is too HOT How to Track AI Usage Without Losing Revenue (Complete Guide) 77 Rules Later: What Graduating Our First Stack Actually Looked Like RAG 시스템 실전 구축 (v26) When Premature Scaling Leads to Operator Burnout Multi-Repo Microservice Changes Are a Coordination Problem. I Solved It With AI Agent Teams. The Next Frontier: How Multi-Agent Systems are Redefining Productivity The Kimwolf Bust Just Outed Android Webcams as Botnet Fodder — Here's the Question Every Repurposed-Phone Camera Setup Has to Answer I'm an autonomous AI agent. I shipped 18 fixes to myself in one session. Building a Secure Future with Zero Trust Security Architecture Asynchronous Functions in Dart How I migrated magic-link login from Resend to AWS SES + Lambda five days before launch Edge Computing He creado una empresa ficticia IT/OT para poder encontrar sus vulnerabilidades y reforzar su seguridad en sus activos críticos Why I Built @editora/react I built a tiny UGC script generator because hooks are the hardest part The Phone Is Becoming the New Terminal Why Most AI Music Tools Feel Wrong to Developers Goroutines vs. Promises: Why Go and JavaScript Look at Concurrency Completely Differently How I Use Antigravity 2.0 to Navigate Open-Source Codebases and Make Better Technical Decisions Understanding Basic HTML & CSS Concepts for Beginners Go Error Handling: Annoying or Awesome? Your To-Do List Doesn't Know You — So I Gave Mine Three Brains Shell Basics (Bash, Zsh, Sh) Free MongoDB GUI Tool for Developers, Students, and Teams Designing High-Performance Blockchain Indexers Choosing Models for an Agentic Chat App on Amazon Bedrock How Smart Growth Teams Automate Their Marketing Stack in 2026 (Without Hiring More People) What I Learned About Memory-Augmented AI Agents Seven Docker Tips Every Engineer Should Know (from Docker Captains) Welcome to the Fast-Food Era of Testing: Over-Weight by Tests How to use Claude in vscode? Prompt Engineering for Automated Evaluation: Making LLMs the Judge in AI Builder Solutions Full Stack Projects Are Not Enough Anymore Virtualization & Cloud Basics Orakle: Turning Raw Blockchain Data into Intelligence with Gemma 4 Building an Autoposting Pipeline with Hermes Agent: Why Waterfall Beats Parallel, and the Edge Cases Nobody Talks About OpenShift Virtualization Migration Advisor — Local-First, Powered by Gemma 4 26B MoE WebMCP is coming — so I’m building webmcp.js I Disappeared for 4 Months After Launch - Here's What Brought Me Back Jira Is Turing-Complete (And You've Been Coding in It) NyayAI: Building an AI Legal Assistant for 1.4 Billion People — A Technical Deep Dive E-commerce Order Automation: Stripe + Invoice + Shipping Workflow How to Evaluate AI Agents: LLM-as-Judge Tutorial The Interview Prep Stack I Used as a Senior Software Engineer Targeting Big Tech Gemma4 Challenge OptiLearn - Powered by Google Gemma 4 Aura — The Gemma 4 Powered Agentic Web Copilot & Self-Healing Accessibility Engine I built a tool that catches misleading charts using Gemma 4 running locally Worklog companion with Gemma4 GBase: Building LLM Agents That Actually Learn from Their Mistakes Blossom — a small step toward student mental wellbeing WordPress Performance Monitoring: A Complete Guide Principal Components in TypeScript (Part 4) When three sharp wallets agree: what consensus signals on Polymarket actually mean I Built a Fail-Fast Rust Scheduler with Background OAuth Auto-Refresh (Part 2) Sharing is caring How Putting Faces (Literally) to My AI Garden Images Gave It a Personality Sofi Log #001: Thailand's Tourism Tax & the 180-Day AI Surveillance Wall Sofi Log #006: Decentralized IP-Address Obfuscation Specs Sofi Log #008: Bypassing Legacy Cross-Border Bank Fee Traps Secret Rotation Automation: The Operational Cost of Security Sofi Log #009: Portable Identity & DID Passport Framework Sofi Log #011: Autonomous Smart Treasury Repatriation Specs History of Linux & Unix I asked Claude if my plan was on track for the goal — and got an honest 'No' PHPStan 'expects X, Y given' — the trace it doesn't give you Using Gemma4 2B to Assist Community Health Workers Open-source Playwright wrapper that passes bot.sannysoft.com, pixelscan, and CreepJS in headless mode Policy Storyteller: Turning Nepali Bills into Human Stories with Gemma 4 Avoid Cross Module Dependencies with Dependency Cruiser Invariant-Driven Architecture: 20M transactions on a €80/mo Cloud VM. Stop using external npm packages just to generate a UUID v4 Choosing the Right Gemma 4 Model Matters More Than Choosing the Best One Your LLM Is Not an Agent. Your Framework Is Not Enough. You Need a Harness. From HTTPS to UCP: Shopping Is About to Stop Being Your Problem From Creation to Consumption: How Antigravity 2.0 and Gemini Spark Are Defining the Agentic Era 10 Mistakes I Wish I Knew Before Taking the CKA Exam AI That Actually Does Stuff: Autonomous Agents Explained Exploring AI workflow Orchestration: Comparing Weft, Python & Alternative Pipeline Approaches El Poder del Aprendizaje Federado: Cuando los Algoritmos Distribuidos Entrenan a la IA Email Marketing Automation in 2026: 5 Tools (and 1 Self-Hosted) Through Their APIs A Replay Runbook For Missed Publishing Windows Why timeout handling matters more than most backend logic How I Make $6,800/Month Selling Niche VS Code Extensions Model Routing Cost Checklist: Hosted APIs, Open Models, Or Self-Hosted Inference? ORA-00207 오류 원인과 해결 방법 완벽 가이드 Deno 2.8 Operator Upgrade Checklist: CI, Lockfiles, Node Compatibility, And Rollback AI-Discovered Vulnerabilities Need A Triage Queue, Not A Panic Channel AI Agent Workboards Need Audit Controls Before They Need More Agents Demystifying DevRel: What It Actually Is (And Why Should You Become One?)
Stop Using Fetch() in React: A Better Way To Call Your Backend
Opemipo Disu · 2026-05-25 · via DEV Community

Developers have an ‘unspoken struggle’ when communicating with APIs. When working on an interactive application, developers constantly need to communicate their frontend to their backend logic.

The hassle of writing logic, connecting routes, and defining endpoints is a huge part of building that developers would prefer to avoid. With tools like Graftcode, developers can install a strongly-typed backend package that connects directly to their backend, instead of manually writing API clients, routes, and endpoint integration code.

What You’ll Learn

  • Why using fetch() can be a complex approach
  • How Graftcode removes the need for building APIs
  • How to expose your own backend logic through Graftcode Gateway
  • How to call backend modules can be used in React applications as dependencies without writing APIs

Prerequisites

This tutorial assumes the reader has the following:

  1. Node >= 22 or higher installed on their local development machine
  2. npx 7.2 or higher is installed on their local development machine
  3. Basic understanding of how to work with fetch() or REST APIs
  4. A basic knowledge of JavaScript and React
  5. A Stripe account with in test mode

Once you have these prerequisites, you’re ready to begin this tutorial. In this blog post, you’ll learn how Graftcode works and how to use Graftcode as a connector between your React frontend and Node.js backend without manually building an API. This blog post/tutorial includes a demo that shows how to build an interactive application by just building your application’s logic through an imported backend.

Why Do Developers Still Use fetch() in React?

Most applications still rely on the regular pattern of using fetch() or other HTTP clients. Here’s the most common approach React applications use when communicating with their backend:

Image from “**Automating APIs with JavaScript: How I Stopped Writing Endless Boilerplate” -** [Babar saad](https://sa82912045.medium.com/?source=post_page---byline--cdfbcc930a48---------------------------------------)

Image Credit: Babar saad

This approach works, but it increases workload and introduces friction, and, unknowingly to most developers, it creates problems such as:

  • Repeated boilerplate for every endpoint
  • Manual serialization and parsing
  • Increased workload when building new features

API layers are not necessary for many applications, but it’s common practice and introduces the issues listed above.

There is an alternate way to call your backend apart from using fetch() and other HTTP-based clients. With this option, you don’t need to worry about creating requests, API routes, and managing them. An alternate option is to use Graftcode, which is what this blog post will be all about.

What Is Graftcode?

Graftcode is a tool that lets you call backend functions and methods from another runtime without manually building REST APIs, writing HTTP client code, or creating custom SDKs. Instead of treating your backend as a collection of endpoints, Graftcode packages backend logic as a strongly-typed, installable dependency.

Graftcode uses its Gateway to expose selected backend classes and methods and generates a package, called a Graft, that you can install directly in your application. Once installed, you can import backend modules and call their methods like regular functions, while Graftcode handles the communication between your application and the backend runtime.

This works whether your frontend and backend are written in different languages or the same language. When they are different, Graftcode bridges runtimes so one side can call methods from the other. When they are the same, as in this React and Node.js example, the main benefit is removing the manual REST/API layer, routes, and fetch() calls between them.

In practice, Graftcode changes how interactive applications are built. Instead of configuring endpoints, maintaining client code, and managing API integration logic, you expose backend methods through Graftcode Gateway, install the generated Graft package, import the module you need, and call the method directly.

For example, here’s a traditional way to call Stripe’s SDK with React:

fetch('/api/create-intent') -> Express route -> Stripe SDK

Enter fullscreen mode Exit fullscreen mode

When using Graftcode to call Stripe’s SDK through React, here’s what you do:

StripeService.createPaymentIntent() -> [WebSocket] -> Node.js

Enter fullscreen mode Exit fullscreen mode

With Graftcode, you just call functions; you do not need Express, routes, or even fetch().

Use Case for Graftcode: Stripe Dashboard without a REST API

In this section, we’ll take a look at how to work with Graftcode and when you should use it.

We will be building an interactive Stripe dashboard in React. Yes - without a single API! This isn’t just a simple example; this is an interactive application that does three things:

  • Create a payment intent with Stripe
  • Generate payment links
  • List your most recent transactions
  • Displays your Stripe’s revenue summary

All these will be done without using a single REST endpoint. However, since we’re using Stripe Node.js SDK, which requires a secret key and cannot run in the browser, we will have the SDK as a backend and expose it through Graftcode Gateway.

This section has been broken down into different steps to make it easy to understand how to build applications with Graftcode using React.

Step 1: Create a React Project

Firstly, we’ll create a React application from scratch using Vite:

npm create vite@latest graftcode-demo -- --template react
cd graftcode-demo
npm install

Enter fullscreen mode Exit fullscreen mode

Step 2: Install Hypertube NodeJS SDK

Navigate to the project within your CLI and install hypertube-nodejs-sdk - It’s needed for the Websocket transport layer as it uses Node.js built-in features that don’t exist in the browser. Vite needs to polyfill them; to do this, install the SDK and the polyfill plugin:

npm install hypertube-nodejs-sdk vite-plugin-node-polyfills

Enter fullscreen mode Exit fullscreen mode

After doing this, you need to update your vite.config.js to enable the polyfills.

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { nodePolyfills } from 'vite-plugin-node-polyfills';
import { resolve } from 'path';

export default defineConfig({
  plugins: [
    react(),
    nodePolyfills({ exclude: ['crypto'] }),
  ],
  resolve: {
    alias: {
      crypto: resolve('./src/crypto-shim.js'),
    },
  },
});

Enter fullscreen mode Exit fullscreen mode

After doing this, create a crypto-shim.js file in the src/ directory:

export const randomUUID = () => window.crypto.randomUUID();
export default { randomUUID };

Enter fullscreen mode Exit fullscreen mode

Step 3: Create the Backend Module

Now, this is where the real work begins; we need to work on configuring the backend module, as we can’t import certain backend modules like the one we want to work with, for now (Graftcode is in its beta version).

Inside the project folder, create a backend/ directory and initialize it as its own Node.js project:

mkdir backend
cd backend
npm init -y
npm install stripe dotenv

Enter fullscreen mode Exit fullscreen mode

In the directory, create an index.js file inside the backend/ directory with a class that has your Stripe logic:

require("dotenv").config();
const Stripe = require("stripe");
const stripe = Stripe(process.env.STRIPE_SECRET_KEY);

class StripeService {
  static async createPaymentIntent(amount, currency) {
    amount = amount ?? 1000;
    currency = currency ?? "gbp";
    const intent = await stripe.paymentIntents.create({ amount, currency });
    return JSON.stringify({
      id: intent.id,
      amount: intent.amount,
      currency: intent.currency,
      status: intent.status,
      client_secret: intent.client_secret,
    });
  }

  static async createPaymentLink(amount, currency, name) {
    amount = amount ?? 1000;
    currency = currency ?? "gbp";
    name = name ?? "Payment";
    const price = await stripe.prices.create({
      currency,
      unit_amount: amount,
      product_data: { name },
    });
    const link = await stripe.paymentLinks.create({
      line_items: [{ price: price.id, quantity: 1 }],
    });
    return JSON.stringify({ id: link.id, url: link.url, active: link.active });
  }

  static async listTransactions() {
    const result = await stripe.paymentIntents.list({ limit: 5 });
    return JSON.stringify(
      result.data.map((pi) => ({
        id: pi.id,
        amount: pi.amount,
        currency: pi.currency,
        status: pi.status,
        description: pi.description || "Payment intent",
      }))
    );
  }

  static async getRevenueSummary() {
    const result = await stripe.paymentIntents.list({ limit: 100 });
    const succeeded = result.data.filter((pi) => pi.status === "succeeded");
    const totalRevenue = succeeded.reduce((sum, pi) => sum + pi.amount, 0);
    return JSON.stringify({
      totalRevenue,
      avgTransaction: succeeded.length > 0 ? Math.round(totalRevenue / succeeded.length) : 0,
      successRate: Math.round((succeeded.length / result.data.length) * 100),
      counts: { succeeded: succeeded.length, total: result.data.length },
    });
  }
}

module.exports = { StripeService };

Enter fullscreen mode Exit fullscreen mode

In the code snippet above, the plan was to create a normal Node.js class without decorators, frameworks, and special annotations. The pattern is a class with static methods ****exported by name. That is how Graftcode discovers and registers your backend logic.

Note that the method returns JSON.stringify() rather than plain objects. Graftcode's transport layer wraps the object return values as remote references and returns a JSON string as the platform requires it.

Create a .env in the same backend directory:

STRIPE_SECRET_KEY=sk_test_your_key_here

Enter fullscreen mode Exit fullscreen mode

You can get the Stripe secret key from your dashboard. To get this:

  • Head over to Stripe’s Test account Dashboard
  • Hit the Developers panel
  • Select API Keys
  • Get your secret key from the Standard Keys panel

Step 3: Expose the Backend With Graftcode Gateway

In this section, we’ll be doing a bit more work on the backend - read this guide to learn more about exposing your backend with Graftcode’s gateway.

To begin with, run it against your backend:

gg ./package.json --projectKey YOUR_PROJECT_KEY --port 8080

Enter fullscreen mode Exit fullscreen mode

To get the project key, do the following in your Graftcode dashboard:

  • Head over to the Vision panel
  • Create a new gateway
  • In the deployment options section, hit the “I already have Graftcode Gateway” button: This skips the download process and automatically generates a new project key for you.

Run and deploy logic

The gateway reads your package.json, finds the main entry point, loads StripeService, and registers all four methods automatically.

Once running, the gateway prints the exact install command for your project. It looks like this:

npm install --registry https://grft.dev/YOUR_PROJECT_ID__graftcode @graft/npm-backend@1.0.0

Enter fullscreen mode Exit fullscreen mode

Copy the command exactly as printed, alongside the project ID in the URL, which is specific to your account.

Step 4: Install the Configured Package

In the project’s root, configure the @graft registry so npm knows where to find the generated package:

echo "@graft:registry=https://grft.dev/YOUR_PROJECT_ID__graftcode" >> .npmrc

Enter fullscreen mode Exit fullscreen mode

Be sure to always replace your actual project ID as shown in your Graftcode portal. Then install the generated package using the exact command the gateway printed when it started - so this is more like wrapped into Graftcode now:

npm install @graft/npm-backend@1.0.0

Enter fullscreen mode Exit fullscreen mode

Step 5: Import the Backend From Your React Application

The next step after configuring your backend is to import it into your frontend. In your App.jsx, import the generated package and configure the gateway host.

You can retrieve the gateway host URL from Graftcode Vision. Open your project in the Vision portal, navigate to your running gateway, and copy the WebSocket endpoint shown for your deployment. When running locally, this will usually look like ws://localhost:8080/ws.

import { GraftConfig, StripeService } from "@graft/npm-backend";
GraftConfig.host = "ws://localhost:8080/ws";

Enter fullscreen mode Exit fullscreen mode

In the code snippet above, the GraftConfig.host is the WebSocket URL of your running gateway. Ensure the backend is currently running on a separate terminal. That is the entire connection setup you need to work with Graftcode. You don’t need any base URLs, HTTP clients, or middleware.

All you need to call your backend methods like regular functions like this:

const raw = await StripeService.createPaymentIntent(1000, "gbp");

const raw2 = await StripeService.createPaymentLink(1000, "gbp", "demo Product");

const raw3 = await StripeService.listTransactions();

const raw4 = await StripeService.getRevenueSummary();

Enter fullscreen mode Exit fullscreen mode

Each function call moves over WebSocket to the gateway, which runs it in Node.js, where the Stripe SDK is wrapped, and returns the result. What Graftcode eliminates is all the code you would normally write around it, and the direct contact the SDK has with your browser.

You can compare this approach to the traditional approach. To work with Stripe traditionally, you’ll be working with endpoints directly, which is a stressful approach. Here’s an example of what you’ll be doing normally:

const res = await fetch("/api/create-intent", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ amount: 1000, currency: "gbp" }),
});
const intent = await res.json();

Enter fullscreen mode Exit fullscreen mode

With this, you need to ensure there’s a configured endpoint for the create-intent. Whereas, in Graftcode, all you need to do is call functions. In fact, in your IDE, when you type your function, it raises suggestions based on the imported module; this way, it’s easy for you to use Graftcode.

With the traditional approach, you would need the Express route, the request validation, the response shape, the error handling, and you would maintain them. With Graftcode, you write the function once and call it.

Step 6: Exploring Backend Methods with Graftcode Vision

Now, the React application has been connected to a backend without writing any API routes. But there’s another part of the Graftcode experience that makes this workflow even more interesting: Graftcode Vision.

Unlike working with API workflows, where you rely on documentation, Swagger specs, or tools like Postman, Graftcode Vision lets you see your backend in modules. When you open it in the browser, you’re not looking at endpoints or routes. You are looking at actual classes and methods; the actual ones you imported.

In the portal, you can inspect the module’s classes, see every method it exposes, understand the parameters it expects, and even test those methods live. It removes the guesswork that developers usually deal with when integrating APIs.

Graftcode Vision Dashboard

Step 7: Run Your Entire Application

As mentioned earlier, you need to start the gateway from the backend/ directory in one terminal:

cd backend
gg ./package.json --projectKey YOUR_PROJECT_KEY --port 8080

Enter fullscreen mode Exit fullscreen mode

Start your React application from your project’s root in a separate terminal:

npm run start OR npm run dev

Enter fullscreen mode Exit fullscreen mode

Click any button in the application - they perform different functions. When a button is clicked, a call goes over WebSocket to Node.js, hits the Stripe API, and returns a response without a REST API, endpoints, or fetch().

Graftcode demo with Stripe

In your Stripe dashboard, you should see recent interactions with your Stripe.

Stripe Dashboard

A Deeper Look at Graftcode

The code looks simple and also looks like an easier path to making things work, but there’s a bigger change than the simplicity.

In a normal setup, your frontend and backend communicate through an API that you manually built.

The four methods we configured in StripeService: createPaymentIntent, createPaymentLink, listTransactions, getRevenueSummary , would normally be an Express route. You would define the route, its request shape, response shape, and the error handling. You would write fetch() calls on the React side and keep both in sync.

Here, you expose them through the gateway, gg. The auto-generated @graft/npm-backend package is what React imports and calls. The most interesting thing is: instead of writing routes and fetch() calls, you write functions and let Graftcode handle the communication.

Conclusion

If you look back at the application you built in this tutorial, the most interesting part is the fact that none of it required an API.

There were no routes to define or anything to write, and no requests to construct. The entire interaction between frontend and backend was reduced to a simple method call, without losing any capability.

Thank you for taking the time to read this blog post. If you enjoyed this blog post, you can do well to try out Graftcode and check out some of its resources that will be listed in the references section.

If you have any questions, leave them in the comments section below. See you in the next blog post!

References