Skip to content

Commit fb0840f

Browse files
DOC-4996 add replies and connect pages
1 parent 5903466 commit fb0840f

File tree

3 files changed

+370
-290
lines changed

3 files changed

+370
-290
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
categories:
3+
- docs
4+
- develop
5+
- stack
6+
- oss
7+
- rs
8+
- rc
9+
- oss
10+
- kubernetes
11+
- clients
12+
description: Connect to the server with `hiredis`.
13+
linkTitle: Connect
14+
title: Connect
15+
weight: 1
16+
---
17+
18+
## Basic synchronous connection
19+
20+
```c
21+
#include <stdio.h>
22+
23+
#include "hiredis.h"
24+
25+
// The `redisContext` type represents the connection
26+
// to the Redis server. Here, we connect to the
27+
// default host and port.
28+
redisContext *c = redisConnect("127.0.0.1", 6379);
29+
30+
// Check if the context is null or if a specific
31+
// error occurred.
32+
if (c == NULL || c->err) {
33+
if (c != NULL) {
34+
printf("Error: %s\n", c->errstr);
35+
// handle error
36+
} else {
37+
printf("Can't allocate redis context\n");
38+
}
39+
}
40+
41+
// Set a string key.
42+
redisReply *reply = redisCommand(c, "SET foo bar");
43+
44+
// Check and free the reply.
45+
if (reply != NULL) {
46+
printf("Reply: %s\n", reply->str); // >>> Reply: OK
47+
freeReplyObject(reply);
48+
}
49+
50+
// Get the key we have just stored.
51+
reply = redisCommand(c, "GET foo");
52+
53+
// Check and free the reply.
54+
if (reply != NULL) {
55+
printf("Reply: %s\n", reply->str); // >>> Reply: bar
56+
freeReplyObject(reply);
57+
}
58+
59+
// Close the connection.
60+
redisFree(c);
61+
```
Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
---
2+
categories:
3+
- docs
4+
- develop
5+
- stack
6+
- oss
7+
- rs
8+
- rc
9+
- oss
10+
- kubernetes
11+
- clients
12+
description: Handle replies with `hiredis`.
13+
linkTitle: Handle replies
14+
title: Handle replies
15+
weight: 10
16+
---
17+
18+
The `redisCommand()` and `redisCommandArgv()` functions return
19+
a pointer to a `redisReply` object when you issue a command (see
20+
[Issue commands]({{< relref "/develop/clients/hiredis/issue-commands" >}})
21+
for more information). This type supports all
22+
reply formats defined in the
23+
[RESP2 and RESP3]({{< relref "/develop/reference/protocol-spec#resp-protocol-description" >}})
24+
protocols, so its content varies greatly between calls.
25+
26+
A simple example is the status response returned by the `SET`
27+
command. The code below shows how to get this from the `redisReply`
28+
object:
29+
30+
```c
31+
redisReply *reply = redisCommand(c, "SET greeting Hello");
32+
33+
// Check and free the reply.
34+
if (reply != NULL) {
35+
printf("Reply: %s\n", reply->str);
36+
freeReplyObject(reply);
37+
reply = NULL;
38+
}
39+
```
40+
41+
A null reply indicates an error, so you should always check for this.
42+
If an error does occur, then the `redisContext` object will have a
43+
non-zero error number in its integer `err` field and sometimes a textual
44+
description of the error in its `errstr` field.
45+
46+
For `SET`, a successful call will simply return an "OK" string that you
47+
can access with the `reply->str` field. The code in the example prints
48+
this to the console, but you should check for the specific value to ensure
49+
the command executed correctly.
50+
51+
The `redisCommand()` call allocates memory for the reply, so you should
52+
always free it using `freeReplyObject()` when you have finished using
53+
the reply. If you want to reuse the reply variable then it is wise to
54+
set it to `NULL` after you free it, so that you don't accidentally use
55+
the stale pointer later.
56+
57+
## Reply formats
58+
59+
The Redis
60+
[`RESP`]({{< relref "/develop/reference/protocol-spec#resp-protocol-description" >}})
61+
protocols support several different types of reply format for commands.
62+
63+
You can find the reply format for a command at the end of its
64+
reference page in the RESP2/RESP3 Reply section (for example, the
65+
[`INCRBY`]({{< relref "/commands/incrby" >}}) page shows that the
66+
command has an integer result). You can also determine the format
67+
using the `type` field of the reply object. This contains a
68+
different integer value for each type, and `hiredis.h` defines
69+
constants for each type (for example `REDIS_REPLY_STRING`).
70+
71+
The `redisReply` struct has several fields to contain different
72+
types of replies, with different fields being set depending on
73+
the value of the `type` field. The table below shows the type
74+
constants, the corresponding reply type, and the fields you can
75+
use to access the reply value:
76+
77+
| Constant | Type | Relevant fields of `redisReply` | RESP protocol |
78+
| :- | :- |:- | :- |
79+
| `REDIS_REPLY_STATUS` | [Simple string]({{< relref "/develop/reference/protocol-spec#simple-strings" >}}) | `reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`) | 2, 3 |
80+
| `REDIS_REPLY_ERROR` | [Simple error]({{< relref "/develop/reference/protocol-spec#simple-errors" >}}) | `reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`) | 2, 3 |
81+
| `REDIS_REPLY_INTEGER` | [Integer]({{< relref "/develop/reference/protocol-spec#integers" >}}) | `reply->integer`: the integer value (`long long`)| 2, 3 |
82+
| `REDIS_REPLY_NIL` | [Null]({{< relref "/develop/reference/protocol-spec#nulls" >}}) | No data | 2, 3 |
83+
| `REDIS_REPLY_STRING` | [Bulk string]({{< relref "/develop/reference/protocol-spec#bulk-strings" >}}) |`reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`) | 2, 3 |
84+
| `REDIS_REPLY_ARRAY` | [Array]({{< relref "/develop/reference/protocol-spec#arrays" >}}) | `reply->elements`: number of elements (`size_t`)<br/> `reply->element`: array elements (`redisReply`) | 2, 3 |
85+
| `REDIS_REPLY_DOUBLE` | [Double]({{< relref "/develop/reference/protocol-spec#doubles" >}}) | `reply->str`: double value as string (`char*`)<br/> `reply->len`: the string length (`size_t`) | 3 |
86+
| `REDIS_REPLY_BOOL` | [Boolean]({{< relref "/develop/reference/protocol-spec#booleans" >}}) | `reply->integer`: the boolean value, 0 or 1 (`long long`) | 3 |
87+
| `REDIS_REPLY_MAP` | [Map]({{< relref "/develop/reference/protocol-spec#maps" >}}) | `reply->elements`: number of elements (`size_t`)<br/> `reply->element`: array elements (`redisReply`) | 3 |
88+
| `REDIS_REPLY_SET` | [Set]({{< relref "/develop/reference/protocol-spec#sets" >}}) | `reply->elements`: number of elements (`size_t`)<br/> `reply->element`: array elements (`redisReply`) | 3 |
89+
| `REDIS_REPLY_PUSH` | [Push]({{< relref "/develop/reference/protocol-spec#pushes" >}}) | `reply->elements`: number of elements (`size_t`)<br/> `reply->element`: array elements (`redisReply`) | 3 |
90+
| `REDIS_REPLY_BIGNUM` | [Big number]({{< relref "/develop/reference/protocol-spec#big-numbers" >}}) | `reply->str`: number value as string (`char*`)<br/> `reply->len`: the string length (`size_t`) | 3 |
91+
| `REDIS_REPLY_VERB` | [Verbatim string]({{< relref "/develop/reference/protocol-spec#verbatim-strings" >}}) |`reply->str`: the string value (`char*`)<br/> `reply->len`: the string length (`size_t`)<br/> `reply->vtype`: content type (`char[3]`) | 3 |
92+
93+
## Reply format processing examples
94+
95+
The sections below explain how to process specific reply types in
96+
more detail.
97+
98+
### Integers
99+
100+
The `REDIS_REPLY_INTEGER` and `REDIS_REPLY_BOOL` reply types both
101+
contain values in `reply->integer`. However, `REDIS_REPLY_BOOL` is
102+
rarely used. Even when the command essentially returns a boolean value,
103+
the reply is usually reported as an integer.
104+
105+
```c
106+
// Add some values to a set.
107+
redisReply *reply = redisCommand(c, "SADD items bread milk peas");
108+
109+
if (reply != NULL) {
110+
// This gives an integer reply.
111+
if (reply->type == REDIS_REPLY_INTEGER) {
112+
// Report status.
113+
printf("Integer reply\n");
114+
printf("Number added: %lld\n", reply->integer);
115+
// >>> Number added: 3
116+
}
117+
118+
freeReplyObject(reply);
119+
reply = NULL;
120+
}
121+
122+
reply = redisCommand(c, "SISMEMBER items bread");
123+
124+
if (reply != NULL) {
125+
// This also gives an integer reply but you should interpret
126+
// it as a boolean value.
127+
if (reply->type == REDIS_REPLY_INTEGER) {
128+
// Respond to boolean integer value.
129+
printf("Integer reply\n");
130+
131+
if (reply->integer == 0) {
132+
printf("Items set has no member 'bread'\n");
133+
} else {
134+
printf("'Bread' is a member of items set\n");
135+
}
136+
// >>> 'Bread' is a member of items set
137+
}
138+
139+
freeReplyObject(reply);
140+
reply = NULL;
141+
}
142+
```
143+
144+
### Strings
145+
146+
The `REDIS_REPLY_STATUS`, `REDIS_REPLY_ERROR`, `REDIS_REPLY_STRING`,
147+
`REDIS_REPLY_DOUBLE`, `REDIS_REPLY_BIGNUM`, and `REDIS_REPLY_VERB`
148+
are all returned as strings, with the main difference lying in how
149+
you interpret them. For all these types, the string value is
150+
returned in `reply->str` and the length of the string is in
151+
`reply->len`. The example below shows some of the possibilities.
152+
153+
```c
154+
// Set a numeric value in a string.
155+
reply = redisCommand(c, "SET number 1.5");
156+
157+
if (reply != NULL) {
158+
// This gives a status reply.
159+
if (reply->type == REDIS_REPLY_STATUS) {
160+
// Report status.
161+
printf("Status reply\n");
162+
printf("Reply: %s\n", reply->str); // >>> Reply: OK
163+
}
164+
165+
freeReplyObject(reply);
166+
reply = NULL;
167+
}
168+
169+
// Attempt to interpret the key as a hash.
170+
reply = redisCommand(c, "HGET number field1");
171+
172+
if (reply != NULL) {
173+
// This gives an error reply.
174+
if (reply->type == REDIS_REPLY_ERROR) {
175+
// Report the error.
176+
printf("Error reply\n");
177+
printf("Reply: %s\n", reply->str);
178+
// >>> Reply: WRONGTYPE Operation against a key holding the wrong kind of value
179+
}
180+
181+
freeReplyObject(reply);
182+
reply = NULL;
183+
}
184+
185+
reply = redisCommand(c, "GET number");
186+
187+
if (reply != NULL) {
188+
// This gives a simple string reply.
189+
if (reply->type == REDIS_REPLY_STRING) {
190+
// Display the string.
191+
printf("Simple string reply\n");
192+
printf("Reply: %s\n", reply->str); // >>> Reply: 1.5
193+
}
194+
195+
freeReplyObject(reply);
196+
reply = NULL;
197+
}
198+
199+
reply = redisCommand(c, "ZADD prices 1.75 bread 5.99 beer");
200+
201+
if (reply != NULL) {
202+
// This gives an integer reply.
203+
if (reply->type == REDIS_REPLY_INTEGER) {
204+
// Display the integer.
205+
printf("Integer reply\n");
206+
printf("Number added: %lld\n", reply->integer);
207+
// >>> Number added: 2
208+
}
209+
210+
freeReplyObject(reply);
211+
reply = NULL;
212+
}
213+
214+
reply = redisCommand(c, "ZSCORE prices bread");
215+
216+
if (reply != NULL) {
217+
// This gives a string reply with RESP2 and a double reply
218+
// with RESP3, but you handle it the same way in either case.
219+
if (reply->type == REDIS_REPLY_STRING) {
220+
printf("String reply\n");
221+
222+
char *endptr; // Not used.
223+
double price = strtod(reply->str, &endptr);
224+
double discounted = price * 0.75;
225+
printf("Discounted price: %.2f\n", discounted);
226+
// >>> Discounted price: 1.31
227+
}
228+
229+
freeReplyObject(reply);
230+
reply = NULL;
231+
}
232+
```
233+
234+
### Arrays and maps
235+
236+
Arrays (reply type `REDIS_REPLY_ARRAY`) and maps (reply type `REDIS_REPLY_MAP`)
237+
are returned by commands that retrieve several values at the
238+
same time. For both types, the number of elements in the reply is contained in
239+
`reply->elements` and the pointer to the array itself is is `reply->element`.
240+
Each item in the array is of type `redisReply`. The array elements
241+
are typically simple types rather than arrays or maps.
242+
243+
The example below shows how to get the items from a
244+
[list]({{< relref "/develop/data-types/lists" >}}):
245+
246+
```c
247+
reply = redisCommand(c, "RPUSH things thing0 thing1 thing2 thing3");
248+
249+
if (reply != NULL) {
250+
printf("Added %lld items\n", reply->integer);
251+
// >>> Added 4 items
252+
freeReplyObject(reply);
253+
reply = NULL;
254+
}
255+
256+
reply = redisCommand(c, "LRANGE things 0 -1");
257+
258+
if (reply != NULL) {
259+
for (int i = 0; i < reply->elements; ++i) {
260+
if (reply->element[i]->type == REDIS_REPLY_STRING) {
261+
printf("List item %d: %s\n", i, reply->element[i]->str);
262+
}
263+
}
264+
// >>> List item 0: thing0
265+
// >>> List item 1: thing1
266+
// >>> List item 2: thing2
267+
// >>> List item 3: thing3
268+
}
269+
```
270+
271+
A map is essentially the same as an array but it has the extra
272+
guarantee that the items will be listed in key-value pairs.
273+
The example below shows how to get all the fields from a
274+
[hash]({{< relref "/develop/data-types/hashes" >}}) using
275+
[`HGETALL`]({{< relref "/commands/hgetall" >}}):
276+
277+
```c
278+
const char *hashCommand[] = {
279+
"HSET", "details",
280+
"name", "Mr Benn",
281+
"address", "52 Festive Road",
282+
"hobbies", "Cosplay"
283+
};
284+
285+
reply = redisCommandArgv(c, 8, hashCommand, NULL);
286+
287+
if (reply != NULL) {
288+
printf("Added %lld fields\n", reply->integer);
289+
// >>> Added 3 fields
290+
291+
freeReplyObject(reply);
292+
reply = NULL;
293+
}
294+
295+
reply = redisCommand(c, "HGETALL details");
296+
297+
// This gives an array reply with RESP2 and a map reply with
298+
// RESP3, but you handle it the same way in either case.
299+
if (reply->type == REDIS_REPLY_ARRAY) {
300+
for (int i = 0; i < reply->elements; i += 2) {
301+
char *key = reply->element[i]->str;
302+
char *value = reply->element[i + 1]->str;
303+
printf("Key: %s, value: %s\n", key, value);
304+
}
305+
// >>> Key: name, value: Mr Benn
306+
// >>> Key: address, value: 52 Festive Road
307+
// >>> Key: hobbies, value: Cosplay
308+
}
309+
```

0 commit comments

Comments
 (0)