# Basic operations · A simple Chromia app with Rell and React · Learn Chromia

> This part of the tutorial covers basic operations on the Chromia blockchain, focusing on how you write data with transactions. When you finish, you will…

Source: https://chromia.com/learn/my-news-feed/module-one/operations-queries/basic-operations/

A simple Chromia app with Rell and ReactLesson 11 of 27

1. [01Building a simple Chromia app with Rell, React and FT4](https://chromia.com/learn/my-news-feed/introduction/)
2. [02Project setup complete](https://chromia.com/learn/my-news-feed/setup/)

Module 1: A Rell backend with FT accounts

1. [03Overview](https://chromia.com/learn/my-news-feed/module-one/)
2. [04Part 1: Designing the database schema](https://chromia.com/learn/my-news-feed/module-one/data-modeling/)
3. [05The data model](https://chromia.com/learn/my-news-feed/module-one/data-modeling/tables/)
4. [06Code the model in Rell](https://chromia.com/learn/my-news-feed/module-one/data-modeling/model/)
5. [07Part 2: Set up accounts](https://chromia.com/learn/my-news-feed/module-one/create-accounts/)
6. [08FT4 accounts configuration](https://chromia.com/learn/my-news-feed/module-one/create-accounts/install-configure-ft4/)
7. [09Authentication with FT4 accounts](https://chromia.com/learn/my-news-feed/module-one/create-accounts/authentication/)
8. [10Part 3: A closer look at operations and queries](https://chromia.com/learn/my-news-feed/module-one/operations-queries/)
9. [11Basic operations](https://chromia.com/learn/my-news-feed/module-one/operations-queries/basic-operations/)
10. [12Basic queries](https://chromia.com/learn/my-news-feed/module-one/operations-queries/write-queries/)
11. [13Part 4: Validating and verifying input](https://chromia.com/learn/my-news-feed/module-one/input-verification/)
12. [14Verify inputs](https://chromia.com/learn/my-news-feed/module-one/input-verification/input-verification/)
13. [15Run unit tests](https://chromia.com/learn/my-news-feed/module-one/input-verification/tests/)
14. [16Part 5: How the dapp project is organized](https://chromia.com/learn/my-news-feed/module-one/project-structure/)
15. [17Work with Rell modules](https://chromia.com/learn/my-news-feed/module-one/project-structure/modules/)
16. [18Add modules to your dapp](https://chromia.com/learn/my-news-feed/module-one/project-structure/incorporate-modules/)
17. [19Part 6: Sign up users with an EVM wallet](https://chromia.com/learn/my-news-feed/module-one/register-evm-accounts/)
18. [20Sign up accounts with EVM wallets](https://chromia.com/learn/my-news-feed/module-one/register-evm-accounts/register-evm-accounts/)
19. [21Test the registration](https://chromia.com/learn/my-news-feed/module-one/register-evm-accounts/test-registration/)

Module 2: The React project

1. [22Overview](https://chromia.com/learn/my-news-feed/module-two/)
2. [23Set up the project](https://chromia.com/learn/my-news-feed/module-two/setup/)
3. [24Project scaffold](https://chromia.com/learn/my-news-feed/module-two/scaffold/)
4. [25Connect the client](https://chromia.com/learn/my-news-feed/module-two/connecting-the-client/)
5. [26Summary and manual testing](https://chromia.com/learn/my-news-feed/module-two/summary-and-tests/)

1. [27What is next?](https://chromia.com/learn/my-news-feed/what-next/)

[Learn](https://chromia.com/learn/)[A simple Chromia app with Rell and React](https://chromia.com/learn/my-news-feed/)

11 / 27Module 1: A Rell backend with FT accountsBeginner

# Basic operations

This part of the tutorial covers basic operations on the Chromia blockchain, focusing on how you write data with transactions. When you finish, you will know how to create users, publish posts, and manage followers in your dapp.

## Add data through transactions

You write data to a Chromia blockchain by sending transactions. Each transaction holds one or more database actions called "operations." The operations below create users, publish posts, and set up follow relationships.

### Register a user

src/registration/module.rell

```
operation register_user(name) {
    val account = register_account();
    val user = create user ( name, account.id, account );
    create follower ( user = user, follower = user );
}
```

`register_user` adds a new user to the database from a single parameter, `name`, which holds the user's name. The public key that serves as the `id` goes straight into the constructor, because Rell matches arguments to attributes by their type.

* The public key must be a `byte_array` that is 32 or 64 bytes long.

You can also write it this way:

rell

```nolines
create user( name = name, id = pubkey );
```

### Make a post

rell/src/news\_feed/operations.rell

```
operation make_post(content: text) {
    val account = auth.authenticate();
    require(content.size() <= 255, "A post cannot be longer than 255 letters");
    val user = user @ { account };
    create post ( user, content );
}
```

`make_post` publishes a post. You pass it `user_id`, the ID of the author, and `content`, the post's text. You don't supply a timestamp, since the entity definition gives it a default value.

### Follow a user

rell/src/news\_feed/operations.rell

```
operation follow_user(follow_pubkey: pubkey) {
    val account = auth.authenticate();
    val user = user @ { account };
    val follow = require_user(follow_pubkey);
    create follower ( user = follow, follower = user );
}
```

`follow_user` lets one user follow another. It takes `user_id`, the ID of the user doing the following, and `follow_id`, the ID of the user being followed. It loads both users from the database and then creates a `follower` entity that records the relationship.

### Unfollow a user

Unfollowing means deleting the matching `follower` entity.

rell/src/news\_feed/operations.rell

```
operation unfollow_user(unfollow_id: byte_array) {
    val account = auth.authenticate();
    val user = user @ { account };
    val follow = require_user(unfollow_id);
    delete follower @? { .user == follow, .follower == user };
}
```

## Test the operations

Next, you add unit tests to confirm the dapp code behaves as expected.

### Test module

1. Open the test folder in your project directory.
2. Find the file `news_feed_test.rell` there. Your test cases go in this file.

src/test/news\_feed\_test.rell

```
@test module;

import ^.test_operations. { create_user };
import ^^.news_feed.*;
import lib.ft4.test.core. { ft_auth_operation_for };
```

* The `@test` annotation on the module declaration marks it as test code.
* `import^^.news_feed.*;` pulls in everything from the `news_feed` module so your tests can reach the dapp code.
* For tests that use FT4 authentication, call `auth.ft_auth` or `auth.evm_auth`  
  in the same transaction, immediately before the operation.
  To build it, use the `ft_auth_operation_for` function from the test module of the `ft` library.

### Test dapp

The following test cases check that your dapp works correctly by covering user creation, follow relationships, and posts.

src/test/news\_feed\_test.rell

```

val alice = rell.test.pubkeys.alice;
val bob = rell.test.pubkeys.bob;

function test_create_entities() {
    rell.test.tx()
        .op(create_user("Alice", alice))
        .op(create_user("Bob", bob))
        .run();
    assert_equals(user @ { } ( @sum 1 ), 2);
    rell.test.tx()
        .op(ft_auth_operation_for(alice))
        .op(follow_user(bob))
        .op(ft_auth_operation_for(alice))
        .op(make_post("My post"))
        .sign(alice_kp)
        .run();
    assert_true(is_following(alice, bob));
    assert_equals(follower @ { } ( @sum 1 ), 1);
    assert_equals(post @ { } ( @sum 1 ), 1);
    rell.test.tx()
        .op(ft_auth_operation_for(alice))
        .op(unfollow_user(bob))
        .sign(alice_kp)
        .run();
    assert_equals(follower @ { } ( @sum 1 ), 0);
}
```

What this test does:

* It takes two public keys from the Rell test framework, `alice` and `bob`, and uses them as user IDs.
* `test_create_entities` is a test case, which its `test_` prefix signals. It sends a sequence of transactions that create users and handle their interactions.
* After every transaction, `assert_equals` verifies that each table contains the expected number of entities. The count comes from `@sum`, which aggregates over the table; the summed value is set to `1` since only the number of entities matters.

The updated `test_input_verification` shows how well this approach blocks impersonation. When Charlie attempts to post, the attempt fails because he cannot produce the auth operation. Here is the revised test:

src/test/news\_feed\_test.rell

```
function test_input_verification() {
    rell.test.tx()
        .op(create_user("Alice", alice))
        .op(create_user("Bob", bob)).run();

    // Bob cannot impersonate alice
    rell.test.tx()
        .op(ft_auth_operation_for(alice))
        .op(follow_user(bob))
        .sign(bob_kp)
        .run_must_fail();
    rell.test.tx()
        .op(ft_auth_operation_for(alice))
        .op(make_post("My malicous post"))
        .sign(bob_kp)
        .run_must_fail();

    // Alice cannot follow non-existing charlie
    val f1 = rell.test.tx()
        .op(ft_auth_operation_for(alice))
        .op(follow_user(charlie))
        .sign(alice_kp)
        .run_must_fail();
    assert_true(f1.message.contains("does not exist"));

    // Charlie cannot create post since he does not exist
    val f2 = rell.test.tx()
        .op(make_post("My secret post"))
        .sign(charlie_kp)
        .run_must_fail();
    assert_true(f2.message.contains("Expected at least two operations"));
}
```

### Run the tests

You can now run the tests to check your dapp.

1. In a terminal, go to the root directory of your project.
2. Run this command:

shell

```nolines
chr test
```

The command executes the tests found in the `test: modules` listed in `chromia.yml`. When every test passes, the output confirms that your dapp behaves as intended.

Your dapp now has unit tests that help keep it reliable.

Written for this site from Chromia’s public course. Code samples are the course’s own.

[← Previous**Part 3: A closer look at operations and queries**](https://chromia.com/learn/my-news-feed/module-one/operations-queries/)[Next →**Basic queries**](https://chromia.com/learn/my-news-feed/module-one/operations-queries/write-queries/)

On this page

* [Add data through transactions](#add-data-through-transactions)
* [Test the operations](#test-the-operations)
