# Creating posts

In this chapter, we will be focusing on the process of handling a "create post"
message. This involves the use of a special type of function known as a keeper
method. [Keeper](https://docs.cosmos.network/main/building-modules/keeper)
methods are responsible for interacting with the blockchain and modifying its
state based on the instructions provided in a message.

When a "create post" message is received, the corresponding keeper method will
be called and passed the message as an argument. The keeper method can then use
the various getter and setter functions provided by the store object to retrieve
and modify the current state of the blockchain. This allows the keeper method to
effectively process the "create post" message and make the necessary updates to
the blockchain.

In order to keep the code for accessing and modifying the store object clean and
separate from the logic implemented in the keeper methods, we will create a new
file called `post.go`. This file will contain functions that are specifically
designed to handle operations related to creating and managing posts within the
blockchain.

## Appending posts to the store

```go title="x/blog/keeper/post.go"
package keeper

import (
	"encoding/binary"

	"blog/x/blog/types"

	"github.com/cosmos/cosmos-sdk/store/prefix"
	sdk "github.com/cosmos/cosmos-sdk/types"
)

func (k Keeper) AppendPost(ctx sdk.Context, post types.Post) uint64 {
	count := k.GetPostCount(ctx)
	post.Id = count
	store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.PostKey))
	appendedValue := k.cdc.MustMarshal(&post)
	store.Set(GetPostIDBytes(post.Id), appendedValue)
	k.SetPostCount(ctx, count+1)
	return count
}
```

This code defines a function called `AppendPost` which belongs to a `Keeper`
type. The `Keeper` type is responsible for interacting with the blockchain and
modifying its state in response to various messages.

The `AppendPost` function takes in two arguments: a `Context` object and a
`Post` object. The [`Context`](https://docs.cosmos.network/main/core/context)
object is a standard parameter in many functions in the Cosmos SDK and is used
to provide contextual information about the current state of the blockchain,
such as the current block height. The `Post` object represents a post that will
be added to the blockchain.

The function begins by retrieving the current post count using the
`GetPostCount` method. You will implement this method in the next step as it has
not been implemented yet. This method is called on the `Keeper` object and takes
in a `Context` object as an argument. It returns the current number of posts
that have been added to the blockchain.

Next, the function sets the ID of the new post to be the current post count, so
that each post has a unique identifier. It does this by assigning the value of
count to the `Id` field of the `Post` object.

The function then creates a new
[store](https://docs.cosmos.network/main/core/store) object using the
`prefix.NewStore` function. The `prefix.NewStore` function takes in two
arguments: the `KVStore` associated with the provided context and a key prefix
for the `Post` objects. The `KVStore` is a key-value store that is used to
persist data on the blockchain, and the key prefix is used to differentiate the
`Post` objects from other types of objects that may be stored in the same
`KVStore`.

The function then serializes the `Post` object using the `cdc.MustMarshal`
function and stores it in the blockchain using the `Set` method of the store
object. The `cdc.MustMarshal` function is part of the Cosmos SDK's
[encoding/decoding](https://docs.cosmos.network/main/core/encoding) library and
is used to convert the `Post` object into a byte slice that can be stored in the
`KVStore`. The `Set` method is called on the store object and takes in two
arguments: a key and a value. In this case, the key is a byte slice generated by
the `GetPostIDBytes` function and the value is the serialized `Post` object. You
will implement this method in the next step as it has not been implemented yet.

Finally, the function increments the post count by one and updates the
blockchain state using the `SetPostCount` method. You will implement this method
in the next step as it has not been implemented yet. This method is called on
the Keeper object and takes in a `Context` object and a new post count as
arguments. It updates the current post count in the blockchain to be the new
post count provided.

The function then returns the ID of the newly created post, which is the current
post count before it was incremented. This allows the caller of the function to
know the ID of the post that was just added to the blockchain.

To complete the implementation of `AppendPost`, the following tasks need to be
performed:

* Define `PostKey`, which will be used to store and retrieve posts from the
  database.
* Implement `GetPostCount`, which will retrieve the current number of posts
  stored in the database.
* Implement `GetPostIDBytes`, which will convert a post ID to a byte array.
* Implement `SetPostCount`, which will update the post count stored in the
  database.

### Post key prefix

In the file `keys.go`, let's define the `PostKey` prefix as follows:

```go title="x/blog/types/keys.go"
const (
	PostKey = "Post/value/"
)
```

This prefix will be used to uniquely identify a post within the system. It will
be used as the beginning of the key for each post, followed by the ID of the
post to create a unique key for each post.

### Getting the post count

In the file `post.go`, let's define the `GetPostCount` function as follows:

```go title="x/blog/keeper/post.go"
func (k Keeper) GetPostCount(ctx sdk.Context) uint64 {
	store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{})
	byteKey := types.KeyPrefix(types.PostCountKey)
	bz := store.Get(byteKey)
	if bz == nil {
		return 0
	}
	return binary.BigEndian.Uint64(bz)
}
```

This code defines a function named `GetPostCount` that belongs to the `Keeper`
struct. The function takes in a single argument, a context object `ctx` of type
`sdk.Context`, and returns a value of type `uint64`.

The function begins by creating a new store using the key-value store in the
context and an empty byte slice as the prefix. It then defines a byte slice
`byteKey` using the `KeyPrefix` function from the `types` package, which takes
in the `PostCountKey`. You will define `PostCountKey` in the next step.

The function then retrieves the value at the key `byteKey` in the store using
the `Get` method and stores it in a variable `bz`.

Next, the function checks if the value at `byteKey` is `nil` using an if
statement. If it is `nil`, meaning that the key does not exist in the store, the
function returns 0. This indicates that there are no elements or posts
associated with the key.

If the value at `byteKey` is not nil, the function uses the `binary` package's
`BigEndian` type to parse the bytes in `bz` and returns the resulting `uint64`
value. The `BigEndian` type is used to interpret the bytes in `bz` as a
big-endian encoded unsigned 64-bit integer. The `Uint64` method converts the
bytes to a `uint64` value and returns it.

`GetPostCount` function is used to retrieve the total number of posts stored in
the key-value store, represented as a `uint64` value.

In the file `keys.go`, let's define the `PostCountKey` as follows:

```go title="x/blog/types/keys.go"
const (
	PostCountKey = "Post/count/"
)
```

This key will be used to keep track of the ID of the latest post added to the
store.

### Converting post ID to bytes

Now, let's implement `GetPostIDBytes`, which will convert a post ID to a byte
array.

```go title="x/blog/keeper/post.go"
func GetPostIDBytes(id uint64) []byte {
	bz := make([]byte, 8)
	binary.BigEndian.PutUint64(bz, id)
	return bz
}
```

`GetPostIDBytes` takes in a value `id` of type `uint64` and returns a value of
type `[]byte`.

The function starts by creating a new byte slice `bz` with a length of 8 using
the `make` built-in function. It then uses the `binary` package's `BigEndian`
type to encode the value of `id` as a big-endian encoded unsigned integer and
store the result in `bz` using the `PutUint64` method. Finally, the function
returns the resulting byte slice `bz`.

This function can be used to convert a post ID, represented as a `uint64`, to a
byte slice that can be used as a key in a key-value store. The
`binary.BigEndian.PutUint64` function encodes the `uint64` value of `id` as a
big-endian encoded unsigned integer and stores the resulting bytes in the
`[]byte` slice `bz`. The resulting byte slice can then be used as a key in the
store.

### Updating the post count

Implement `SetPostCount` in `post.go`, which will update the post count stored
in the database.

```go title="x/blog/keeper/post.go"
func (k Keeper) SetPostCount(ctx sdk.Context, count uint64) {
	store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{})
	byteKey := types.KeyPrefix(types.PostCountKey)
	bz := make([]byte, 8)
	binary.BigEndian.PutUint64(bz, count)
	store.Set(byteKey, bz)
}
```

This code defines a function `SetPostCount` in the `Keeper` struct. The function
takes in a context `ctx` of type `sdk.Context` and a value `count` of type
`uint64`, and does not return a value.

The function first creates a new store by calling the `NewStore` function from
the prefix package and passing in the key-value store from the context and an
empty byte slice as the prefix. It stores the resulting store in a variable
named `store`.

Next, the function defines a byte slice `byteKey` using the `KeyPrefix` function
from the `types` package and passing in the `PostCountKey`. The `KeyPrefix`
function returns a byte slice with the given key as a prefix.

The function then creates a new byte slice `bz` with a length of 8 using the
`make` built-in function. It then uses the `binary` package's `BigEndian` type
to encode the value of count as a big-endian encoded unsigned integer and store
the result in `bz` using the `PutUint64` method.

Finally, the function calls the `Set` method on the `store` variable, passing in
`byteKey` and `bz` as arguments. This sets the value at the key `byteKey` in the
store to the value `bz`.

This function can be used to update the count of posts stored in the database.
It does this by converting the `uint64` value of count to a byte slice using the
`binary.BigEndian.PutUint64` function, and then storing the resulting byte slice
at the key `byteKey` in the store using the `Set` method.

Now that you have implemented the code for creating blog posts, you can proceed
to implement the keeper method that is invoked when the "create post" message is
processed.

## Handling the "create post" message

```go title="x/blog/keeper/msg_server_create_post.go"
package keeper

import (
	"context"

	"blog/x/blog/types"

	sdk "github.com/cosmos/cosmos-sdk/types"
)

func (k msgServer) CreatePost(goCtx context.Context, msg *types.MsgCreatePost) (*types.MsgCreatePostResponse, error) {
	ctx := sdk.UnwrapSDKContext(goCtx)
	var post = types.Post{
		Creator: msg.Creator,
		Title:   msg.Title,
		Body:    msg.Body,
	}
	id := k.AppendPost(
		ctx,
		post,
	)
	return &types.MsgCreatePostResponse{
		Id: id,
	}, nil
}
```

The `CreatePost` function is a message handler for the `MsgCreatePost` message
type. It is responsible for creating a new post on the blockchain based on the
information provided in the `MsgCreatePost` message.

The function first retrieves the Cosmos SDK context from the Go context using
the `sdk.UnwrapSDKContext` function. It then creates a new `Post` object using
the `Creator`, `Title`, and `Body` fields from the MsgCreatePost message.

Next, the function calls the `AppendPost` method on the `msgServer` object
(which is of the Keeper type) and passes in the Cosmos SDK context and the new
`Post` object as arguments. The `AppendPost` method is responsible for adding
the new post to the blockchain and returning the ID of the new post.

Finally, the function returns a `MsgCreatePostResponse` object that contains the
ID of the new post. It also returns a nil error, indicating that the operation
was successful.

## Summary

Great job! You have successfully implemented the logic for writing blog posts to
the blockchain store and the keeper method that will be called when a "create
post" message is processed.

The `AppendPost` keeper method retrieves the current post count, sets the ID of
the new post to be the current post count, serializes the post object, and
stores it in the blockchain using the `Set` method of the `store` object. The
key for the post in the store is a byte slice generated by the `GetPostIDBytes`
function and the value is the serialized post object. The function then
increments the post count by one and updates the blockchain state using the
`SetPostCount` method.

The `CreatePost` handler method receives a `MsgCreatePost` message containing
the data for the new post, creates a new `Post` object using this data, and
passes it to the `AppendPost` keeper method to be added to the blockchain. It
then returns a `MsgCreatePostResponse` object containing the ID of the newly
created post.

By implementing these methods, you have successfully implemented the necessary
logic for handling "create post" messages and adding posts to the blockchain.