solher/arangolite

View on GitHub
senders.go

Summary

Maintainability
A
35 mins
Test Coverage
package arangolite

import (
    "context"
    "encoding/json"
    "io/ioutil"
    "net/http"
    "strings"
)

type sender interface {
    Send(ctx context.Context, cli *http.Client, req *http.Request) (*response, error)
}

type basicSender struct{}

func (s *basicSender) Send(ctx context.Context, cli *http.Client, req *http.Request) (*response, error) {
    select {
    case <-ctx.Done():
        return nil, ctx.Err()
    default:
        break
    }

    res, err := cli.Do(req.WithContext(ctx))
    if err != nil {
        return nil, withMessage(err, "the database HTTP request failed")
    }

    raw, err := ioutil.ReadAll(res.Body)
    res.Body.Close()
    if err != nil {
        return nil, withMessage(err, "could not read the database response")
    }

    parsed := parsedResponse{}
    // Some API calls (such as /_api/aqlfunction) return arrays, so we have to check that
    // the body is a JSON object before trying to unmarshal.
    if strings.Contains(res.Header.Get("Content-Type"), "application/json") && raw[0] == '{' {
        if err := json.Unmarshal(raw, &parsed); err != nil {
            return nil, withMessage(err, "could not decode the json database response")
        }
    }

    raw = []byte(strings.TrimSpace(string(raw)))
    return &response{statusCode: res.StatusCode, raw: raw, parsed: parsed}, nil
}

type parsedResponse struct {
    Error        bool            `json:"error"`
    ErrorMessage string          `json:"errorMessage"`
    ErrorNum     int             `json:"errorNum"`
    Result       json.RawMessage `json:"result"`
    HasMore      bool            `json:"hasMore"`
    ID           string          `json:"id"`
}

type response struct {
    statusCode int
    raw        json.RawMessage
    parsed     parsedResponse
}

func (r *response) Raw() json.RawMessage {
    return r.raw
}

func (r *response) RawResult() json.RawMessage {
    return r.parsed.Result
}

func (r *response) StatusCode() int {
    return r.statusCode
}

func (r *response) HasMore() bool {
    return r.parsed.HasMore
}

func (r *response) Cursor() string {
    return r.parsed.ID
}

func (r *response) Unmarshal(v interface{}) error {
    if err := json.Unmarshal(r.raw, v); err != nil {
        return withMessage(err, "response unmarshalling failed")
    }
    return nil
}

func (r *response) UnmarshalResult(v interface{}) error {
    if err := json.Unmarshal(r.parsed.Result, v); err != nil {
        return withMessage(err, "response result unmarshalling failed")
    }
    return nil
}