mirror of https://github.com/vapor/docs.git
update redis docs
This commit is contained in:
parent
16483f71bc
commit
025b1c7db2
|
|
@ -1,100 +0,0 @@
|
|||
# Redis basic usage
|
||||
|
||||
To interact with Redis, you first need to construct a Redis client.
|
||||
The Redis library primarily supports TCP sockets.
|
||||
|
||||
This requires a hostname, port and worker. The eventloop will be used for Redis' Socket. The hostname and port have a default. The hostname is defaulted to `localhost`, and the port to Redis' default port `6379`.
|
||||
|
||||
```swift
|
||||
let client = try RedisClient.connect(on: worker) // Future<RedisClient>
|
||||
```
|
||||
|
||||
The `connect` method will return a future containing the TCP based Redis Client.
|
||||
|
||||
## Redis Data Types
|
||||
|
||||
Redis has 6 data types:
|
||||
|
||||
- null
|
||||
- Int
|
||||
- Error
|
||||
- Array
|
||||
- Basic String (used for command names and basic replies only)
|
||||
- Bulk String (used for Strings and binary data blobs)
|
||||
|
||||
You can instantiate one from the static functions and variables on `RedisData`.
|
||||
|
||||
```swift
|
||||
let null = RedisData.null
|
||||
|
||||
let helloWorld = RedisData.bulkString("Hello World")
|
||||
|
||||
let three = RedisData.integer(3)
|
||||
|
||||
let oneThroughTen = RedisData.array([
|
||||
.integer(1),
|
||||
.integer(2),
|
||||
.integer(3),
|
||||
.integer(4),
|
||||
.integer(5),
|
||||
.integer(6),
|
||||
.integer(7),
|
||||
.integer(8),
|
||||
.integer(9),
|
||||
.integer(10)
|
||||
])
|
||||
```
|
||||
|
||||
The above is the explicit way of defining Redis Types. You can also use literals in most scenarios:
|
||||
|
||||
```swift
|
||||
let array = RedisData.array([
|
||||
[
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
|
||||
],
|
||||
"Hello World",
|
||||
"One",
|
||||
"Two",
|
||||
.null,
|
||||
.null,
|
||||
"test"
|
||||
])
|
||||
```
|
||||
|
||||
## CRUD using Redis
|
||||
|
||||
From here on it is assumed that your client has been successfully created and is available in the variable `client` as a `RedisClient`.
|
||||
|
||||
### Creating a record
|
||||
|
||||
Creating a record is done using a `RedisData` for a value and a key.
|
||||
|
||||
```swift
|
||||
client.set("world", forKey: "hello")
|
||||
```
|
||||
|
||||
This returns a future that'll indicate successful or unsuccessful insertion.
|
||||
|
||||
### Reading a record
|
||||
|
||||
Reading a record is similar, only you'll get a warning if you don't use the returned future.
|
||||
|
||||
The `Future<RedisData>` for the key "hello" will be "world" if you created the record as shown above.
|
||||
|
||||
```swift
|
||||
let futureRecord = client.getData(forKey: "hello") // Future<RedisData>
|
||||
```
|
||||
|
||||
### Deleting a record
|
||||
|
||||
Deleting a record is similar but allows querying the keys, too.
|
||||
|
||||
```swift
|
||||
client.delete(keys: ["hello"])
|
||||
```
|
||||
|
||||
Where the above command will remove the key "hello", the next command will delete **all** keys from the Redis database.
|
||||
|
||||
```swift
|
||||
client.delete(keys: ["*"])
|
||||
```
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# Custom commands
|
||||
|
||||
Many commands are not (yet) implemented by the driver using a convenience function. This does not mean the feature/command is not usable.
|
||||
|
||||
[(Almost) all functions listed here](https://redis.io/commands) work out of the box using custom commands.
|
||||
|
||||
## Usage
|
||||
|
||||
The Redis client has a `run` function that allows you to run these commands.
|
||||
|
||||
The following code demonstrates a "custom" implementation for [GET](https://redis.io/commands/get).
|
||||
|
||||
```swift
|
||||
let future = client.run(command: "GET", arguments: ["my-key"]) // Future<RedisData>
|
||||
```
|
||||
|
||||
This future will contain the result as specified in the article on the redis command page or an error.
|
||||
|
|
@ -1,36 +1,68 @@
|
|||
!!! warning
|
||||
Redis 3.0 is still in beta. Some documentation may be missing or out of date.
|
||||
# Getting Started with Redis
|
||||
|
||||
# Redis
|
||||
Redis ([vapor/redis](https://github.com/vapor/redis)) is a pure-Swift, event-driven, non-blocking Redis client built on top of SwiftNIO.
|
||||
|
||||
Redis is a Redis client library that can communicate with a Redis database.
|
||||
You can use this package to interact send Redis commands to your server directly, or as a cache through Vapor's `KeyedCache` interface.
|
||||
|
||||
### What is Redis?
|
||||
Let's take a look at how you can get started using Redis.
|
||||
|
||||
Redis is an in-memory data store used as a database, cache and message broker. It supports most common data structures. Redis is most commonly used for caching data such as sessions and notifications (between multiple servers).
|
||||
## Package
|
||||
|
||||
Redis works as a key-value store, but allows querying the keys, unlike most databases.
|
||||
|
||||
## With and without Vapor
|
||||
|
||||
To include it in your package, add the following to your `Package.swift` file.
|
||||
The first step to using Redis is adding it as a dependency to your project in your SPM package manifest file.
|
||||
|
||||
```swift
|
||||
// swift-tools-version:4.0
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "Project",
|
||||
name: "MyApp",
|
||||
dependencies: [
|
||||
...
|
||||
.package(url: "https://github.com/vapor/redis.git", .upToNextMajor(from: "3.0.0")),
|
||||
/// Any other dependencies ...
|
||||
|
||||
// ⚡️Non-blocking, event-driven Redis client.
|
||||
.package(url: "https://github.com/vapor/redis.git", from: "3.0.0"),
|
||||
],
|
||||
targets: [
|
||||
.target(name: "Project", dependencies: ["Redis", ... ])
|
||||
.target(name: "App", dependencies: ["Redis", ...]),
|
||||
.target(name: "Run", dependencies: ["App"]),
|
||||
.testTarget(name: "AppTests", dependencies: ["App"]),
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
If this is your first time adding a dependency, you should read our introduction to [Package.swift](../getting-started/spm.md).
|
||||
## Provider
|
||||
|
||||
Once you have succesfully added the Auth package to your project, the next step is to configure it in your application. This is usually done in [`configure.swift`](../getting-started/structure.md#configureswift).
|
||||
|
||||
```swift
|
||||
import Redis
|
||||
|
||||
// register Redis provider
|
||||
try services.register(RedisProvider())
|
||||
```
|
||||
|
||||
That's it for basic setup. The next step is to create a Redis connection and send a command.
|
||||
|
||||
## Command
|
||||
|
||||
First, create a new connection to your Redis database. This package is built on top of DatabaseKit, so you can use any of its convenience methods for creating a new connection. See [DatabaseKit → Overview](../database-kit/overview.md) for more information.
|
||||
|
||||
```swift
|
||||
router.get("redis") { req -> Future<String> in
|
||||
return req.withNewConnection(to: .redis) { redis in
|
||||
// use redis connection
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Once you have a connection, you can use it to send a command. Let's send the `"INFO"` command which should return information about our Redis server.
|
||||
|
||||
```swift
|
||||
// send INFO command to redis
|
||||
return redis.command("INFO")
|
||||
// map the resulting RedisData to a String
|
||||
.map { $0.string ?? "" }
|
||||
```
|
||||
|
||||
Run your app and query `GET /redis`. You should see information about your Redis server printed as output. Congratulations!
|
||||
|
||||
Use `import Redis` to access Redis' APIs.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
# Using Redis
|
||||
|
||||
Redis ([vapor/redis](https://github.com/vapor/redis)) is a pure-Swift, event-driven, non-blocking Redis client built on top of SwiftNIO.
|
||||
|
||||
You can use this package to interact send Redis commands to your server directly, or as a cache through Vapor's `KeyedCache` interface.
|
||||
|
||||
## Redis Commands
|
||||
|
||||
Let's take a look at how to send and recieve data using Redis commands.
|
||||
|
||||
### Connection
|
||||
|
||||
The first thing you will need to send a Redis command is a connection. This package is built on top of DatabaseKit, so you can use any of its convenience methods for creating a new connection.
|
||||
|
||||
For this example, we will use the `withNewConnection(to:)` method to create a new connection to Redis.
|
||||
|
||||
```swift
|
||||
router.get("redis") { req -> Future<String> in
|
||||
return req.withNewConnection(to: .redis) { redis in
|
||||
// use redis connection
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See [DatabaseKit → Overview](../database-kit/overview.md) for more information.
|
||||
|
||||
### Available Commands
|
||||
|
||||
See [`RedisClient`](https://api.vapor.codes/redis/latest/Redis/Classes/RedisClient.html) for a list of all available commands. Here we'll take a look at some common commands.
|
||||
|
||||
#### Get / Set
|
||||
|
||||
Redis's `GET` and `SET` commands allow you to store and later retrieve data from the server. You can pass any `Codable` type as the value to this command.
|
||||
|
||||
```swift
|
||||
router.get("set") { req -> Future<HTTPStatus> in
|
||||
// create a new redis connection
|
||||
return req.withNewConnection(to: .redis) { redis in
|
||||
// save a new key/value pair to the cache
|
||||
return redis.set("hello", to: "world")
|
||||
// convert void future to HTTPStatus.ok
|
||||
.transform(to: .ok)
|
||||
}
|
||||
}
|
||||
|
||||
router.get("get") { req -> Future<String> in
|
||||
// create a new redis connection
|
||||
return req.withNewConnection(to: .redis) { redis in
|
||||
// fetch the key/value pair from the cache, decoding a String
|
||||
return redis.get("hello", as: String.self)
|
||||
// handle nil case
|
||||
.map { $0 ?? "" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Delete
|
||||
|
||||
Redis's `DELETE` command allows you to clear a previously stored key/value pair.
|
||||
|
||||
```swift
|
||||
router.get("del") { req -> Future<HTTPStatus> in
|
||||
// create a new redis connection
|
||||
return req.withNewConnection(to: .redis) { redis in
|
||||
// fetch the key/value pair from the cache, decoding a String
|
||||
return redis.delete("hello")
|
||||
// convert void future to HTTPStatus.ok
|
||||
.transform(to: .ok)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See [`RedisClient`](https://api.vapor.codes/redis/latest/Redis/Classes/RedisClient.html) for a list of all available commands.
|
||||
|
||||
## Keyed Cache
|
||||
|
||||
You can also use Redis as the backend to Vapor's [`KeyedCache`](https://api.vapor.codes/database-kit/latest/DatabaseKit/Protocols/KeyedCache.html) protocol.
|
||||
|
||||
```swift
|
||||
router.get("set") { req -> Future<HTTPStatus> in
|
||||
let string = try req.query.get(String.self, at: "string")
|
||||
return try req.keyedCache(for: .redis).set("string", to: string)
|
||||
.transform(to: .ok)
|
||||
}
|
||||
|
||||
router.get("get") { req -> Future<String> in
|
||||
return try req.keyedCache(for: .redis).get("string", as: String.self)
|
||||
.unwrap(or: Abort(.badRequest, reason: "No string set yet."))
|
||||
}
|
||||
```
|
||||
|
||||
See [DatabaseKit → Overview](../database-kit/overview/#keyed-cache) for more information.
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# Pipelining
|
||||
|
||||
Pipelining is used for sending multiple commands at once. The performance advantages become apparent when sending a large number of queries. Redis' pipelining cuts down latency by reducing the RTT (Round Trip Time) between the client and server. Pipelining also reduces the amount of IO operations Redis has to perform, this increases the amount of queries per second Redis can handle.
|
||||
|
||||
### Use cases
|
||||
Sometimes multiple commands need to be executed at once. Instead of sending those commands individually in a loop, pipelining allows the commands to be batched and sent in one request. A common scenario might be needing to set a key and increment a count, pipelining those commands would be ideal.
|
||||
|
||||
### Enqueuing Commands
|
||||
|
||||
```swift
|
||||
let pipeline = connection.makePipeline()
|
||||
let result = try pipeline
|
||||
.enqueue(command: "SET", arguments: ["KEY", "VALUE"])
|
||||
.enqueue(command: "INCR", arguments: ["COUNT"])
|
||||
.execute() // Future<[RedisData]>
|
||||
|
||||
```
|
||||
Note: Commands will not be executed until execute is called.
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
# Publish & Subscribe
|
||||
|
||||
Redis' Publish and Subscribe model is really useful for notifications.
|
||||
|
||||
### Use cases
|
||||
|
||||
Pub/sub is used for notifying subscribers of an event.
|
||||
A simple and common event for example would be a chat message.
|
||||
|
||||
A channel consists of a name and group of listeners. Think of it as being `[String: [Listener]]`.
|
||||
When you send a notification to a channel you need to provide a payload.
|
||||
Each listener will get a notification consisting of this payload.
|
||||
|
||||
Channels must be a string. For chat groups, for example, you could use the database identifier.
|
||||
|
||||
### Publishing
|
||||
|
||||
You cannot get a list of listeners, but sending a payload will emit the amount of listeners that received the notification.
|
||||
Sending (publishing) an event is done like so:
|
||||
|
||||
```swift
|
||||
// Any redis data
|
||||
let notification: RedisData = "My-Notification"
|
||||
|
||||
client.publish(notification, to: "my-channel")
|
||||
```
|
||||
|
||||
If you want access to the listener count:
|
||||
|
||||
```swift
|
||||
let notifiedCount = client.publish(notification, to: "my-channel") // Future<Int>
|
||||
```
|
||||
|
||||
### Subscribing
|
||||
|
||||
To subscribe for notifications you're rendering an entire Redis Client useless in exchange for listening to events.
|
||||
|
||||
A single client can listen to one or more channels, which is provided using a set of unique channel names. The result of subscribing is a `SubscriptionStream`.
|
||||
|
||||
```swift
|
||||
let notifications = client.subscribe(to: ["some-notification-channel", "other-notification-channel"])
|
||||
```
|
||||
|
||||
If you try to use the client after subscribing, all operations will fail. These errors are usually emitted through the Future.
|
||||
|
||||
This stream will receive messages asynchronously from the point of `draining`. This works like any other async stream.
|
||||
|
||||
Notifications consist of the channel and payload.
|
||||
|
||||
```swift
|
||||
notifications.drain { notification in
|
||||
print(notification.channel)
|
||||
|
||||
let payload = notification.payload
|
||||
|
||||
// TODO: Process the payload
|
||||
}
|
||||
```
|
||||
|
|
@ -74,10 +74,7 @@ pages:
|
|||
- 'Getting Started': 'postgresql/getting-started.md'
|
||||
- 'Redis':
|
||||
- 'Getting Started': 'redis/getting-started.md'
|
||||
- 'Basics': 'redis/basics.md'
|
||||
- 'Custom commands': 'redis/custom-commands.md'
|
||||
- 'Publish and Subscribe': 'redis/pub-sub.md'
|
||||
- 'Pipeline': 'redis/pipeline.md'
|
||||
- 'Overview': 'redis/overview.md'
|
||||
- 'Routing':
|
||||
- 'Getting Started': 'routing/getting-started.md'
|
||||
- 'Overview': 'routing/overview.md'
|
||||
|
|
|
|||
Loading…
Reference in New Issue