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

推荐订阅源

Spread Privacy
Spread Privacy
P
Palo Alto Networks Blog
P
Proofpoint News Feed
AI
AI
Help Net Security
Help Net Security
S
Securelist
T
Troy Hunt's Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
C
Cisco Blogs
Scott Helme
Scott Helme
Hacker News - Newest:
Hacker News - Newest: "LLM"
Vercel News
Vercel News
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
B
Blog
GbyAI
GbyAI
Recent Commits to openclaw:main
Recent Commits to openclaw:main
D
Darknet – Hacking Tools, Hacker News & Cyber Security
P
Proofpoint News Feed
S
Security Affairs
Cisco Talos Blog
Cisco Talos Blog
AWS News Blog
AWS News Blog
T
Tenable Blog
H
Help Net Security
NISL@THU
NISL@THU
F
Fortinet All Blogs
博客园_首页
G
GRAHAM CLULEY
L
LINUX DO - 最新话题
P
Privacy International News Feed
G
Google Developers Blog
博客园 - Franky
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Security Archives - TechRepublic
Security Archives - TechRepublic
The Register - Security
The Register - Security
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
T
Tor Project blog
P
Privacy & Cybersecurity Law Blog
量子位
C
Cyber Attacks, Cyber Crime and Cyber Security
Forbes - Security
Forbes - Security
S
Secure Thoughts
Simon Willison's Weblog
Simon Willison's Weblog
D
Docker
Recorded Future
Recorded Future
博客园 - 三生石上(FineUI控件)
L
Lohrmann on Cybersecurity
T
Tailwind CSS Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
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