From ABI to API: Understanding Smart Contract Interactions for JavaScript Engineer
Deep dive into the differences between ABIs and APIs, specifically tailored to JavaScript engineers transitioning into blockchain development.

If you're a JavaScript engineer transitioning into blockchain development, understanding ABIs is key to interacting with smart contracts.
This guide will help you navigate your JavaScript to Web3 transition with practical examples using OpenZeppelin contracts.
ABIs are to blockchain development what API specifications are to Web2 engineering - but they operate at a lower level of abstraction.
For Ethereum development with JavaScript, learning this fundamental difference is essential.
The Mental Model Shift: APIs vs. ABIs for JavaScript Engineers
As JavaScript developers, we make requests to endpoints and get a response back.
// REST API example
async function fetchUserData() {
const response = await fetch('<https://api.example.com/users/123>', {
headers: {
'Authorization': 'Bearer token123'
}
});
return response.json();
}
// Response
// { name: "Jules", age: "30" }
When interacting with smart contracts, we're not making requests to a server, but rather reading from the blockchain or initiating state-changing transactions.
Instead of APIs (Application Programming Interfaces), we have ABIs (Application Binary Interfaces).
Smart contract ABIs are generated when compiling the smart contract, which we do every time before deploying them to the blockchain.
Think of an ABI as the smart contract's public face — it tells you what functions exist, what parameters they take, and what they return. With these specifications, RPC providers are able to call on the right functions from your smart contracts.

ABIs vs APIs: A Deeper Dive for JavaScript Engineers
To appreciate the difference in blockchain development for JavaScript engineers, we must understand how Web2 architecture differs from Web3 architecture.

In a traditional REST API flow:
- Your front-end applications constructs an HTTP request with a URL, method, and possibly headers/body to call your API endpoint
- The request travels over the internet to a specific server hosted in a cloud provider like AWS, GCP, Heroku, etc
- Your server software (i.e. your Express.js or Rails application) routes the request to the appropriate handler
- The handler executes code in your server, typically interacting with a database
- The server sends back a response, usually JSON
- Your front-end processes the response
In blockchain development with JavaScript:
- Your front-end application, via Web3 libraries for JavaScript like ethers.js or viem.js, encodes a function call using the contract's ABI
- The encoded call is wrapped in a transaction or a call message that gets sent to the blockchain
- This message is broadcasted to the entire blockchain network via a provider (like Alchemy, Infura, etc)
- Every node in the network processes the call according to the same rules
- The result is returned to your application
- Your frontend library decodes the result using the ABI definitions
The fundamental differences between ABIs vs APIs:
Web3 Providers: Your Gateway to the Blockchain
If ABIs are the language dictionaries that help us communicate with smart contracts, Web3 providers are the messengers that carry our words to the blockchain.
A provider is your JavaScript application's connection to the Ethereum network (or any other blockchain).
It is responsible for submitting your transactions to the blockchain and reading data from it. Think of providers as the HTTP clients of the blockchain world — they handle the actual communication while you focus on what you want to say.
// Viem is a JavaScript Web3 JS library
import { createPublicClient, http, custom } from 'viem';
import { mainnet } from 'viem/chains';
// Connect to browser wallet like MetaMask
export const browserProvider = createPublicClient({
chain: mainnet,
transport: custom(window.ethereum)
});
// Connect to a specific network via public node
export const infuraProvider = (projectId) => createPublicClient({
chain: mainnet,
transport: http(`https://mainnet.infura.io/v3/${projectId}`)
});
// Connect to a local node
export const localProvider = createPublicClient({
chain: mainnet,
transport: http('<http://localhost:8545>')
});
When you call a smart contract function from any application during Ethereum development with JavaScript, the provider:
- Formats your request according to the Ethereum JSON-RPC specification
- Sends it to the appropriate node
- Returns the response to your application
Without a Web3 provider, your JavaScript code has no way to communicate with the blockchain — it's like having a phone but no cellular service.

How do JavaScript Developers Interact with Smart Contracts?
When using an API, we create an endpoint request to fetch and write information.
In blockchain development, we instead pass a Web3 library our contract's ABI and use it so it generates functions we can call from our application - in this case viem
.
// (a) REST API
const api = {
baseUrl: '<https://api.example.com>',
async getUser(id) {
const response = await fetch(`${this.baseUrl}/users/${id}`);
return response.json();
}
};
// (b) Ethereum smart contract approach - using viem
import { createPublicClient, custom, getContract } from 'viem';
import { mainnet } from 'viem/chains';
// Create a public client to interact with the blockchain
const publicClient = createPublicClient({
chain: mainnet,
transport: custom(window.ethereum)
});
const contractABI = [
{
"inputs": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "address",
"name": "initialOwner",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "ECDSAInvalidSignature",
"type": "error"
},
// other functions would be listed here
];
const contract = getContract({
address: '0x123...', // contract address on the blockchain
abi: contractABI,
publicClient
});
Without the ABI, viem
wouldn't know how to properly format the call or interpret the response during smart contract interaction.
It's like viem
needs to read the API documentation before writing a single line of code — the ABI is that documentation.
The ABI Decoded: What's Actually Happening in the Smart Contract Interaction
ABIs are the bridge between your JavaScript code and the Ethereum Virtual Machine (EVM).
{
"inputs": [
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "getUser",
"outputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
In this ABI example, the ABI tells us that our contract has a function named getUser
that:
- Takes a single parameter:
id
of typeuint256
- Returns two values: a
string
namedname
and auint256
namedbalance
- Has a "view" state mutability, meaning it doesn't modify blockchain state
Web3 libraries for JavaScript like viem
and ethers
use this information to encode our function calls into the format the EVM understands so that we can easily call on smart contract functions from our applications.
const { name, balance } = await contract.getUser(123);
Behind the scenes of a smart contract interaction:
- The function name and parameters are hashed into a "function selector" (the first 4 bytes of the Keccak-256 hash of the function signature)
- The parameters are encoded according to their types following the ABI specification
- The resulting data is sent as part of a transaction or call via your provider
- The returned data is decoded according to the output types specified in the ABI
It's like your JavaScript is being translated to blockchain-speak and back again through viem
.
ABIs vs APIs: The Technical Distinctions for JavaScript Engineers
As JavaScript engineers transition into Web3, there are some technical distinctions to keep in mind when building blockchain applications.
The biggest shift for JavaScript developers is understanding that smart contracts are state machines, not servers.
- APIs (Request-Response): The server processes your request and returns a response. The server's state can change in any way the developer programmed.
- Smart Contracts (State Machines): The contract has a defined set of state transitions. Your transaction proposes a state change that must follow the rules encoded in the contract.
With APIs, the server is in control. With smart contracts, the rules are in control because the “server” (the EVM’s execution environment) is globally shared —and they're transparent to everyone.

The blockchain version is often more complex because:
- We need user permission (wallet connection)
- We pay for computation (gas estimation)
- We wait for confirmation (
tx.wait()
) - We extract results from event logs rather than direct returns
Real World Example: ERC20 Implementation Using OpenZeppelin Contracts
One of the most common contracts to interact with are ERC20 token contracts from OpenZeppelin contracts library.
OpenZeppelin contracts let you extend standard tokens with additional functionality, making ERC20 implementation straightforward for JavaScript developers.
// Import OpenZeppelin's ERC20 and Pausable ABI and viem functions
import { createPublicClient, createWalletClient, custom, getContract } from 'viem';
import { mainnet } from 'viem/chains';
import ERC20PausableABI from '@openzeppelin/contracts/build/contracts/ERC20Pausable.json';
// Create a public client - used for reading blockchain data
// This client doesn't require a signer and can only perform read operations
// like calling view/pure functions, getting block information, etc.
const publicClient = createPublicClient({
chain: mainnet,
transport: custom(window.ethereum)
});
// Create a wallet client - used for writing data to the blockchain
// This client connects to the user's wallet (MetaMask, etc.) and can sign transactions
// It's required for any operation that changes blockchain state (transfers, contract writes, etc.)
const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
});
// Connect to the token contract
// We use the publicClient for the contract instance since most interactions are reads
const contract = getContract({
address: tokenAddress,
abi: ERC20PausableABI.abi,
publicClient
});
// Get token details - these are read operations using the publicClient
const name = await contract.read.name();
const symbol = await contract.read.symbol();
const isPaused = await contract.read.paused();
console.log(`${name} (${symbol}) Is Paused: ${isPaused}`);
// To pause the token (if you have the rights)
if (!isPaused) {
// Request user wallet access - needed for the wallet client to sign transactions
// This prompts the user's wallet (e.g., MetaMask) to connect if not already connected
const [address] = await walletClient.requestAddresses();
// Send the transaction using the wallet client since we're writing to the blockchain
// This requires the user to sign the transaction in their wallet
const hash = await walletClient.writeContract({
address: tokenAddress,
abi: ERC20PausableABI.abi,
functionName: 'pause',
account: address
});
// Wait for the transaction to be mined - we use the publicClient for this
// since it's just reading the transaction status from the blockchain
await publicClient.waitForTransactionReceipt({ hash });
console.log(`${symbol} is now paused`);
}
The JavaScript Developer's Toolkit for Web3
Here are the most common Web3 libraries for JavaScript to interact with blockchain during your JavaScript to Web3 transition:
1. Libraries
- viem - TypeScript-first Ethereum library for all JS projects
- wagmi - React hooks for Ethereum to make interacting with the blockchain easier for the frontend
- ethers.js - An older version to
viem
's similar functionality
2. Development Environment for Ethereum Development with JavaScript
- Hardhat - Ethereum development environment with JavaScript support
- Foundry - Fast, portable toolkit for Ethereum development, all Solidity
3. Testing Your Smart Contract Interaction
- Hardhat Network - Local blockchain for testing
- Anvil - Local Ethereum node
- Tenderly - For simulating transactions before sending them
4. Frontend Authentication - Wallet Connectors
- ConnectKit - Wallet connection interface
- WalletConnect - Modal for connecting to various wallets
- RainbowKit - Wallet connection UI
Conclusion: Mastering Your JavaScript to Web3 Transition
Moving from APIs to ABIs requires a mental shift, but here are the key differences to remember for JavaScript engineers:
- ABIs are your contract interface - They define how you can interact with the contract
- Web3 providers are your network gateway - They connect your JavaScript code to the blockchain
- Transactions, not requests - You're proposing state changes to a decentralized network
- Gas and confirmation - Operations cost money and take time to confirm
- Events for updates - Use contract events to track changes and updates
- State machine, not server - Contracts follow strict rules for state transitions
There's something satisfying about code that executes exactly as written, without hidden dependencies or server-side surprises. You're not calling an API — you're participating in a global state machine through Ethereum development with JavaScript.
That understanding makes all the difference in your JavaScript to Web3 transition.