docs_: better usage docs for status-backend (#5955)
This commit is contained in:
parent
e611b1e513
commit
9fcb153f32
|
@ -11,7 +11,8 @@
|
||||||
- [How to run a Bootnode](BOOTNODE.md)
|
- [How to run a Bootnode](BOOTNODE.md)
|
||||||
- [How to run a Mailserver](MAILSERVER.md)
|
- [How to run a Mailserver](MAILSERVER.md)
|
||||||
- [How to run a Waku node](./_examples/README.md#run-waku-node)
|
- [How to run a Waku node](./_examples/README.md#run-waku-node)
|
||||||
- [How to configure status-go](/config)
|
- [How to configure status-go](/config/README.md)
|
||||||
|
- [How to run status-go as HTTP server](/cmd/status-backend/README.md)
|
||||||
|
|
||||||
## Policies
|
## Policies
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Description
|
# 📝Description
|
||||||
|
|
||||||
Welcome to `status-backend`. This is a tool for debugging and testing `status-go`.
|
Welcome to `status-backend`. This is a tool for debugging and testing `status-go`.
|
||||||
In contrast to existing `statusd` and `status-cli`, the `status-backend` exposes full status-go API through HTTP.
|
In contrast to existing `statusd` and `status-cli`, the `status-backend` exposes full status-go API through HTTP.
|
||||||
|
@ -13,17 +13,87 @@ This allows to communicate with status-go through HTTP the same way as `status-d
|
||||||
- subscribe to status-go signals
|
- subscribe to status-go signals
|
||||||
- etc.
|
- etc.
|
||||||
|
|
||||||
# status-go API
|
# 📍status-go API
|
||||||
|
|
||||||
## Public methods in `./mobile/status.go`
|
> [!NOTE]
|
||||||
|
> Unfortunately, for now there is no convenient docs like OpenAPI
|
||||||
|
|
||||||
Only specific function signatures are currently supported:
|
## 1️⃣ Public methods in `./mobile/status.go`
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
Any **public** functions in `./mobile/status.go` with the one of the following signatures:
|
||||||
- `func(string) string` - 1 argument, 1 return
|
- `func(string) string` - 1 argument, 1 return
|
||||||
- `func() string` - 0 argument, 1 return
|
- `func() string` - 0 argument, 1 return
|
||||||
|
|
||||||
|
### Address
|
||||||
|
|
||||||
|
Endpoints address: `http://<address>/statusgo/<function-name>`.
|
||||||
|
|
||||||
|
Here, `statusgo` is the name of the package in `/mobile/status.go`. We might create more APIs next to it in the future.
|
||||||
|
|
||||||
|
### Response
|
||||||
|
|
||||||
|
Responses have JSON body with a single `error` field.
|
||||||
|
If `error` is empty, no error occurred.
|
||||||
|
|
||||||
|
The structure of response is defined in [`APIResponse`](https://github.com/status-im/status-go/blob/91c6949cd25449d5459581a21f2c8b929290ced0/mobile/types.go#L9-L12):
|
||||||
|
```go
|
||||||
|
// APIResponse generic response from API.
|
||||||
|
type APIResponse struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
Parameters are passed as request JSON body.
|
||||||
|
Specific parameters for each endpoint should be checked in the source code.
|
||||||
|
|
||||||
|
### How to read the source code?
|
||||||
|
|
||||||
|
As example, let's look at [`CreateAccountAndLogin`](https://github.com/status-im/status-go/blob/fc36a7e980fc8f73dd36d7e3db29675ddff1d5dc/mobile/status.go#L415-L417).
|
||||||
|
```go
|
||||||
|
func CreateAccountAndLogin(requestJSON string) string {
|
||||||
|
return callWithResponse(createAccountAndLogin, requestJSON)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. The function has 1 JSON string argument and 1 JSON string return value.
|
||||||
|
2. The function wraps a private `createAccountAndLogin` with `callWithResponse`.
|
||||||
|
`callWithResponse` does some internal magic like logging the request and response.
|
||||||
|
So we should check [the private function](https://github.com/status-im/status-go/blob/fc36a7e980fc8f73dd36d7e3db29675ddff1d5dc/mobile/status.go#L419) for real arguments and return values:
|
||||||
|
```go
|
||||||
|
func createAccountAndLogin(requestJSON string) string {
|
||||||
|
var request requests.CreateAccount
|
||||||
|
err := json.Unmarshal([]byte(requestJSON), &request)
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
3. We can see that the parameters are unmarshalled to [`requests.CreateAccount`](https://github.com/status-im/status-go/blob/f660be0daa7cc742a07f6a139ea5ac9966f3ebe0/protocol/requests/create_account.go#L35):
|
||||||
|
```go
|
||||||
|
type CreateAccount struct {
|
||||||
|
RootDataDir string `json:"rootDataDir"`
|
||||||
|
KdfIterations int `json:"kdfIterations"`
|
||||||
|
// ...
|
||||||
|
```
|
||||||
|
4. We can also see that each the response is formed as [`makeJSONResponse(err)`](https://github.com/status-im/status-go/blob/fc36a7e980fc8f73dd36d7e3db29675ddff1d5dc/mobile/status.go#L422-L424):
|
||||||
|
```go
|
||||||
|
if err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
... which wraps the error to [`APIResponse`](https://github.com/status-im/status-go/blob/91c6949cd25449d5459581a21f2c8b929290ced0/mobile/types.go#L9-L12):
|
||||||
|
```go
|
||||||
|
// APIResponse generic response from API.
|
||||||
|
type APIResponse struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Unsupported methods
|
### Unsupported methods
|
||||||
|
|
||||||
Attempt to call any other functions will return `501: Not Implemented` HTTP code.
|
Attempt to call any functions with unsupported signatures will return `501: Not Implemented` HTTP code.
|
||||||
For example, [`VerifyAccountPassword`](https://github.com/status-im/status-go/blob/669256095e16d953ca1af4954b90ca2ae65caa2f/mobile/status.go#L275-L277) has 3 arguments:
|
For example, [`VerifyAccountPassword`](https://github.com/status-im/status-go/blob/669256095e16d953ca1af4954b90ca2ae65caa2f/mobile/status.go#L275-L277) has 3 arguments:
|
||||||
```go
|
```go
|
||||||
func VerifyAccountPassword(keyStoreDir, address, password string) string {
|
func VerifyAccountPassword(keyStoreDir, address, password string) string {
|
||||||
|
@ -38,7 +108,31 @@ For example, https://github.com/status-im/status-go/pull/5865 fixes some of thes
|
||||||
|
|
||||||
Deprecated methods will have `Deprecation: true` HTTP header.
|
Deprecated methods will have `Deprecation: true` HTTP header.
|
||||||
|
|
||||||
## Signals in `./signal`
|
## 2️⃣ Signals in `./signal`
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Unfortunately, there is no description of when any expected signals will appear.
|
||||||
|
> For now, you have to check the source code.
|
||||||
|
|
||||||
|
### Address
|
||||||
|
|
||||||
|
Signals are available at `ws://<address>/signals`.
|
||||||
|
|
||||||
|
Connect to it as the first thing when running `status-backend`.
|
||||||
|
|
||||||
|
### Available signals
|
||||||
|
|
||||||
|
List of possible events can be found in `./signal/event_*.go` files.
|
||||||
|
|
||||||
|
For example, `node.login` event is defined [here](https://github.com/status-im/status-go/blob/6bcf5f1289f9160168574290cbd6f90dede3f8f6/signal/events_node.go#L27-L28):
|
||||||
|
```go
|
||||||
|
const (
|
||||||
|
// EventLoggedIn is once node was injected with user account and ready to be used.
|
||||||
|
EventLoggedIn = "node.login"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Signals structure
|
||||||
|
|
||||||
Each signal has [this structure](https://github.com/status-im/status-go/blob/c9b777a2186364b8f394ad65bdb18b128ceffa70/signal/signals.go#L30-L33):
|
Each signal has [this structure](https://github.com/status-im/status-go/blob/c9b777a2186364b8f394ad65bdb18b128ceffa70/signal/signals.go#L30-L33):
|
||||||
```go
|
```go
|
||||||
|
@ -49,16 +143,7 @@ type Envelope struct {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
List of possible events can be found in `./signal/event_*.go` files.
|
Here, `type` is the name of the event, e.g. `node.login`.
|
||||||
|
|
||||||
For example, `node.login` event is defined [here](https://github.com/status-im/status-go/blob/6bcf5f1289f9160168574290cbd6f90dede3f8f6/signal/events_node.go#L27-L28):
|
|
||||||
```go
|
|
||||||
const (
|
|
||||||
// EventLoggedIn is once node was injected with user account and ready to be used.
|
|
||||||
EventLoggedIn = "node.login"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
And the structure of this event is [defined in the same file](https://github.com/status-im/status-go/blob/6bcf5f1289f9160168574290cbd6f90dede3f8f6/signal/events_node.go#L36-L42):
|
And the structure of this event is [defined in the same file](https://github.com/status-im/status-go/blob/6bcf5f1289f9160168574290cbd6f90dede3f8f6/signal/events_node.go#L36-L42):
|
||||||
```go
|
```go
|
||||||
// NodeLoginEvent returns the result of the login event
|
// NodeLoginEvent returns the result of the login event
|
||||||
|
@ -70,7 +155,6 @@ type NodeLoginEvent struct {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
So the signal for `node.login` event will look like this (with corresponding data):
|
So the signal for `node.login` event will look like this (with corresponding data):
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -84,9 +168,33 @@ So the signal for `node.login` event will look like this (with corresponding dat
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Services in `./services/**/api.go`
|
## 3️⃣ Services in `./services/**/api.go`
|
||||||
|
|
||||||
Services are registered in go-ethereum JSON-RPC server. To call such method, send request to `statusgo/CallRPC` endpoint.
|
Services are registered in the [go-ethereum JSON-RPC](https://geth.ethereum.org/docs/interacting-with-geth/rpc) server.
|
||||||
|
All `./services/**/api.go` are registered as services in geth.
|
||||||
|
|
||||||
|
Each method name has form `<namespace>_<method>`. In most cases namespace is the directory name, but it can be ensured in the `APIs` method of each service. For example, for [wallet service](https://github.com/status-im/status-go/blob/1d173734a608de2d71480d6ad39f4559f11a75e2/services/wallet/service.go#L288-L298):
|
||||||
|
```go
|
||||||
|
// APIs returns list of available RPC APIs.
|
||||||
|
func (s *Service) APIs() []gethrpc.API {
|
||||||
|
return []gethrpc.API{
|
||||||
|
{
|
||||||
|
Namespace: "wallet",
|
||||||
|
Version: "0.1.0",
|
||||||
|
Service: NewAPI(s),
|
||||||
|
Public: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Address
|
||||||
|
|
||||||
|
These methods are available through `/statusgo/CallRPC` endpoint defined [here](https://github.com/status-im/status-go/blob/fc36a7e980fc8f73dd36d7e3db29675ddff1d5dc/mobile/status.go#L249-L260).
|
||||||
|
|
||||||
|
This is the way desktop and mobile clients call these methods. You don't have to run a separate geth HTTP server for this.
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
```http request
|
```http request
|
||||||
|
@ -105,12 +213,14 @@ POST http://localhost:12345/statusgo/CallRPC
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Please reference to the source code for the list of methods and its arguments.
|
||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|
||||||
1. In this case, there's no limitation to the number of arguments, comparing to `mobile/status.go`, so ll method are supported.
|
1. In this case, there's no limitation to the number of arguments, comparing to `mobile/status.go`, so ll method are supported.
|
||||||
2. Deprecated methods won't have a corresponding `Deprecated: true`
|
2. Deprecated methods won't have a corresponding `Deprecated: true`
|
||||||
|
|
||||||
# Usage
|
# 🏃♂️Usage
|
||||||
|
|
||||||
Start the app with the address to listen to:
|
Start the app with the address to listen to:
|
||||||
```shell
|
```shell
|
||||||
|
@ -135,21 +245,35 @@ Access the exposed API with any HTTP client you prefer:
|
||||||
- [Python](https://pypi.org/project/requests/)
|
- [Python](https://pypi.org/project/requests/)
|
||||||
- [Go](https://pkg.go.dev/net/http)
|
- [Go](https://pkg.go.dev/net/http)
|
||||||
|
|
||||||
# Simple flows
|
# 👌 Simple flows
|
||||||
|
|
||||||
In most cases to start testing you'll need some boilerplate. Below are the simple call flows for common cases.
|
In most cases to start testing you'll need some boilerplate. Below are the simple call flows for common cases.
|
||||||
|
|
||||||
## Create account and login
|
## Create account and login
|
||||||
|
|
||||||
1. `InitializeApplication`
|
1. Subscribe to `/signals`
|
||||||
2. `CreateAccountAndLogin`
|
2. Call `/statusgo/InitializeApplication`
|
||||||
3. `wakuext_startMessenger`
|
3. Create an account
|
||||||
4. `wallet_startWallet`
|
1. Call `/statusgo/CreateAccountAndLogin`
|
||||||
5. `settings_getSettings` (temporary workaround, otherwise settings don't get saved into DB)
|
2. Wait for `node.login` signal
|
||||||
|
- If `error` is empty, no error occurred
|
||||||
|
- If `error` is not empty, stop the operation
|
||||||
|
4. Start required services
|
||||||
|
1. Call `/statusgo/CallRPC` with `{ "method": "wakuext_startMessenger", "params": [] }`
|
||||||
|
2. Call `/statusgo/CallRPC` with `{ "method": "wallet_startWallet", "params": [] }`
|
||||||
|
5. Apply temporary workarounds:
|
||||||
|
1. Call `/statusgo/CallRPC` with `{ "method": "settings_getSettings", "params": [] }`
|
||||||
|
_(otherwise settings don't get saved into DB)_
|
||||||
|
|
||||||
## Login into account
|
## Login into account
|
||||||
|
|
||||||
1. `InitializeApplication`
|
1. Subscribe to `/signals`
|
||||||
2. `LoginAccount`
|
2. Call `/statusgo/InitializeApplication`
|
||||||
3. `wakuext_startMessenger`
|
3. Create an account
|
||||||
4. `wallet_startWallet`
|
1. Call `/statusgo/LoginAccount`
|
||||||
|
2. Wait for `node.login` signal
|
||||||
|
- If `error` is empty, no error occurred
|
||||||
|
- If `error` is not empty, stop the operation
|
||||||
|
4. Start required services
|
||||||
|
1. Call `/statusgo/CallRPC` with `{ "method": "wakuext_startMessenger", "params": [] }`
|
||||||
|
2. Call `/statusgo/CallRPC` with `{ "method": "wallet_startWallet", "params": [] }`
|
||||||
|
|
Loading…
Reference in New Issue