--- categories: - docs - develop - stack - oss - rs - rc - oss - kubernetes - clients description: Handle command replies with `hiredis`. linkTitle: Handle command replies title: Handle command replies weight: 10 --- The `redisCommand()` and `redisCommandArgv()` functions return a pointer to a `redisReply` object when you issue a command (see [Issue commands]({{< relref "/develop/clients/hiredis/issue-commands" >}}) for more information). This type supports all reply formats defined in the [RESP2 and RESP3]({{< relref "/develop/reference/protocol-spec#resp-protocol-description" >}}) protocols, so its content varies greatly between calls. A simple example is the status response returned by the [`SET`]({{< relref "/commands/set" >}}) command. The code below shows how to get this from the `redisReply` object: ```c redisReply *reply = redisCommand(c, "SET greeting Hello"); // Check and free the reply. if (reply != NULL) { printf("Reply: %s\n", reply->str); freeReplyObject(reply); reply = NULL; } ``` A null reply indicates an error, so you should always check for this. If an error does occur, then the `redisContext` object will have a non-zero error number in its integer `err` field and a textual description of the error in its `errstr` field. For `SET`, a successful call will simply return an "OK" string that you can access with the `reply->str` field. The code in the example prints this to the console, but you should check for the specific value to ensure the command executed correctly. The `redisCommand()` call allocates memory for the reply, so you should always free it using `freeReplyObject()` when you have finished using the reply. If you want to reuse the reply variable then it is wise to set it to `NULL` after you free it, so that you don't accidentally use the stale pointer later. ## Reply formats The Redis [`RESP`]({{< relref "/develop/reference/protocol-spec#resp-protocol-description" >}}) protocols support several different reply formats for commands. You can find the reply format for a command at the end of its reference page in the RESP2/RESP3 Reply section (for example, the [`INCRBY`]({{< relref "/commands/incrby" >}}) page shows that the command has an integer result). You can also determine the format using the `type` field of the reply object. This contains a different integer value for each type. The `hiredis.h` header file defines constants for all of these integer values (for example `REDIS_REPLY_STRING`). The `redisReply` struct has several fields to contain different types of replies, with different fields being set depending on the value of the `type` field. The table below shows the type constants, the corresponding reply type, and the fields you can use to access the reply value: | Constant | Type | Relevant fields of `redisReply` | RESP protocol | | :- | :- |:- | :- | | `REDIS_REPLY_STATUS` | [Simple string]({{< relref "/develop/reference/protocol-spec#simple-strings" >}}) | `reply->str`: the string value (`char*`)
`reply->len`: the string length (`size_t`) | 2, 3 | | `REDIS_REPLY_ERROR` | [Simple error]({{< relref "/develop/reference/protocol-spec#simple-errors" >}}) | `reply->str`: the string value (`char*`)
`reply->len`: the string length (`size_t`) | 2, 3 | | `REDIS_REPLY_INTEGER` | [Integer]({{< relref "/develop/reference/protocol-spec#integers" >}}) | `reply->integer`: the integer value (`long long`)| 2, 3 | | `REDIS_REPLY_NIL` | [Null]({{< relref "/develop/reference/protocol-spec#nulls" >}}) | No data | 2, 3 | | `REDIS_REPLY_STRING` | [Bulk string]({{< relref "/develop/reference/protocol-spec#bulk-strings" >}}) |`reply->str`: the string value (`char*`)
`reply->len`: the string length (`size_t`) | 2, 3 | | `REDIS_REPLY_ARRAY` | [Array]({{< relref "/develop/reference/protocol-spec#arrays" >}}) | `reply->elements`: number of elements (`size_t`)
`reply->element`: array elements (`redisReply`) | 2, 3 | | `REDIS_REPLY_DOUBLE` | [Double]({{< relref "/develop/reference/protocol-spec#doubles" >}}) | `reply->str`: double value as string (`char*`)
`reply->len`: the string length (`size_t`) | 3 | | `REDIS_REPLY_BOOL` | [Boolean]({{< relref "/develop/reference/protocol-spec#booleans" >}}) | `reply->integer`: the boolean value, 0 or 1 (`long long`) | 3 | | `REDIS_REPLY_MAP` | [Map]({{< relref "/develop/reference/protocol-spec#maps" >}}) | `reply->elements`: number of elements (`size_t`)
`reply->element`: array elements (`redisReply`) | 3 | | `REDIS_REPLY_SET` | [Set]({{< relref "/develop/reference/protocol-spec#sets" >}}) | `reply->elements`: number of elements (`size_t`)
`reply->element`: array elements (`redisReply`) | 3 | | `REDIS_REPLY_PUSH` | [Push]({{< relref "/develop/reference/protocol-spec#pushes" >}}) | `reply->elements`: number of elements (`size_t`)
`reply->element`: array elements (`redisReply`) | 3 | | `REDIS_REPLY_BIGNUM` | [Big number]({{< relref "/develop/reference/protocol-spec#big-numbers" >}}) | `reply->str`: number value as string (`char*`)
`reply->len`: the string length (`size_t`) | 3 | | `REDIS_REPLY_VERB` | [Verbatim string]({{< relref "/develop/reference/protocol-spec#verbatim-strings" >}}) |`reply->str`: the string value (`char*`)
`reply->len`: the string length (`size_t`)
`reply->vtype`: content type (`char[3]`) | 3 | ## Reply format processing examples The sections below explain how to process specific reply types in more detail. ### Integers The `REDIS_REPLY_INTEGER` and `REDIS_REPLY_BOOL` reply types both contain values in `reply->integer`. However, `REDIS_REPLY_BOOL` is rarely used. Even when the command essentially returns a boolean value, the reply is usually reported as an integer. ```c // Add some values to a set. redisReply *reply = redisCommand(c, "SADD items bread milk peas"); if (reply->type == REDIS_REPLY_INTEGER) { // Report status. printf("Integer reply\n"); printf("Number added: %lld\n", reply->integer); // >>> Number added: 3 } freeReplyObject(reply); reply = NULL; reply = redisCommand(c, "SISMEMBER items bread"); // This also gives an integer reply but you should interpret // it as a boolean value. if (reply->type == REDIS_REPLY_INTEGER) { // Respond to boolean integer value. printf("Integer reply\n"); if (reply->integer == 0) { printf("Items set has no member 'bread'\n"); } else { printf("'Bread' is a member of items set\n"); } // >>> 'Bread' is a member of items set } freeReplyObject(reply); reply = NULL; ``` ### Strings The `REDIS_REPLY_STATUS`, `REDIS_REPLY_ERROR`, `REDIS_REPLY_STRING`, `REDIS_REPLY_DOUBLE`, `REDIS_REPLY_BIGNUM`, and `REDIS_REPLY_VERB` are all returned as strings, with the main difference lying in how you interpret them. For all these types, the string value is returned in `reply->str` and the length of the string is in `reply->len`. The example below shows some of the possibilities. ```c // Set a numeric value in a string. reply = redisCommand(c, "SET number 1.5"); // This gives a status reply. if (reply->type == REDIS_REPLY_STATUS) { // Report status. printf("Status reply\n"); printf("Reply: %s\n", reply->str); // >>> Reply: OK } freeReplyObject(reply); reply = NULL; // Attempt to interpret the key as a hash. reply = redisCommand(c, "HGET number field1"); // This gives an error reply. if (reply->type == REDIS_REPLY_ERROR) { // Report the error. printf("Error reply\n"); printf("Reply: %s\n", reply->str); // >>> Reply: WRONGTYPE Operation against a key holding the wrong kind of value } freeReplyObject(reply); reply = NULL; reply = redisCommand(c, "GET number"); // This gives a simple string reply. if (reply->type == REDIS_REPLY_STRING) { // Display the string. printf("Simple string reply\n"); printf("Reply: %s\n", reply->str); // >>> Reply: 1.5 } freeReplyObject(reply); reply = NULL; reply = redisCommand(c, "ZADD prices 1.75 bread 5.99 beer"); // This gives an integer reply. if (reply->type == REDIS_REPLY_INTEGER) { // Display the integer. printf("Integer reply\n"); printf("Number added: %lld\n", reply->integer); // >>> Number added: 2 } freeReplyObject(reply); reply = NULL; reply = redisCommand(c, "ZSCORE prices bread"); // This gives a string reply with RESP2 and a double reply // with RESP3, but you handle it the same way in either case. if (reply->type == REDIS_REPLY_STRING) { printf("String reply\n"); char *endptr; // Not used. double price = strtod(reply->str, &endptr); double discounted = price * 0.75; printf("Discounted price: %.2f\n", discounted); // >>> Discounted price: 1.31 } freeReplyObject(reply); reply = NULL; ``` ### Arrays and maps Arrays (reply type `REDIS_REPLY_ARRAY`) and maps (reply type `REDIS_REPLY_MAP`) are returned by commands that retrieve several values at the same time. For both types, the number of elements in the reply is contained in `reply->elements` and the pointer to the array itself is is `reply->element`. Each item in the array is of type `redisReply`. The array elements are typically simple types rather than arrays or maps. The example below shows how to get the items from a [list]({{< relref "/develop/data-types/lists" >}}): ```c reply = redisCommand(c, "RPUSH things thing0 thing1 thing2 thing3"); printf("Added %lld items\n", reply->integer); // >>> Added 4 items freeReplyObject(reply); reply = NULL; reply = redisCommand(c, "LRANGE things 0 -1"); for (int i = 0; i < reply->elements; ++i) { if (reply->element[i]->type == REDIS_REPLY_STRING) { printf("List item %d: %s\n", i, reply->element[i]->str); } } // >>> List item 0: thing0 // >>> List item 1: thing1 // >>> List item 2: thing2 // >>> List item 3: thing3 ``` A map is essentially the same as an array but it has the extra guarantee that the items will be listed in key-value pairs. The example below shows how to get all the fields from a [hash]({{< relref "/develop/data-types/hashes" >}}) using [`HGETALL`]({{< relref "/commands/hgetall" >}}): ```c const char *hashCommand[] = { "HSET", "details", "name", "Mr Benn", "address", "52 Festive Road", "hobbies", "Cosplay" }; reply = redisCommandArgv(c, 8, hashCommand, NULL); printf("Added %lld fields\n", reply->integer); // >>> Added 3 fields freeReplyObject(reply); reply = NULL; reply = redisCommand(c, "HGETALL details"); // This gives an array reply with RESP2 and a map reply with // RESP3, but you handle it the same way in either case. if (reply->type == REDIS_REPLY_ARRAY) { for (int i = 0; i < reply->elements; i += 2) { char *key = reply->element[i]->str; char *value = reply->element[i + 1]->str; printf("Key: %s, value: %s\n", key, value); } // >>> Key: name, value: Mr Benn // >>> Key: address, value: 52 Festive Road // >>> Key: hobbies, value: Cosplay } ``` ## Handling errors When a command executes successfully, the `err` field of the context object will be set to zero. If a command fails, it will return either `NULL` or `REDIS_ERR`, depending on which function and command you used. When this happens, `context->err` will contain an error code - `REDIS_ERR_IO`: There was an I/O error while creating the connection, or while trying to write or read data. Whenever `context->err` contains `REDIS_ERR_IO`, you can use the features of the standard library file [`errno.h`](https://en.wikipedia.org/wiki/Errno.h) to find out more information about the error. - `REDIS_ERR_EOF`: The server closed the connection which resulted in an empty read. - `REDIS_ERR_PROTOCOL`: There was an error while parsing the [RESP protocol]({{< relref "/develop/reference/protocol-spec" >}}). - `REDIS_ERR_OTHER`: Any other error. Currently, it is only used when the connection hostname can't be resolved. The context object also has an `errstr` field that contains a descriptive error message.