How to Code Solidity Smart Contract CRUD Functions: The Right Way
Tags: solidity, smartcontract, blockchain, web3
Published: 2022-05-15 17:55:00

## Introduction

Smart contract development and the Web3 economy are still in their infancy, and there is a high demand for blockchain developers globally.

According to a recent [LinkedIn report](https://www.linkedin.com/posts/linkedin-news_theworkshift-economy-labormarket-activity-6887062336839016450-67iT/), job postings containing terms like Bitcoin, blockchain, and other digital asset-related roles increased 395 percent in 2021 in the United States compared to the previous year. With a 98 percent increase, this was the fastest growing industry in history, outpacing the entire industry by four times.

Blockchain development has a greater chance of landing you that six-figure dream job of yours. And the coolest part is that most blockchain jobs are remote base, so you don’t need to worry about locations.

But how do you jump in and capitalize on this space? It's by learning how to build things with the technology.

If you are looking for a personal tutor to speed you up with web3 development kindly [**book a session with me**](http://daltonic.github.io/).

With that being said, let’s jump into this tutorial…

[Check out my YouTube channel for FREE web3 tutorials now](https://www.youtube.com/channel/UCQteXYZ5mC-cuTxplzM4Hlw?sub_confirmation=1).

## Why you should Master CRUD Function in Solidity

Mastering how to create, read, update, and delete records from the blockchain is a skill you must understand. Yes, you can delete stuff from the blockchain (to an extent) using the technique you are about to learn.

CRUD skills are needed to effectively build a content-driven system, and being that the blockchain serves as a database to immutably store records, wisdom demands that you understand how to work with the technology.

Again, if you’re going to work on a blockchain project for either a company or a client, there may still be a need to remove some unnecessary records which is why you should **ACE** your Solidity CRUD skills now.

What if you’re working on a web3 blog project, and you know there needs to be a delete button for very bad comments. You will need a delete functionality in that case.

You see that a good knowledge of CRUD will become inevitable as you dive deep into blockchain development.

By the way, deleting a record from a blockchain network is kind of different from the way you delete from a regular database. The record will still exist in the network but will be removed from your web3 app.

The full example below will show you step by step how to accomplish this.

## CRUD Functions Example

This is a smart contract that I created and tested; to see how it works, you can open it in a remix editor and run it yourself. But first, finish the tutorial; there is important information below that explains each function specifically.


{% gist https://gist.github.com/Daltonic/57f054c6b06241c5adab9ac6bbd32986 %}


Alright, let's dissect this smart contract step by step; if you're a beginner, don't worry; I wrote this smart contract example to demonstrate simplicity.

**Step 1:** The smart contract structure


    //SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    contract Blog {
      // code goes here...
    }

This is a typical smart contract structure; consider it a class in object-oriented programming because it is one in reality.

The SPDX is used to specify the smart contract's license type. Pragma refers to the version of the solidity compiler that will be used for the smart contract. Finally, the smart contract's name is Blog.

It is critical to note that the file name should always correspond to the class name; this will ensure consistency and prevent unnecessary bugs in your code.

**Step 2:** Defining Contract Variables


    address public owner;
    uint256 public activePostCounter = 0;
    uint256 public inactivePostCounter = 0;
    uint256 private postCounter = 0;

Here we have two types of variables: address and uint256. An address represents a user's account, whereas uint256 represents an unsigned integer ranging from 0 to 2256–1.

The owner will hold the deployer’s account, and activePostCounter holds the number of available posts. inactivePostCounter keeps track of the deleted post, just in case, it needs to be recovered. postCounter holds the total number of posts in the smart contract, but it is private.

**Step 3:** Defining the Mappings


    mapping(uint256 => address) public delPostOf;
    mapping(uint256 => address) public authorOf;
    mapping(address => uint256) public postsOf;

authorOf() is a mapped variable that accepts a postId and returns the address of the post author. Whereas, postsOf() keep track of an author’s posts, and delPostOf() serves as a recycle bin for each author.

**Step 4:** Defining an Enumerable


    enum Deactivated { NO, YES }

This is used to indicate whether or not a post has been deleted. Enum converts an alphabetical value to unsigned integers beginning with zero. For example, the values NO and YES would become 0 and 1, respectively.

**Step 5:** Defining the Struct


    struct PostStruct {
        uint256 postId;
        string title;
        string description;
        address author;
        Deactivated deleted; // We are using the enum here
        uint256 created;
        uint256 updated;
    }
    
    PostStruct[] activePosts;
    PostStruct[] inactivePosts;

Structs are used to define complex data structures, which are made up of two or more data types.

We specified in the above PostStruct that a post should have an Id, title, description, author, a deleted key, time of creation, and time of update.

Next, we made two arrays: one for active posts and one for inactive posts, or deleted posts. This method prevents data loss, but you can also use a single array and only toggle the deleted key on and off. However, this raises another issue: you'll have to read them all in your frontend app before showing the active posts. I'd like to spare you that trip.

**Step 6:** Defining an Event


    event Action (
        uint256 postId,
        string actionType,
        Deactivated deleted,
        address indexed executor,
        uint256 created
    );

We defined a dynamic event to emit some vital information on created, updated, deleted, and restored functions respectively.

**Step 7:** Defining modifier


    modifier ownerOnly(){
        require(msg.sender == owner, "Owner reserved only");
        _;
    }

A modifier is a function that changes the behavior of another function at compile time. We can say, it is a prerequisite for executing a function.

In the above modifier, we specified that the caller of the function to which this modifier will be attached must be the owner or deployer of the smart contract.

**Step 8:** Defining the Constructor


    constructor() {
        owner = msg.sender;
    }

From your OOP knowledge, a constructor is always the first function to run when a class is instantiated. OOP construct is mutual to smart contracts. 

The first function to run when this smart contract is deployed is the constructor, and we specified that it should make the owner the one who deployed the smart contract.

**Step 9:** The createPost() function


    function createPost(
        string memory title,
        string memory description
    ) external returns (bool) {
        // Checks for empty string
        require(bytes(title).length > 0, "Title cannot be empty");
        require(bytes(description).length > 0, "Description cannot be empty");
    
        // Performs computations
        postCounter++;
        authorOf[postCounter] = msg.sender;
        postsOf[msg.sender]++;
        activePostCounter++;
    
        // Adds post to array
        activePosts.push(
            PostStruct(
                postCounter,
                title,
                description,
                msg.sender,
                Deactivated.NO,
                block.timestamp,
                block.timestamp
            )
        );
      
        // Emits a created event
        emit Action (
            postCounter,
            "POST CREATED",
            Deactivated.NO,
            msg.sender,
            block.timestamp
        );
        
        // Returns success
        return true;
    }

This function accomplishes the post-creation in five steps.

Firstly, it checks that you are sending real information to the smart contract and not just an empty string.

Secondly, it performs some computations like incrementing post counts for the blog and for the author, including making the author the post owner.

Thirdly, it adds the post into the activePosts using the PostStruct defined earlier.

Fourthly, it emits a “POST CREATED” event which is logged off on the EVM, this is essential for enriching the information captured in a transaction.

Lastly, we returned a true boolean key indicating that the entire function ran successfully.

**Step 10:** The updatePost() function.


    function updatePost(
        uint256 postId,
        string memory title,
        string memory description
    ) external returns (bool) {
        // Checks for empty string
        require(authorOf[postId] == msg.sender, "Unauthorized entity");
        require(bytes(title).length > 0, "Title cannot be empty");
        require(bytes(description).length > 0, "Description cannot be empty");
    
        // Changes post record
        for(uint i = 0; i < activePosts.length; i++) {
            if(activePosts[i].postId == postId) {
                activePosts[i].title = title;
                activePosts[i].description = description;
                activePosts[i].updated = block.timestamp;
            }
        }
        
        // Emits a updated event
        emit Action (
            postId,
            "POST UPDATED",
            Deactivated.NO,
            msg.sender,
            block.timestamp
        );
      
        // Returns success
        return true;
    }

This function operates like the createPost() function. The difference is that when checking for an empty string, the updatePost() function ensures that the person updating the function is the post owner (author).

Next, it targets the particular post by the Id and updates the record.

**Step 11:** The showPost() function


    function showPost(
        uint256 postId
    ) external view returns (PostStruct memory) {
        PostStruct memory post;
        for(uint i = 0; i < activePosts.length; i++) {
            if(activePosts[i].postId == postId) {
                post = activePosts[i];
            }
        }
        return post;
    }

This simply returns our post by recursively searching for a match in the activePost array.

**Step 12:** The getPosts() function.


    function getPosts() external view returns (PostStruct[] memory) {
        return activePosts;
    }

Returns all available active blog posts.

**Step 13:** The getDeletedPost() function


    function getDeletedPost() 
      ownerOnly external view returns (PostStruct[] memory) {
        return inactivePosts;
    }

This simply returns all deleted posts and it can only be accessed by the owner of the blog.

**Step 14:** The deletePost() function


    function deletePost(uint256 postId) external returns (bool) {
        // check if post belong to user
        require(authorOf[postId] == msg.sender, "Unauthorized entity");
        
        // find and delete post
        for(uint i = 0; i < activePosts.length; i++) {
            if(activePosts[i].postId == postId) {
                activePosts[i].deleted = Deactivated.YES;
                activePosts[i].updated = block.timestamp;
                inactivePosts.push(activePosts[i]);
                delPostOf[postId] = authorOf[postId];
                delete activePosts[i];
                delete authorOf[postId];
            }
        }
    
        // Recallibrate counters
        postsOf[msg.sender]--;
        inactivePostCounter++;
        activePostCounter--;
    
        // Emits event
        emit Action (
            postId,
            "POST DELETED",
            Deactivated.YES,
            msg.sender,
            block.timestamp
        );
      
        // Returns success
        return true;
    }

The above function was achieved in four steps.

First, we validated that the owner of the post is the one deleting, then we searched for the post, deleted it, and emitted a “POST DELETED” event and also returns a boolean value of true.

Please, take note that the delete behavior is not done like in a normal database, rather we specified two arrays; activePosts and inactivePosts. Whenever we deleted a post, it will be moved to the inactivePosts array, and only the blog owner can restore it at the request of the post author.

**Step 15:** The Post Restore Function


    function restorDeletedPost(
        uint256 postId, 
        address author
    ) ownerOnly external returns (bool) {
        // checks if post exists in users recycle bin
        require(delPostOf[postId] == author, "Unmatched Author");
    
        // Finds and restore the post to the author
        for(uint i = 0; i < inactivePosts.length; i++) {
            if(inactivePosts[i].postId == postId) {
                inactivePosts[i].deleted = Deactivated.NO;
                inactivePosts[i].updated = block.timestamp;
                activePosts.push(inactivePosts[i]);
                delete inactivePosts[i];
                authorOf[postId] = delPostOf[postId];
                delete delPostOf[postId];
            }
        }
    
        // Recallibrates counter to reflect restored post
        postsOf[author]++;
        inactivePostCounter--;
        activePostCounter++;
    
        // Emits a restoration event
        emit Action (
            postId,
            "POST RESTORED",
            Deactivated.NO,
            msg.sender,
            block.timestamp
        );
    
        // resturns success
        return true;
    }

Whenever a post is restored, it is moved from the inactivePosts array to the activePosts array.

It is worth mentioning that you can design your delete pattern a little bit different than mine. You can decide to leverage on the enum Deactivated structure we created above, and only delete by toggling the deleted state to YES or NO.

Men and brethren, that is how you crush the solidity CRUD functions…

[Watch my FREE web3 tutorials on YouTube now](https://www.youtube.com/channel/UCQteXYZ5mC-cuTxplzM4Hlw?sub_confirmation=1).

## Conclusion

It’s been a blast journeying with you on this tutorial, I hope you got some valuable insights on how to write solidity smart contract CRUD functions.

I want to inform you of my private tutoring classes for those who want to jump into the web3 space. If you’re interested, please [**book me up on my website**](http://daltonic.github.io/).

That’s all for this tutorial, please like and share…

Expecting to see you in the next tutorial, till then, enjoy!


## About the Author

Gospel Darlington kick-started his journey as a software engineer in 2016. Over the years, he has grown full-blown skills in JavaScript stacks such as React, ReactNative, NextJs, and now blockchain.

He is currently freelancing, building apps for clients, and writing technical tutorials teaching others how to do what he does.

Gospel Darlington is open and available to hear from you. You can reach him on [LinkedIn](https://www.linkedin.com/in/darlington-gospel-aa626b125/), [Facebook](https://www.facebook.com/darlington.gospel01), [Github](https://github.com/Daltonic), or on his [website](https://daltonic.github.io/).