Build on Internet Computer with ICP Rust CDK
Explaining Frontend Code
Connecting Frontend and Backend in ICP: Final Project Walkthrough
Welcome to the final video of our Internet Computer Protocol (ICP) development series. In the previous video, we explored the frontend of our voting application. In this lesson, we’ll dive into the code and focus on how the frontend interacts with the backend smart contracts.
Purpose of This Lesson
This tutorial is not about how the frontend works in detail, but rather about how the frontend communicates with the backend smart contracts. We'll explore how to make API calls to the backend, pass data, and handle smart contract responses.
Importing the Backend in the Frontend
To begin interacting with the backend, we import the final_project_backend from the generated declarations folder. This file is auto-created when you deploy your project and includes all the exposed methods and structures from the backend.
import { final_project_backend } from "../../../declarations/final_project_backend";
This makes it extremely easy to connect to the backend—easier than many traditional Web2 applications.
Using Asynchronous Functions
To call a backend method, use asynchronous functions in your frontend. For example, to get the current proposal:
const currentProposal = await final_project_backend.get_proposal(count);
- The backend function get_proposal expects a nat64 value (interpreted as a number in JavaScript).
- It returns a proposal object, which can then be used just like any JavaScript object.
Retrieving Proposals in Bulk
Since we can't get all proposals at once, we use a loop to retrieve them individually:
- Get the total number of proposals using get_proposal_count().
- Use a loop to fetch each proposal by ID and push it into a list.
This list is then set in state to display on the frontend.
Displaying Proposals
Proposals and their counts are passed from the main page to the Hero section, and then down to the ProposalCard component.
Each component only focuses on presentation. The business logic and data retrieval happen in the main page.
Voting Functionality
Voting is handled via a method that sets a user’s choice (approve, reject, or pass) and sends it to the backend.
Enum Handling
The Choice enum from Rust is used here. Since these enums don't carry values, we pass them as null when calling from the frontend. If the enums had payloads (e.g., a String or u32), we would need to include that data.
Editing Proposals
To edit a proposal:
- Call edit_proposal with the proposal_id and a new CreateProposal object.
- This object must match the backend structure, with fields like description (String) and is_active (Boolean).
Again, types must match exactly between frontend and backend to ensure smooth operation.
Key Integration Tips
- Type Matching: Text in Rust maps to String in JavaScript, and nat64 maps to number.
- Async/Await: Always use async/await for backend calls.
- Mirror Structures: Ensure frontend data structures match backend expectations exactly.
Security Best Practices
It's vital that all validation and permission checks happen on the backend. Anyone can interact with your smart contract, not just through your frontend. Always enforce ownership, access control, and input validation server-side.
Final Thoughts
Connecting your ICP backend to a frontend is more straightforward than most Web2 systems. The key is understanding data types and struct alignment between Rust and JavaScript. Let the backend handle logic and security; let the frontend focus on user interaction.
Thank you for following this course. I hope this walkthrough helps you on your journey to becoming a smart contract developer.
Comments
You need to enroll in the course to be able to comment!