Skip to content

Commit

Permalink
Merge pull request #986 from itowlson/api-guides-to-v2
Browse files Browse the repository at this point in the history
Update API guides to v2
  • Loading branch information
itowlson authored Oct 31, 2023
2 parents 34d4fa1 + ed4b400 commit b4c3dfe
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 86 deletions.
24 changes: 12 additions & 12 deletions content/spin/v2/api-guides-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ url = "https://github.com/fermyon/developer/blob/main/content/spin/v2/api-guides

The following table shows the status of the interfaces Spin provides to applications.

| Host Capabilities/Interfaces | Stability | Cloud |
|----------------------------------------|----------|-------|
| [HTTP Trigger](./http-trigger) | Stable | Yes |
| [Redis Trigger](./redis-trigger) | Stable | No |
| [Outbound HTTP](./http-outbound) | Stable | Yes |
| [Outbound Redis](./redis-outbound) | Stable | Yes |
| [Configuration Variables](./variables) | Stable | Yes |
| [PostgreSQL](./rdbms-storage) | Experimental | Yes |
| [MySQL](./rdbms-storage) | Experimental | Yes |
| [Key-value Storage](./kv-store-api-guide) | Stabilizing | Yes |
| [Serverless AI](./serverless-ai-api-guide) | Experimental | [Private Beta](/cloud/serverless-ai.md) |
| [SQLite Storage](./sqlite-api-guide) | Experimental | Yes |
| Host Capabilities/Interfaces | Stability | Cloud |
|----------------------------------------------|--------------|---------|
| [HTTP Trigger](./http-trigger) | Stable | Yes |
| [Redis Trigger](./redis-trigger) | Stable | No |
| [Outbound HTTP](./http-outbound) | Stable | Yes |
| [Outbound Redis](./redis-outbound) | Stable | Yes |
| [Configuration Variables](./variables) | Stable | Yes |
| [PostgreSQL](./rdbms-storage) | Experimental | Yes |
| [MySQL](./rdbms-storage) | Experimental | Yes |
| [Key-value Storage](./kv-store-api-guide) | Stabilizing | Yes |
| [Serverless AI](./serverless-ai-api-guide) | Experimental | [Private Beta](/cloud/serverless-ai.md) |
| [SQLite Storage](./sqlite-api-guide) | Experimental | Yes |

For more information about what is possible in the programming language of your choice, please see our [Language Support Overview](./language-support-overview).
4 changes: 2 additions & 2 deletions content/spin/v2/http-outbound.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The outbound HTTP interface depends on your language.

To send requests, use the [`spin_sdk::http::send`](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/http/fn.send.html) function. This takes a request argument and returns a response (or error). It is `async`, so within an async inbound handler you can have multiple outbound `send`s running concurrently.

> The Rust SDK includes **experimental** support for streaming request and response bodies. We currently recommend that you stick with the simpler non-streaming interfaces if you don't require streaming.
> Support for streaming request and response bodies is **experimental**. We currently recommend that you stick with the simpler non-streaming interfaces if you don't require streaming.
`send` is quite flexible in its request and response types. The request may be:

Expand Down Expand Up @@ -119,7 +119,7 @@ You can find a complete example for using outbound HTTP in the [Python SDK repos

{{ startTab "TinyGo"}}

HTTP functions are available in the `github.com/fermyon/spin/sdk/go/v2/http` package. [See Go Packages for reference documentation.](https://pkg.go.dev/github.com/fermyon/spin/sdk/go/v2/http). The general function is named `Send`, but the Go SDK also surfaces individual functions, with request-specific parameters, for the `Get` and `Post` operations. For example:
HTTP functions are available in the `github.com/fermyon/spin/sdk/go/v2/http` package. [See Go Packages for reference documentation.](https://pkg.go.dev/github.com/fermyon/spin/sdk/go/v2/http) The general function is named `Send`, but the Go SDK also surfaces individual functions, with request-specific parameters, for the `Get` and `Post` operations. For example:

```go
import (
Expand Down
9 changes: 5 additions & 4 deletions content/spin/v2/kv-store-api-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,17 @@ Key value functions are available in the `spin_sdk::key_value` module. The funct
```rust
use anyhow::Result;
use spin_sdk::{
http::{Request, Response},
http::{IntoResponse, Request},
http_component,
key_value::{Store},
};
#[http_component]
fn handle_request(_req: Request) -> Result<Response> {
fn handle_request(_req: Request) -> Result<impl IntoResponse> {
let store = Store::open_default()?;
store.set("mykey", "myvalue")?;
let value = store.get("mykey")?;
Ok(http::Response::builder().status(200).body(Some(value.into()))?)
let response = value.unwrap_or_else(|| "not found".into());
Ok(http::Response::builder().status(200).body(response)?)
}
```

Expand Down Expand Up @@ -136,7 +137,7 @@ def handle_request(request):
{{ startTab "TinyGo"}}
Key value functions are provided by the `github.com/fermyon/spin/sdk/go/v2/kv` module. [See Go Packages for reference documentation.](https://pkg.go.dev/github.com/fermyon/spin/sdk/go/v2/kv). For example:
Key value functions are provided by the `github.com/fermyon/spin/sdk/go/v2/kv` module. [See Go Packages for reference documentation.](https://pkg.go.dev/github.com/fermyon/spin/sdk/go/v2/kv) For example:
```go
import "github.com/fermyon/spin/sdk/go/v2/kv"
Expand Down
88 changes: 81 additions & 7 deletions content/spin/v2/rdbms-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ url = "https://github.com/fermyon/developer/blob/main/content/spin/v2/rdbms-stor

---
- [Using MySQL and PostgreSQL From Applications](#using-mysql-and-postgresql-from-applications)
- [Granting Network Permissions to Components](#granting-network-permissions-to-components)

Spin provides two interfaces for relational (SQL) databases:

Expand All @@ -21,10 +22,11 @@ This page covers the "bring your own database" scenario. See [SQLite Storage](.

The Spin SDK surfaces the Spin MySQL and PostgreSQL interfaces to your language. The set of operations is the same across both databases:

| Operation | Parameters | Returns | Behavior |
|------------|-------------------------------------|---------------------|----------|
| `query` | address, statement, SQL parameters | database records | Runs the specified statement against the database, returning the query results as a set of rows. |
| `execute` | address, statement, SQL parameters | integer (not MySQL) | Runs the specified statement against the database, returning the number of rows modified by the statement. (MySQL does not return the modified row count.) |
| Operation | Parameters | Returns | Behavior |
|------------|----------------------------|---------------------|----------|
| `open` | address | connection resource | Opens a connection to the specified database. The host must be listed in `allowed_outbound_hosts`. Other operations must be called through a connection. |
| `query` | statement, SQL parameters | database records | Runs the specified statement against the database, returning the query results as a set of rows. |
| `execute` | statement, SQL parameters | integer (not MySQL) | Runs the specified statement against the database, returning the number of rows modified by the statement. (MySQL does not return the modified row count.) |

The exact detail of calling these operations from your application depends on your language:

Expand All @@ -35,10 +37,12 @@ The exact detail of calling these operations from your application depends on yo
MySQL functions are available in the `spin_sdk::mysql` module, and PostgreSQL functions in the `spin_sdk::pg` module. The function names match the operations above. This example shows MySQL:

```rust
use spin_sdk::mysql::{self, Decode, ParameterValue};
use spin_sdk::mysql::{self, Connection, Decode, ParameterValue};

let connection = Connection::open(&address)?;

let params = vec![ParameterValue::Int32(id)];
let rowset = mysql::query(&address, "SELECT id, name FROM pets WHERE id = ?", &params)?;
let rowset = connection.query("SELECT id, name FROM pets WHERE id = ?", &params)?;

match rowset.rows.first() {
None => /* no rows matched query */,
Expand All @@ -58,6 +62,8 @@ match rowset.rows.first() {

You can find complete examples for using relational databases in the Spin repository on GitHub ([MySQL](https://github.com/fermyon/spin/tree/main/examples/rust-outbound-mysql), [PostgreSQL](https://github.com/fermyon/spin/tree/main/examples/rust-outbound-pg)).

For full information about the MySQL and PostgreSQL APIs, see [the Spin SDK reference documentation](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/index.html).

{{ blockEnd }}

{{ startTab "TypeScript"}}
Expand All @@ -74,8 +80,76 @@ The Python SDK doesn't currently surface the MySQL or PostgreSQL APIs.

{{ startTab "TinyGo"}}

The Go SDK doesn't currently surface the MySQL or PostgreSQL APIs.
MySQL functions are available in the `github.com/fermyon/spin/sdk/go/v2/mysql` package, and PostgreSQL in `github.com/fermyon/spin/sdk/go/v2/pg`. [See Go Packages for reference documentation.](https://pkg.go.dev/github.com/fermyon/spin/sdk/go/v2)

The package follows the usual Go database API. Use `Open` to return a connection to the database of type `*sql.DB` - see the [Go standard library documentation](https://pkg.go.dev/database/sql#DB) for usage information. For example:

```go
package main

import (
"encoding/json"
"fmt"
"net/http"
"os"

spinhttp "github.com/fermyon/spin/sdk/go/v2/http"
"github.com/fermyon/spin/sdk/go/v2/pg"
)

type Pet struct {
ID int64
Name string
Prey *string // nullable field must be a pointer
IsFinicky bool
}

func init() {
spinhttp.Handle(func(w http.ResponseWriter, r *http.Request) {

// addr is the environment variable set in `spin.toml` that points to the
// address of the Mysql server.
addr := os.Getenv("DB_URL")

db := pg.Open(addr)
defer db.Close()

_, err := db.Query("INSERT INTO pets VALUES ($1, 'Maya', $2, $3);", int32(4), "bananas", true)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

rows, err := db.Query("SELECT * FROM pets")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

var pets []*Pet
for rows.Next() {
var pet Pet
if err := rows.Scan(&pet.ID, &pet.Name, &pet.Prey, &pet.IsFinicky); err != nil {
fmt.Println(err)
}
pets = append(pets, &pet)
}
json.NewEncoder(w).Encode(pets)
})
}

func main() {}
```

{{ blockEnd }}

{{ blockEnd }}

## Granting Network Permissions to Components

By default, Spin components are not allowed to make outgoing network requests, including MySQL or PostgreSQL. This follows the general Wasm rule that modules must be explicitly granted capabilities, which is important to sandboxing. To grant a component permission to make network requests to a particular host, use the `allowed_outbound_hosts` field in the component manifest, specifying the host and allowed port:

```toml
[component.uses-db]
allowed_outbound_hosts = ["postgres.example.com:5432"]
```
52 changes: 31 additions & 21 deletions content/spin/v2/redis-outbound.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,49 @@ Spin provides an interface for you to read and write the Redis key/value store,

The Spin SDK surfaces the Spin Redis interface to your language. The set of operations is common across all SDKs:

| Operation | Parameters | Returns | Behavior |
|------------|------------|---------|----------|
| Operation | Parameters | Returns | Behavior |
|--------------|---------------------|---------|----------|
| `open` | address | connection resource | Opens a connection to the specified Redis instance. The host must be listed in `allowed_outbound_hosts`. Other operations must be called through a connection. (Exception: for JavaScript and Python, do not call `open`, and pass the address to each data operation - see the language guides below.) |
| Single value operations |
| `get` | address, key | bytes | Returns the value of `key`. If the key does not exist, returns a zero-length array. |
| `set` | address, key, bytes | - | Sets the value of `key`, overwriting any existing value. |
| `incr` | address, key | integer | Increments the value at `key` by 1. If the key does not exist, its value is set to 0 first (and immediately incremented to 1). If the current value isn't an integer, or a string that represents an integer, it errors and the value is not changed. |
| `del` | address, list of keys | - | Removes the specified keys. Keys that don't exist are ignored (they do _not_ cause an error). |
| `get` | key | bytes | Returns the value of `key`. If the key does not exist, returns a zero-length array. |
| `set` | key, bytes | - | Sets the value of `key`, overwriting any existing value. |
| `incr` | key | integer | Increments the value at `key` by 1. If the key does not exist, its value is set to 0 first (and immediately incremented to 1). If the current value isn't an integer, or a string that represents an integer, it errors and the value is not changed. |
| `del` | list of keys | - | Removes the specified keys. Keys that don't exist are ignored (they do _not_ cause an error). |
| Set value operations |
| `sadd` | address, key, list of strings | integer | Adds the strings to the set of values of `key`, and returns the number of newly added values. If the key does not exist, its value is set to the set of values |
| `smembers` | address, key | list of strings | Returns the set of values of `key`. if the key does not exist, this is an empty set. |
| `srem` | address, key, list of strings | integer | Removes the strings from the set of values of `key`, and returns the number of newly removed values. If the key does not exist, this does nothing. |
| `sadd` | key, list of strings | integer | Adds the strings to the set of values of `key`, and returns the number of newly added values. If the key does not exist, its value is set to the set of values |
| `smembers` | key | list of strings | Returns the set of values of `key`. if the key does not exist, this is an empty set. |
| `srem` | key, list of strings | integer | Removes the strings from the set of values of `key`, and returns the number of newly removed values. If the key does not exist, this does nothing. |
| Pub-sub operations |
| `publish` | address, channel, bytes | - | Publishes a message to the specified channel, with the specified payload bytes. |
| `publish` | channel, bytes | - | Publishes a message to the specified channel, with the specified payload bytes. |
| General operations |
| `execute` | address, command, list of argument values | list of results | Executes the specified command with the specified arguments. This is a general-purpose 'escape hatch' if you need a command that isn't covered by the built-in operations. |
| `execute` | command, list of argument values | list of results | Executes the specified command with the specified arguments. This is a general-purpose 'escape hatch' if you need a command that isn't covered by the built-in operations. |

The exact detail of calling these operations from your application depends on your language:

{{ tabs "sdk-type" }}

{{ startTab "Rust"}}

Redis functions are available in the `spin_sdk::redis` module. The function names match the operations above. For example:
Redis functions are available in the `spin_sdk::redis` module.

To access a Redis instance, use the `Connection::open` function.

```rust
use spin_sdk::redis;
let connection = spin_sdk::redis::Connection::open(&address)?;
```

You can then call functions on the `Connection` to work with the Redis instance:

let value = redis::get(&address, &key)?;
```rust
connection.set("my-key", &"my-value".into());
let data = connection.get("my-key")?;
```

For full details of the Redis API, see the [Spin SDK reference documentation](https://fermyon.github.io/rust-docs/spin/main/spin_sdk/redis/index.html);

**General Notes**

* Address and key parameters are of type `&str`.
* Keys are of type `&str`.
* Bytes parameters are of type `&[u8]` and return values are `Vec<u8>`.
* Numeric return values are of type `i64`.
* All functions wrap the return in `anyhow::Result`.
Expand All @@ -60,11 +70,11 @@ let value = redis::get(&address, &key)?;

**`del` Operation**

* The list of keys is passed as `&[&str]`.
* The list of keys is passed as `&[String]`.

**Set Operations**

* List arguments are passed as `&[&str]` and returned as `Vec<String>`.
* List arguments are passed as `&[String]` and returned as `Vec<String>`.

**`execute` Operation**

Expand All @@ -76,7 +86,7 @@ You can find a complete Rust code example for using outbound Redis from an HTTP

{{ startTab "TypeScript"}}

Redis functions are available on the `Redis` object. The function names match the operations above. For example:
Redis functions are available on the `Redis` object. The function names match the operations above, but you must pass the Redis instance address to _each_ operation as its first parameter. For example:

```javascript
import {Redis} from "@fermyon/spin-sdk"
Expand All @@ -102,7 +112,7 @@ You can find a complete TypeScript example for using outbound Redis from an HTTP

{{ startTab "Python"}}

Redis functions are available in the `spin_redis` module. The function names are prefixed `redis_`. For example:
Redis functions are available in the `spin_redis` module. The function names are prefixed `redis_`. You must pass the Redis instance address to _each_ operation as its first parameter. For example:

```python
from spin_redis import redis_get
Expand All @@ -124,7 +134,7 @@ You can find a complete Python code example for using outbound Redis from an HTT

{{ startTab "TinyGo"}}

Redis functions are available in the `github.com/fermyon/spin/sdk/go/v2/redis` package. [See Go Packages for reference documentation.](https://pkg.go.dev/github.com/fermyon/spin/sdk/go/v2/redis). The function names are TitleCased. For example:
Redis functions are available in the `github.com/fermyon/spin/sdk/go/v2/redis` package. [See Go Packages for reference documentation.](https://pkg.go.dev/github.com/fermyon/spin/sdk/go/v2/redis) The function names are TitleCased. For example:

```go
import (
Expand All @@ -137,7 +147,7 @@ payload, err := rdb.Get(key)

**General Notes**

* Address and key parameters are strings.
* Key parameters are strings.
* Bytes parameters are byte slices (`[]byte`).
* Lists are passed as slices. For example, `redis.Del` takes the keys to delete as a `[]string`.
* Errors are return through the usual Go multiple return values mechanism.
Expand Down
4 changes: 2 additions & 2 deletions content/spin/v2/serverless-ai-api-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ The nature of AI and LLM workloads on already trained models lends itself very n

### Configuration

By default, a given component of a Spin application will not have access to any Serverless AI models. Access must be provided explicitly via the Spin application's manifest (the `spin.toml` file). For example, an individual component in a Spin application could be given access to the llama2-chat model by adding the following `ai_models` configuration inside the specific `[[component]]` section:
By default, a given component of a Spin application will not have access to any Serverless AI models. Access must be provided explicitly via the Spin application's manifest (the `spin.toml` file). For example, an individual component in a Spin application could be given access to the llama2-chat model by adding the following `ai_models` configuration inside the specific `[component.(name)]` section:

<!-- @nocpy -->

```toml
// -- snip --

[[component]]
[component.please-send-the-codes]
ai_models = ["codellama-instruct"]

// -- snip --
Expand Down
Loading

0 comments on commit b4c3dfe

Please sign in to comment.