Skip to content

Commit fc8a1ab

Browse files
Harlie Levinepivotal-saman-alvi
authored andcommitted
Add error handling for TooManyRequests API responses
[#147953573] Signed-off-by: Saman Alvi <[email protected]>
1 parent ae97481 commit fc8a1ab

File tree

5 files changed

+75
-11
lines changed

5 files changed

+75
-11
lines changed

errors.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,19 @@ func newErrUnavailableForLegalReasons(message string) ErrUnavailableForLegalReas
7777
Message: message,
7878
}
7979
}
80+
81+
type ErrTooManyRequests struct {
82+
ResponseCode int `json:"response_code" yaml:"response_code"`
83+
Message string `json:"message" yaml:"message"`
84+
}
85+
86+
func (e ErrTooManyRequests) Error() string {
87+
return e.Message
88+
}
89+
90+
func newErrTooManyRequests() ErrTooManyRequests {
91+
return ErrTooManyRequests{
92+
ResponseCode: http.StatusTooManyRequests,
93+
Message: "You have hit a rate limit for this request",
94+
}
95+
}

pivnet.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ func (c Client) handleUnexpectedResponse(resp *http.Response) error {
193193
return err
194194
}
195195

196+
if resp.StatusCode == http.StatusTooManyRequests {
197+
return newErrTooManyRequests()
198+
}
199+
196200
// We have to handle 500 differently because it has a different structure
197201
if resp.StatusCode == http.StatusInternalServerError {
198202
var internalServerError pivnetInternalServerErr

pivnet_test.go

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,25 @@ var _ = Describe("PivnetClient", func() {
187187
})
188188
})
189189

190-
Context("when making the request fails with error", func() {
191-
It("forwards the error", func() {
192-
newClientConfig.Host = "https://not-a-real-url.com"
193-
client = pivnet.NewClient(newClientConfig, fakeLogger)
190+
Context("when Pivnet returns a 401", func() {
191+
var (
192+
body []byte
193+
)
194+
195+
BeforeEach(func() {
196+
body = []byte(`{"message":"foo message"}`)
197+
})
198+
199+
It("returns an ErrUnauthorized error with message from Pivnet", func() {
200+
server.AppendHandlers(
201+
ghttp.CombineHandlers(
202+
ghttp.VerifyRequest(
203+
"GET",
204+
fmt.Sprintf("%s/foo", apiPrefix),
205+
),
206+
ghttp.RespondWith(http.StatusUnauthorized, body),
207+
),
208+
)
194209

195210
_, err := client.MakeRequest(
196211
"GET",
@@ -199,16 +214,22 @@ var _ = Describe("PivnetClient", func() {
199214
nil,
200215
)
201216
Expect(err).To(HaveOccurred())
217+
Expect(err).To(MatchError(
218+
pivnet.ErrUnauthorized{
219+
ResponseCode: http.StatusUnauthorized,
220+
Message: "foo message",
221+
},
222+
))
202223
})
203224
})
204225

205-
Context("when Pivnet returns a 401", func() {
226+
Context("when Pivnet returns a 429", func() {
206227
var (
207228
body []byte
208229
)
209230

210231
BeforeEach(func() {
211-
body = []byte(`{"message":"foo message"}`)
232+
body = []byte(`Retry later`)
212233
})
213234

214235
It("returns an ErrUnauthorized error with message from Pivnet", func() {
@@ -218,7 +239,7 @@ var _ = Describe("PivnetClient", func() {
218239
"GET",
219240
fmt.Sprintf("%s/foo", apiPrefix),
220241
),
221-
ghttp.RespondWith(http.StatusUnauthorized, body),
242+
ghttp.RespondWith(http.StatusTooManyRequests, body),
222243
),
223244
)
224245

@@ -230,9 +251,9 @@ var _ = Describe("PivnetClient", func() {
230251
)
231252
Expect(err).To(HaveOccurred())
232253
Expect(err).To(MatchError(
233-
pivnet.ErrUnauthorized{
234-
ResponseCode: http.StatusUnauthorized,
235-
Message: "foo message",
254+
pivnet.ErrTooManyRequests{
255+
ResponseCode: http.StatusTooManyRequests,
256+
Message: "You have hit a rate limit for this request",
236257
},
237258
))
238259
})

product_files.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,12 @@ func (p ProductFilesService) Create(config CreateProductFileConfig) (ProductFile
219219
bytes.NewReader(b),
220220
)
221221
if err != nil {
222-
return ProductFile{}, err
222+
_, ok := err.(ErrTooManyRequests)
223+
if ok {
224+
return ProductFile{}, fmt.Errorf("You have hit the file creation limit. Please wait before creating more files. Contact [email protected] with additional questions.")
225+
} else {
226+
return ProductFile{}, err
227+
}
223228
}
224229
defer resp.Body.Close()
225230

product_files_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,24 @@ var _ = Describe("PivnetClient - product files", func() {
527527
})
528528
})
529529

530+
Context("when the server responds with a 429 status code", func() {
531+
It("returns an error indicating the limit was hit", func() {
532+
server.AppendHandlers(
533+
ghttp.CombineHandlers(
534+
ghttp.VerifyRequest("POST", fmt.Sprintf(
535+
"%s/products/%s/product_files",
536+
apiPrefix,
537+
productSlug,
538+
)),
539+
ghttp.RespondWith(http.StatusTooManyRequests, "Retry later"),
540+
),
541+
)
542+
543+
_, err := client.ProductFiles.Create(createProductFileConfig)
544+
Expect(err.Error()).To(ContainSubstring("You have hit the file creation limit. Please wait before creating more files. Contact [email protected] with additional questions."))
545+
})
546+
})
547+
530548
Context("when the json unmarshalling fails with error", func() {
531549
It("forwards the error", func() {
532550
server.AppendHandlers(

0 commit comments

Comments
 (0)