github.com/newrelic/newrelic-client-go@v1.1.0/internal/http/graphql.go (about) 1 package http 2 3 import ( 4 "net/http" 5 "strings" 6 ) 7 8 type graphQLRequest struct { 9 Query string `json:"query"` 10 Variables map[string]interface{} `json:"variables,omitempty"` 11 } 12 13 type graphQLResponse struct { 14 Data interface{} `json:"data"` 15 } 16 17 // GraphQLError represents a single error. 18 type GraphQLError struct { 19 Message string `json:"message,omitempty"` 20 Path []string `json:"path,omitempty"` 21 Extensions struct { 22 ErrorClass string `json:"errorClass,omitempty"` 23 ErrorCode string `json:"error_code,omitempty"` 24 Code string `json:"code,omitempty"` 25 } `json:"extensions,omitempty"` 26 } 27 28 // GraphQLErrorResponse represents a default error response body. 29 type GraphQLErrorResponse struct { 30 Errors []GraphQLError `json:"errors"` 31 } 32 33 func (r *GraphQLErrorResponse) Error() string { 34 if len(r.Errors) > 0 { 35 messages := []string{} 36 for _, e := range r.Errors { 37 if e.Message != "" { 38 messages = append(messages, e.Message) 39 } 40 } 41 return strings.Join(messages, ", ") 42 } 43 44 return "" 45 } 46 47 // IsNotFound determines if the error is due to a missing resource. 48 func (r *GraphQLErrorResponse) IsNotFound() bool { 49 return false 50 } 51 52 // IsRetryableError determines if the error is due to a server timeout, or another error that we might want to retry. 53 func (r *GraphQLErrorResponse) IsRetryableError() bool { 54 if len(r.Errors) == 0 { 55 return false 56 } 57 58 for _, err := range r.Errors { 59 errorClass := err.Extensions.ErrorClass 60 if errorClass == "TIMEOUT" || errorClass == "INTERNAL_SERVER_ERROR" || errorClass == "SERVER_ERROR" { 61 return true 62 } 63 } 64 65 return false 66 } 67 68 // IsUnauthorized checks a NerdGraph response for a 401 Unauthorize HTTP status code, 69 // then falls back to check the nested extensions error_code field for `BAD_API_KEY`. 70 func (r *GraphQLErrorResponse) IsUnauthorized(resp *http.Response) bool { 71 if len(r.Errors) == 0 { 72 return false 73 } 74 75 if resp.StatusCode == http.StatusUnauthorized { 76 return true 77 } 78 79 // Handle invalid or missing API key 80 for _, err := range r.Errors { 81 if err.Extensions.ErrorCode == "BAD_API_KEY" { 82 return true 83 } 84 } 85 86 return false 87 } 88 89 func (r *GraphQLErrorResponse) IsPaymentRequired(resp *http.Response) bool { 90 return resp.StatusCode == http.StatusPaymentRequired 91 } 92 93 // IsDeprecated parses error messages for warnings that a field being used 94 // is deprecated. We want to bubble that up, but not stop returning data 95 // 96 // Example deprecation message: 97 // This field is deprecated! Please use `relatedEntities` instead. 98 func (r *GraphQLErrorResponse) IsDeprecated() bool { 99 for _, err := range r.Errors { 100 if strings.HasPrefix(err.Message, "This field is deprecated!") { 101 return true 102 } 103 } 104 105 return false 106 } 107 108 // New creates a new instance of GraphQLErrorRepsonse. 109 func (r *GraphQLErrorResponse) New() ErrorResponse { 110 return &GraphQLErrorResponse{} 111 }