# K3 Wasm Rust SDK

This document is for developers new to the framework who would like to make applications using our Rust SDK.

## Getting started

The recommended way to start is by forking one of the many Rust examples we have on our GitHub (the simplest one is <https://github.com/k3-labs/k3-template-hello-world-rust>) and then deploy that on our platform through your GitHub login. If you have a Rust project already or want to learn how to set up a K3 project yourself here are the steps:

1. Add K3 dependencies:

   ```rust
   k3-wasm-sdk = { version = "0.1.15" }
   k3-wasm-macros = { version = "0.1.10" }
   ```
2. (optional) switch to nightly and add the nightly feature for the `k3-wasm-macros` dependency

   Switching to nightly gives you access to file-based routing for the macros (i.e. you can have a `get` function exported in `/api/users/mod.rs` and it would work as an HTTP GET handler for `/api/users`. Without file routing you have to specify the HTTP route you want to catch in the macro (this will be shown later)
3. Add the init macro call to your `main.rs` file:

   ```rust
   // your other code here...

   k3_wasm_macros::init!();
   ```
4. Annotate any handlers you want to export with the `http_handler` decorator:

   ```rust
   #[k3_wasm_macros::http_handler]
   pub fn get(_req: Request<Vec<u8>>) -> Response<Vec<u8>> {
   	// your code here...
   }
   ```

   Or without file-based routing:

   ```rust
   #[k3_wasm_macros::http_handler("/api/users")]
   pub fn get(_req: Request<Vec<u8>>) -> Response<Vec<u8>> {
   	// your code here...
   }
   ```

## Writing handlers

Handlers are similar to serverless functions if you’ve ever implemented those in Node.js or Go. Their only parameter is an HTTP request object and it expects you to return an HTTP response object (we re-export the types from the popular Rust `http` crate for both). For example:

```rust
#[k3_wasm_macros::http_handler]
pub fn get(req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	let target = req.uri().to_string();
	let name = target.split('/').last().unwrap();
	if name == "" {
		Response::builder()
			.status(400)
			.body("USAGE: /[name]".as_bytes().to_vec())
			.unwrap()
	} else {
		Response::builder()
			.status(200)
			.body(format!("Hello {}!", name).as_bytes().to_vec())
			.unwrap()
	}
}
```

You can have any logic you like there but you must remember that this will be compiled to WebAssembly which is a very sandboxed environment and doesn’t have direct access to the file-system or the internet for example.

To access the outside world you can use functions from our SDK and for dependencies you will have to check in their documentation if they support the WebAssembly environment (libraries that work in `no_std` will usually directly support WebAssembly as well).

## Using the SDK

The K3 execution environment gives you many tools to access from the outside world (some of which you might have to enable in the dashboard for your team). We’ll go through all of them with a reference for each export and then examples on how to use them.

### HTTP

This is currently the most minimal SDK module and will likely have more functions added soon.

#### `fn get(url: &str) -> Option<Vec<u8>>`

Makes an HTTP GET request to the provided URL and returns the response body as a buffer.

```rust
pub fn get(req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	let res = k3_wasm_sdk::http::get("<https://example.com>").unwrap();
	Response::builder()
		.status(200)
		.header("Content-Type", "text/html")
		.body(res)
		.unwrap()
}
```

\
\
\
`fn get_with_auth(url: &str, auth: &str) -> Option<Vec<u8>>`\
\
Makes an HTTP GET request with AUTHORIZATION header to the provided URL and returns the response body as a buffer.

```rust
pub fn get_with_auth(req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	let res = k3_wasm_sdk::http::get_with_auth(
	"<https://example.com>",
	"EXAMPLE_AUTH_TOKEN"
	).unwrap();

	Response::builder()
		.status(200)
		.header("Content-Type", "text/html")
		.body(res)
		.unwrap()
}
```

### IPFS

The IPFS module allows you to store and read files from IPFS.

#### `fn upload(contents: Vec<u8>) -> String`

Uploads some data to IPFS and returns a content ID that can be used to fetch it later.

```rust
pub fn get(req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	let cid = k3_wasm_sdk::ipfs::upload("Hello IPFS!".as_bytes().to_vec());
	Response::builder()
		.status(200)
		.body(cid.as_bytes().to_vec())
		.unwrap()
}
```

#### `fn read(cid: &str) -> Vec<u8>`

Reads a file from IPFS given its content ID.

```rust
pub fn get(req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	let cid = &req.uri().query().unwrap()["cid=".len()..];
	let buf = k3_wasm_sdk::ipfs::read(cid);
	Response::builder()
		.status(200)
		.body(buf)
		.unwrap()
}
```

### Key Value Store

The `kv` module gives you access to a fast, in-memory, string-based key value store (that unreliably commits to IPFS). The module only exports the `Db` struct, the methods in which give you access to the functionality.

#### `fn Db::open_default() -> Db`

Opens the default store for this module.

```rust
pub fn get(req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	let db = k3_wasm_sdk::kv::open_default();
	// use db here...
}
```

#### `fn Db::get(&self, key: &str) -> Option<String>`

Gets and returns a value from this store.

```rust
pub fn get(req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	let db = k3_wasm_sdk::kv::open_default();
	let current_value = db.get("value").unwrap_or("<UNDEFINED>".to_string());
	Response::builder()
		.status(200)
		.body(current_value.as_bytes().to_vec())
		.unwrap()
}
```

#### `fn Db::set(&mut self, key: &str, value: String)`

Inserts or modifies a value (depending on whether it exists or not) in this store.

```rust
pub fn post(req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	let new_value = String::from_utf8(req.into_body()).unwrap();
	let mut db = k3_wasm_sdk::kv::open_default();
	db.set("value", new_value);
	Response::builder()
		.status(200)
		.body("Updated value!".as_bytes().to_vec())
		.unwrap()
}
```

#### `fn Db::delete(&mut self, key: &str)`

Deletes the value for a given key in this store.

```rust
pub fn delete(req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	let mut db = k3_wasm_sdk::kv::open_default();
	db.delete("value");
	Response::builder()
		.status(200)
		.body("Deleted value!".as_bytes().to_vec())
		.unwrap()
}
```

### Smart contracts

The `sc` module let’s you call Ethereum smart contracts and query data from them. Functions in this module expect you to provide the smart contracts address and also its ABI as a JSON string.

#### `fn call(address: &str, abi: &str, fn_name: &str, params: impl Tokenize) -> String`

Calls a function in the smart contract with the provided parameters and returns the transaction hash as a hex string. Panics if params are in an invalid format for the function.

```rust
pub fn post(_req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	let address = std::env::var("SC_ADDRESS").unwrap();
	let new_value = String::from_utf8(req.into_body()).unwrap();
	let tx_hash = k3_wasm_sdk::sc::call(
		&address,
		include_str!("../abi.json"),
		"writeData",
		new_value,
	);
	Response::builder()
		.status(200)
		.body(tx_hash.as_bytes().to_vec())
		.unwrap()
}
```

#### `fn query<R: Detokenize>(address: &str, abi: &str, fn_name: &str, params: impl Tokenize) -> R`

Queries a function in the smart contract and returns the data. Panics if params or expected response type are invalid for the function.

```rust
pub fn get(_req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	let address = std::env::var("SC_ADDRESS").unwrap();
	let data: (String, U256) = k3_wasm_sdk::sc::query(&address, include_str!("../abi.json"), "readData", ());
	Response::builder()
		.status(200)
		.body(data.0.as_bytes().to_vec())
		.unwrap()
}
```

### Space & Time

The `sxt` module gives you access to your team’s Space & Time databases letting you run SQL on existing tables and make new ones.

#### `fn execute_sql(sql: &str) -> String`

Executes some provided SQL on your databases. Returns a JSON string with either info about how many rows were updated or the queried data. To learn more about the JSON format check out Space & Time’s HTTP API reference.

```rust
pub fn get(_req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	let data = execute_sql("SELECT * FROM users WHERE name = 'John'");
	Response::builder()
		.status(200)
		.header("Content-Type", "application/json")
		.body(data.as_bytes().to_vec())
		.unwrap()
}
```

#### `fn execute_create_table(name: &str, types: &str) -> String`

Creates a table in your selected database. This function exists because `CREATE` table instructions are special in Space & Time and require a biscuit generated using a unique public/private key pair. This function will handle that logic for you, but you can also manually do that using their API as reference and directly call `execute_sql` instead.

```rust
pub fn create(_req: Request<Vec<u8>>) -> Response<Vec<u8>> {
	execute_create_table(
		"public.users",
		"(name VARCHAR PRIMARY KEY, displayname VARCHAR NOT NULL, passwordhash VARCHAR NOT NULL)",
	);
	Response::builder()
		.status(200)
		.header("Content-Type", "application/json")
		.body("Created table!".as_bytes().to_vec())
		.unwrap()
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.k3-labs.com/introduction/tech-documentation/k3-wasm/k3-wasm-rust-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
