# Issue commands
Unlike the other [client libraries](https://redis.io/docs/latest/develop/clients),
`hiredis` doesn't provide an extensive API to construct the many different
Redis [commands](https://redis.io/docs/latest/commands). However, it does provide a lightweight and
flexible API to help you construct commands and parse their replies from
your own code.
The sections below describe the available functions in
detail.
## Construct synchronous commands
Use the `redisCommand()` function to send commands to the server:
```c
void *redisCommand(redisContext *c, const char *format, ...);
```
This function receives a `redisContext` pointer and a pointer
to a string containing the command (see
[Connect](https://redis.io/docs/latest/develop/clients/hiredis/connect)
to learn how to obtain the context pointer). The command text is the
same as the equivalent [`redis-cli`](https://redis.io/docs/latest/develop/tools/cli)
command. For example, to issue the command:
```
SET foo bar
```
you would use the following command with an existing `redisContext* c`:
```c
redisReply *reply = redisCommand(c, "SET foo bar");
```
See the [Command reference](https://redis.io/docs/latest/commands) for examples
of CLI commands that you can use with `hiredis`. Most code examples
in other sections of the docs also have a CLI tab showing
command sequences that are equivalent to the code.
The command string is interpreted in a similar way to the format
string for `printf()`, so you can easily interpolate string values from
your code into the command with the `%s` format specifier:
```c
char *myKeyNumber = "1";
char *myValue = "Hello";
// This issues the command 'SET key:1 Hello'.
redisReply *reply = redisCommand(c, "SET key:%s %s", myKeyNumber, myValue);
```
You may need to include binary data in the command (for example, to store
[vector embeddings](https://redis.io/docs/latest/develop/interact/search-and-query/advanced-concepts/vectors)
in fields of a [hash](https://redis.io/docs/latest/develop/data-types/hashes)) object.
To do this, use the `%b` format specifier and pass a pointer to the
data buffer, followed by a `size_t` value indicating its length in bytes.
As the example below shows, you can freely mix `%s` and `%b` specifiers
in the same format string. Also, you can use the sequence `%%` to
denote a literal percent sign, but the other `printf()` specifiers,
such as `%d`, are not supported.
```c
char *entryNumber = "1";
char *embedding = "";
char *url = "https://redis.io/";
size_t embLength = 13;
redisReply *reply = redisCommand(c,
"HSET entry:%s embedding %b url %s",
entryNumber,
embedding, embLength,
url
);
```
The `redisCommand()` function has a variant called `redisCommandArgv()`:
```c
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
```
This doesn't take a format string but instead builds the command from an array
of strings passed in the `argv` parameter.
Use the `argc` value to
specify the length of this array and the `argvlen` array to specify
the lengths of each of the strings in the array. If you pass `NULL`
for `argvlen` then the function will attempt to use `strlen()` to
get the length of each string. However, this will not work if any of
the strings contains binary data, so you should pass `argvlen`
explicitly in this case. The example below shows how to use
`redisCommandArgv()` with a simple command:
```c
const char *argv[3] = { "SET", "greeting", "hello"};
int argc = 3;
const size_t argvlen[] = {3, 8, 5};
redisReply *reply = redisCommandArgv(c, argc, argv, argvlen);
```
## Construct asynchronous commands
Use the `redisAsyncCommand()` and `redisAsyncCommandArgv()`
functions to send commands to the server asynchronously:
```c
#include
.
.
.
int redisAsyncCommand(
redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
const char *format, ...);
int redisAsyncCommandArgv(
redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
int argc, const char **argv, const size_t *argvlen);
```
These work the same way as `redisCommand()` and `redisCommandArgv()`
(see [Construct synchronous commands](#construct-synchronous-commands)
above) but they have two extra parameters. The first is a pointer to
a optional callback function and the second is a pointer to your own
custom data, which will be passed to the callback when it
executes. Pass `NULL` for both of these pointers if you don't need
to use them.
The callback has the following signature:
```c
void(redisAsyncContext *c, void *reply, void *privdata);
```
The first parameter is the asynchronous connection context and
the second is a pointer to the reply object. Use a cast to
`(redisReply *)` to access the reply in the usual way (see
[Handle command replies](https://redis.io/docs/latest/develop/clients/hiredis/handle-replies)
for a full description of `redisReply`). The last parameter
is the custom data pointer that you supplied during the
`redisAsyncCommand()` call. This is passed to your function
without any modification.
The example below shows how you can use `redisAsyncCommand()` with
or without a reply callback:
```c
// The callback expects the key for the data in the `privdata`
// custom data parameter.
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
char *key = privdata;
if (reply == NULL) {
if (c->errstr) {
printf("errstr: %s\n", c->errstr);
}
return;
}
printf("Key: %s, value: %s\n", key, reply->str);
/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}
.
.
.
// Key and string value to pass to `SET`.
char *key = "testkey";
char *value = "testvalue";
// We aren't interested in the simple status reply for
// `SET`, so use NULL for the callback and custom data
// pointers.
redisAsyncCommand(c, NULL, NULL, "SET %s %s", key, value);
// The reply from `GET` is essential, so set a callback
// to retrieve it. Also, pass the key to the callback
// as the custom data.
redisAsyncCommand(c, getCallback, key, "GET %s", key);
```
Note that you should normally disconnect asynchronously from a
callback when you have finished using the connection.
Use `redisAsyncDisconnect()` to disconnect gracefully, letting
pending commands execute and activate their callbacks.
Use `redisAsyncFree()` to disconnect immediately. If you do this then
any pending callbacks from commands that have already executed will be
called with a `NULL` reply pointer.
## Command replies
The information in the `redisReply` object has several formats,
and the format for a particular reply depends on the command that generated it.
See
[Handle replies](https://redis.io/docs/latest/develop/clients/hiredis/handle-replies)
to learn about the different reply formats and how to use them.