github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/http/response.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package http
     5  
     6  import (
     7  	"encoding/json"
     8  	"io/ioutil"
     9  	"net/http"
    10  
    11  	"github.com/juju/errors"
    12  
    13  	"github.com/juju/juju/apiserver/params"
    14  )
    15  
    16  // ExtractJSONResult unserializes the JSON-encoded result into the
    17  // provided struct.
    18  func ExtractJSONResult(resp *http.Response, result interface{}) error {
    19  	// We defer closing the body here because we want it closed whether
    20  	// or not the subsequent read fails.
    21  	defer resp.Body.Close()
    22  
    23  	if resp.Header.Get("Content-Type") != CTypeJSON {
    24  		return errors.Errorf(`expected "application/json" content type, got %q`, resp.Header.Get("Content-Type"))
    25  	}
    26  
    27  	err := json.NewDecoder(resp.Body).Decode(result)
    28  	return errors.Trace(err)
    29  }
    30  
    31  // ExtractAPIError returns the failure serialized in the response
    32  // body.  If there is no failure (an OK status code), it simply returns
    33  // nil.
    34  func ExtractAPIError(resp *http.Response) (*params.Error, error) {
    35  	if resp.StatusCode == http.StatusOK {
    36  		return nil, nil
    37  	}
    38  	// We defer closing the body here because we want it closed whether
    39  	// or not the subsequent read fails.
    40  	defer resp.Body.Close()
    41  
    42  	body, err := ioutil.ReadAll(resp.Body)
    43  	if err != nil {
    44  		return nil, errors.Annotate(err, "while reading HTTP response")
    45  	}
    46  
    47  	var failure params.Error
    48  	if resp.Header.Get("Content-Type") == CTypeJSON {
    49  		if err := json.Unmarshal(body, &failure); err != nil {
    50  			return nil, errors.Annotate(err, "while unserializing the error")
    51  		}
    52  	} else {
    53  		switch resp.StatusCode {
    54  		case http.StatusNotFound, http.StatusMethodNotAllowed:
    55  			failure.Code = params.CodeNotImplemented
    56  		default:
    57  			// Leave Code empty.
    58  		}
    59  
    60  		failure.Message = string(body)
    61  	}
    62  	return &failure, nil
    63  }