fix(library): fix inconsistencies in comments/code

This commit is contained in:
Richard Ramos 2022-10-09 11:08:46 -04:00 committed by RichΛrd
parent 5403a8fc28
commit 0cf0446881
10 changed files with 133 additions and 130 deletions

View File

@ -18,7 +18,7 @@ endif
build:
cd ../../ && $(MAKE) static-library # Building library
rm -rf build && \
rm -rf build/main && \
echo "Compiling 'main.c'"
+ mkdir -p build
$(CC) \

View File

@ -14,18 +14,6 @@ An alternative is to link existing Waku implementation as a static or dynamic li
This specification describes the C API that SHOULD be implemented by native Waku library and that SHOULD be used to
consume them.
# Design requirements
The API should be generic enough, so:
- it can be implemented by both nwaku and go-waku C-Bindings,
- it can be consumed from a variety of languages such as C#, Kotlin, Swift, Rust, C++, etc.
The selected format to pass data to and from the API is `JSON`.
It has been selected due to its widespread usage and easiness of use. Other alternatives MAY replace it in the future (C
structure, protobuf) if it brings limitations that need to be lifted.
# The API
## General
@ -276,7 +264,7 @@ which are used to react to asynchronous events in Waku.
Type holding a node configuration:
```ts
interface JsonSignal {
interface JsonConfig {
host?: string;
port?: number;
advertiseAddr?: string;
@ -480,7 +468,7 @@ Dial peer using its peer ID.
1`char* peerID`: Peer ID to dial.
The peer must be already known.
It must have been added before with [`waku_add_peer`](#extern-char-waku_add_peerchar-address-char-protocolid)
or previously dialed with [`waku_connect_peer`](#extern-char-waku_connect_peerchar-address-int-timeoutms).
or previously dialed with [`waku_connect`](#extern-char-waku_connectchar-address-int-timeoutms).
2. `int timeoutMs`: Timeout value in milliseconds to execute the call.
If the function execution takes longer than this value,
the execution will be canceled and an error returned.
@ -743,7 +731,6 @@ For Example:
{
"type": "message",
"event": {
"subscriptionID": 1,
"pubsubTopic": "/waku/2/default-waku/proto",
"messageID": "0x6496491e40dbe0b6c3a2198c2426b16301688a2daebc4f57ad7706115eac3ad1",
"wakuMessage": {
@ -825,9 +812,8 @@ For Example:
{
"type": "message",
"event": {
"subscriptionID": 1,
"pubsubTopic": "/waku/2/default-waku/proto",
"messageID": "0x6496491e40dbe0b6c3a2198c2426b16301688a2daebc4f57ad7706115eac3ad1",
"messageId": "0x6496491e40dbe0b6c3a2198c2426b16301688a2daebc4f57ad7706115eac3ad1",
"wakuMessage": {
"payload": "TODO",
"contentTopic": "/my-app/1/notification/proto",
@ -1060,6 +1046,15 @@ Decode a base64 string (useful for reading the payload from Waku Messages).
A [`JsonResponse`](#jsonresponse-type).
If the execution is successful, the `result` field contains the decoded payload.
### `extern void waku_utils_free(char* data)`
Frees a char* since all strings returned by gowaku are allocated in the C heap using malloc.
**Parameters**
1. `char* data`: variable to free
# Copyright
Copyright and related rights waived via

View File

@ -6,33 +6,36 @@ import (
mobile "github.com/status-im/go-waku/mobile"
)
//export waku_store_query
// Query historic messages using waku store protocol.
// queryJSON must contain a valid json string with the following format:
// {
// "pubsubTopic": "...", // optional string
// "startTime": 1234, // optional, unix epoch time in nanoseconds
// "endTime": 1234, // optional, unix epoch time in nanoseconds
// "contentFilters": [ // optional
// {
// contentTopic: "contentTopic1"
// }, ...
// ],
// "pagingOptions": {// optional pagination information
// "pageSize": 40, // number
// "cursor": { // optional
// "digest": ...,
// "receiverTime": ...,
// "senderTime": ...,
// "pubsubTopic" ...,
// }
// "forward": true, // sort order
// }
// }
// If the message length is greater than 0, this function should be executed again, setting the `cursor` attribute with the cursor returned in the response
//
// {
// "pubsubTopic": "...", // optional string
// "startTime": 1234, // optional, unix epoch time in nanoseconds
// "endTime": 1234, // optional, unix epoch time in nanoseconds
// "contentFilters": [ // optional
// {
// contentTopic: "contentTopic1"
// }, ...
// ],
// "pagingOptions": {// optional pagination information
// "pageSize": 40, // number
// "cursor": { // optional
// "digest": ...,
// "receiverTime": ...,
// "senderTime": ...,
// "pubsubTopic" ...,
// }
// "forward": true, // sort order
// }
// }
//
// If a non empty cursor is returned, this function should be executed again, setting the `cursor` attribute with the cursor returned in the response
// peerID should contain the ID of a peer supporting the store protocol. Use NULL to automatically select a node
// If ms is greater than 0, the broadcast of the message must happen before the timeout
// (in milliseconds) is reached, or an error will be returned
//
//export waku_store_query
func waku_store_query(queryJSON *C.char, peerID *C.char, ms C.int) *C.char {
response := mobile.StoreQuery(C.GoString(queryJSON), C.GoString(peerID), int(ms))
return C.CString(response)

View File

@ -8,30 +8,35 @@ import "C"
import (
"encoding/base64"
"unsafe"
mobile "github.com/status-im/go-waku/mobile"
)
//export waku_utils_base64_decode
// Decode a base64 string (useful for reading the payload from waku messages)
//
//export waku_utils_base64_decode
func waku_utils_base64_decode(data *C.char) *C.char {
b, err := base64.StdEncoding.DecodeString(C.GoString(data))
if err != nil {
return makeJSONResponse(err)
return C.CString(mobile.MakeJSONResponse(err))
}
return prepareJSONResponse(string(b), nil)
}
//export waku_utils_base64_encode
// Encode data to base64 (useful for creating the payload of a waku message in the
// format understood by waku_relay_publish)
//
//export waku_utils_base64_encode
func waku_utils_base64_encode(data *C.char) *C.char {
str := base64.StdEncoding.EncodeToString([]byte(C.GoString(data)))
return C.CString(string(str))
}
//export waku_utils_free
// Frees a char* since all strings returned by gowaku are allocated in the C heap using malloc.
//
//export waku_utils_free
func waku_utils_free(data *C.char) {
C.free(unsafe.Pointer(data))
}

View File

@ -98,33 +98,33 @@ func getConfig(configJSON string) (wakuConfig, error) {
func NewNode(configJSON string) string {
if wakuNode != nil {
return makeJSONResponse(errors.New("go-waku already initialized. stop it first"))
return MakeJSONResponse(errors.New("go-waku already initialized. stop it first"))
}
config, err := getConfig(configJSON)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
hostAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", *config.Host, *config.Port))
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
var prvKey *ecdsa.PrivateKey
if config.NodeKey != nil {
prvKey, err = crypto.HexToECDSA(*config.NodeKey)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
} else {
key, err := randomHex(32)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
prvKey, err = crypto.HexToECDSA(key)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
}
@ -146,31 +146,31 @@ func NewNode(configJSON string) string {
w, err := node.New(ctx, opts...)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
wakuNode = w
return makeJSONResponse(nil)
return MakeJSONResponse(nil)
}
func Start() string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
if err := wakuNode.Start(); err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
wakuStarted = true
return makeJSONResponse(nil)
return MakeJSONResponse(nil)
}
func Stop() string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
wakuNode.Stop()
@ -178,24 +178,24 @@ func Stop() string {
wakuStarted = false
wakuNode = nil
return makeJSONResponse(nil)
return MakeJSONResponse(nil)
}
func IsStarted() string {
return prepareJSONResponse(wakuStarted, nil)
return PrepareJSONResponse(wakuStarted, nil)
}
func PeerID() string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
return prepareJSONResponse(wakuNode.ID(), nil)
return PrepareJSONResponse(wakuNode.ID(), nil)
}
func ListenAddresses() string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
var addresses []string
@ -203,26 +203,26 @@ func ListenAddresses() string {
addresses = append(addresses, addr.String())
}
return prepareJSONResponse(addresses, nil)
return PrepareJSONResponse(addresses, nil)
}
func AddPeer(address string, protocolID string) string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
ma, err := multiaddr.NewMultiaddr(address)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
peerID, err := wakuNode.AddPeer(ma, protocolID)
return prepareJSONResponse(peerID, err)
return PrepareJSONResponse(peerID, err)
}
func Connect(address string, ms int) string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
var ctx context.Context
@ -236,12 +236,12 @@ func Connect(address string, ms int) string {
}
err := wakuNode.DialPeer(ctx, address)
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
func ConnectPeerID(peerID string, ms int) string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
var ctx context.Context
@ -249,7 +249,7 @@ func ConnectPeerID(peerID string, ms int) string {
pID, err := peer.Decode(peerID)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
if ms > 0 {
@ -260,29 +260,29 @@ func ConnectPeerID(peerID string, ms int) string {
}
err = wakuNode.DialPeerByID(ctx, pID)
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
func Disconnect(peerID string) string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
pID, err := peer.Decode(peerID)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
err = wakuNode.ClosePeerById(pID)
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
func PeerCnt() string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
return prepareJSONResponse(wakuNode.PeerCount(), nil)
return PrepareJSONResponse(wakuNode.PeerCount(), nil)
}
func ContentTopic(applicationName string, applicationVersion int, contentTopicName string, encoding string) string {
@ -305,7 +305,7 @@ func getTopic(topic string) string {
}
type subscriptionMsg struct {
MessageID string `json:"messageID"`
MessageID string `json:"messageId"`
PubsubTopic string `json:"pubsubTopic"`
Message *pb.WakuMessage `json:"wakuMessage"`
}
@ -320,11 +320,11 @@ func toSubscriptionMessage(msg *protocol.Envelope) *subscriptionMsg {
func Peers() string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
peers, err := wakuNode.Peers()
return prepareJSONResponse(peers, err)
return PrepareJSONResponse(peers, err)
}
func unmarshalPubkey(pub []byte) (ecdsa.PublicKey, error) {
@ -339,13 +339,13 @@ func DecodeSymmetric(messageJSON string, symmetricKey string) string {
var msg pb.WakuMessage
err := json.Unmarshal([]byte(messageJSON), &msg)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
if msg.Version == 0 {
return prepareJSONResponse(msg.Payload, nil)
return PrepareJSONResponse(msg.Payload, nil)
} else if msg.Version > 1 {
return makeJSONResponse(errors.New("unsupported wakumessage version"))
return MakeJSONResponse(errors.New("unsupported wakumessage version"))
}
keyInfo := &node.KeyInfo{
@ -354,12 +354,12 @@ func DecodeSymmetric(messageJSON string, symmetricKey string) string {
keyInfo.SymKey, err = utils.DecodeHexString(symmetricKey)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
payload, err := node.DecodePayload(&msg, keyInfo)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
response := struct {
@ -374,20 +374,20 @@ func DecodeSymmetric(messageJSON string, symmetricKey string) string {
Padding: payload.Padding,
}
return prepareJSONResponse(response, err)
return PrepareJSONResponse(response, err)
}
func DecodeAsymmetric(messageJSON string, privateKey string) string {
var msg pb.WakuMessage
err := json.Unmarshal([]byte(messageJSON), &msg)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
if msg.Version == 0 {
return prepareJSONResponse(msg.Payload, nil)
return PrepareJSONResponse(msg.Payload, nil)
} else if msg.Version > 1 {
return makeJSONResponse(errors.New("unsupported wakumessage version"))
return MakeJSONResponse(errors.New("unsupported wakumessage version"))
}
keyInfo := &node.KeyInfo{
@ -396,17 +396,17 @@ func DecodeAsymmetric(messageJSON string, privateKey string) string {
keyBytes, err := utils.DecodeHexString(privateKey)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
keyInfo.PrivKey, err = crypto.ToECDSA(keyBytes)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
payload, err := node.DecodePayload(&msg, keyInfo)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
response := struct {
@ -421,5 +421,5 @@ func DecodeAsymmetric(messageJSON string, privateKey string) string {
Padding: payload.Padding,
}
return prepareJSONResponse(response, err)
return PrepareJSONResponse(response, err)
}

View File

@ -35,11 +35,11 @@ func toContentFilter(filterJSON string) (filter.ContentFilter, error) {
func FilterSubscribe(filterJSON string, peerID string, ms int) string {
cf, err := toContentFilter(filterJSON)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
var ctx context.Context
@ -56,7 +56,7 @@ func FilterSubscribe(filterJSON string, peerID string, ms int) string {
if peerID != "" {
p, err := peer.Decode(peerID)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
fOptions = append(fOptions, filter.WithPeer(p))
} else {
@ -65,7 +65,7 @@ func FilterSubscribe(filterJSON string, peerID string, ms int) string {
_, f, err := wakuNode.Filter().Subscribe(ctx, cf, fOptions...)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
go func(f filter.Filter) {
@ -74,17 +74,17 @@ func FilterSubscribe(filterJSON string, peerID string, ms int) string {
}
}(f)
return prepareJSONResponse(true, nil)
return PrepareJSONResponse(true, nil)
}
func FilterUnsubscribe(filterJSON string, ms int) string {
cf, err := toContentFilter(filterJSON)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
var ctx context.Context
@ -99,8 +99,8 @@ func FilterUnsubscribe(filterJSON string, ms int) string {
err = wakuNode.Filter().UnsubscribeFilter(ctx, cf)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
return makeJSONResponse(nil)
return MakeJSONResponse(nil)
}

View File

@ -44,31 +44,31 @@ func lightpushPublish(msg pb.WakuMessage, pubsubTopic string, peerID string, ms
func LightpushPublish(messageJSON string, topic string, peerID string, ms int) string {
msg, err := wakuMessage(messageJSON)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
hash, err := lightpushPublish(msg, getTopic(topic), peerID, ms)
return prepareJSONResponse(hash, err)
return PrepareJSONResponse(hash, err)
}
func LightpushPublishEncodeAsymmetric(messageJSON string, topic string, peerID string, publicKey string, optionalSigningKey string, ms int) string {
msg, err := wakuMessageAsymmetricEncoding(messageJSON, publicKey, optionalSigningKey)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
hash, err := lightpushPublish(msg, getTopic(topic), peerID, ms)
return prepareJSONResponse(hash, err)
return PrepareJSONResponse(hash, err)
}
func LightpushPublishEncodeSymmetric(messageJSON string, topic string, peerID string, symmetricKey string, optionalSigningKey string, ms int) string {
msg, err := wakuMessageSymmetricEncoding(messageJSON, symmetricKey, optionalSigningKey)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
hash, err := lightpushPublish(msg, getTopic(topic), peerID, ms)
return prepareJSONResponse(hash, err)
return PrepareJSONResponse(hash, err)
}

View File

@ -17,7 +17,7 @@ var relaySubsMutex sync.Mutex
func RelayEnoughPeers(topic string) string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
topicToCheck := protocol.DefaultPubsubTopic().String()
@ -25,7 +25,7 @@ func RelayEnoughPeers(topic string) string {
topicToCheck = topic
}
return prepareJSONResponse(wakuNode.Relay().EnoughPeersToPublishToTopic(topicToCheck), nil)
return PrepareJSONResponse(wakuNode.Relay().EnoughPeersToPublishToTopic(topicToCheck), nil)
}
func relayPublish(msg pb.WakuMessage, pubsubTopic string, ms int) (string, error) {
@ -50,38 +50,38 @@ func relayPublish(msg pb.WakuMessage, pubsubTopic string, ms int) (string, error
func RelayPublish(messageJSON string, topic string, ms int) string {
msg, err := wakuMessage(messageJSON)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
hash, err := relayPublish(msg, getTopic(topic), int(ms))
return prepareJSONResponse(hash, err)
return PrepareJSONResponse(hash, err)
}
func RelayPublishEncodeAsymmetric(messageJSON string, topic string, publicKey string, optionalSigningKey string, ms int) string {
msg, err := wakuMessageAsymmetricEncoding(messageJSON, publicKey, optionalSigningKey)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
hash, err := relayPublish(msg, getTopic(topic), int(ms))
return prepareJSONResponse(hash, err)
return PrepareJSONResponse(hash, err)
}
func RelayPublishEncodeSymmetric(messageJSON string, topic string, symmetricKey string, optionalSigningKey string, ms int) string {
msg, err := wakuMessageSymmetricEncoding(messageJSON, symmetricKey, optionalSigningKey)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
hash, err := relayPublish(msg, getTopic(topic), int(ms))
return prepareJSONResponse(hash, err)
return PrepareJSONResponse(hash, err)
}
func RelaySubscribe(topic string) string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
topicToSubscribe := getTopic(topic)
@ -91,12 +91,12 @@ func RelaySubscribe(topic string) string {
_, ok := relaySubscriptions[topicToSubscribe]
if ok {
return makeJSONResponse(nil)
return MakeJSONResponse(nil)
}
subscription, err := wakuNode.Relay().SubscribeToTopic(context.Background(), topicToSubscribe)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
relaySubscriptions[topicToSubscribe] = subscription
@ -107,12 +107,12 @@ func RelaySubscribe(topic string) string {
}
}(subscription)
return makeJSONResponse(nil)
return MakeJSONResponse(nil)
}
func RelayUnsubscribe(topic string) string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
topicToUnsubscribe := getTopic(topic)
@ -122,7 +122,7 @@ func RelayUnsubscribe(topic string) string {
subscription, ok := relaySubscriptions[topicToUnsubscribe]
if ok {
return makeJSONResponse(nil)
return MakeJSONResponse(nil)
}
subscription.Unsubscribe()
@ -131,8 +131,8 @@ func RelayUnsubscribe(topic string) string {
err := wakuNode.Relay().Unsubscribe(context.Background(), topicToUnsubscribe)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
return makeJSONResponse(nil)
return MakeJSONResponse(nil)
}

View File

@ -36,13 +36,13 @@ type storeMessagesReply struct {
func StoreQuery(queryJSON string, peerID string, ms int) string {
if wakuNode == nil {
return makeJSONResponse(errWakuNodeNotReady)
return MakeJSONResponse(errWakuNodeNotReady)
}
var args storeMessagesArgs
err := json.Unmarshal([]byte(queryJSON), &args)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
options := []store.HistoryRequestOption{
@ -54,7 +54,7 @@ func StoreQuery(queryJSON string, peerID string, ms int) string {
if peerID != "" {
p, err := peer.Decode(peerID)
if err != nil {
return makeJSONResponse(err)
return MakeJSONResponse(err)
}
options = append(options, store.WithPeer(p))
} else {
@ -91,7 +91,7 @@ func StoreQuery(queryJSON string, peerID string, ms int) string {
if err != nil {
reply.Error = err.Error()
return prepareJSONResponse(reply, nil)
return PrepareJSONResponse(reply, nil)
}
reply.Messages = res.Messages
reply.PagingInfo = storePagingOptions{
@ -100,5 +100,5 @@ func StoreQuery(queryJSON string, peerID string, ms int) string {
Forward: args.PagingOptions.Forward,
}
return prepareJSONResponse(reply, nil)
return PrepareJSONResponse(reply, nil)
}

View File

@ -10,7 +10,7 @@ type jsonResponseSuccess struct {
Result interface{} `json:"result"`
}
func prepareJSONResponse(result interface{}, err error) string {
func PrepareJSONResponse(result interface{}, err error) string {
if err != nil {
errStr := err.Error()
@ -23,12 +23,12 @@ func prepareJSONResponse(result interface{}, err error) string {
data, err := json.Marshal(jsonResponseSuccess{Result: result})
if err != nil {
return prepareJSONResponse(nil, err)
return PrepareJSONResponse(nil, err)
}
return string(data)
}
func makeJSONResponse(err error) string {
func MakeJSONResponse(err error) string {
if err != nil {
errStr := err.Error()
outBytes, _ := json.Marshal(jsonResponseError{Error: &errStr})