Skip to content

Commit 0275965

Browse files
committed
Add rate limit logic
1 parent cc92fe8 commit 0275965

File tree

4 files changed

+139
-1
lines changed

4 files changed

+139
-1
lines changed

client.go

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package temp_mail_go
22

3-
import "net/http"
3+
import (
4+
"context"
5+
"encoding/json"
6+
"io"
7+
"net/http"
8+
)
49

510
type doer interface {
611
Do(req *http.Request) (*http.Response, error)
@@ -14,6 +19,8 @@ type Client struct {
1419
apiKey string
1520
}
1621

22+
const baseURL = "https://api.temp-mail.io"
23+
1724
// NewClient creates ready to use Client.
1825
func NewClient(apiKey string, client *http.Client) *Client {
1926
if client == nil {
@@ -24,3 +31,38 @@ func NewClient(apiKey string, client *http.Client) *Client {
2431
apiKey: apiKey,
2532
}
2633
}
34+
35+
// newRequest creates a new HTTP request.
36+
func (c *Client) newRequest(ctx context.Context, method, path string, body io.Reader) (*http.Request, error) {
37+
req, err := http.NewRequestWithContext(ctx, method, baseURL+path, body)
38+
if err != nil {
39+
return nil, err
40+
}
41+
req.Header.Set("X-API-Key", c.apiKey)
42+
return req, nil
43+
}
44+
45+
// do sends an HTTP request and decodes the response.
46+
func (c *Client) do(req *http.Request, v interface{}) error {
47+
resp, err := c.doer.Do(req)
48+
if err != nil {
49+
return err
50+
}
51+
defer resp.Body.Close()
52+
53+
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
54+
var httpErr HTTPError
55+
if err := json.NewDecoder(resp.Body).Decode(&httpErr); err != nil {
56+
return err
57+
}
58+
return &httpErr
59+
}
60+
61+
if v != nil {
62+
if err := json.NewDecoder(resp.Body).Decode(v); err != nil {
63+
return err
64+
}
65+
}
66+
67+
return nil
68+
}

error.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package temp_mail_go
2+
3+
import (
4+
"fmt"
5+
"io"
6+
)
7+
8+
// HTTPError is the error response that will be returned by the API.
9+
type HTTPError struct {
10+
ErrorDetails HTTPErrorError `json:"error"`
11+
Meta HTTPErrorMeta `json:"meta"`
12+
}
13+
14+
type HTTPErrorError struct {
15+
// Type is the type of the error.
16+
// Possible values: api_error, request_error.
17+
Type string `json:"type"`
18+
// Code is the error code.
19+
Code string `json:"code"`
20+
// Detail is the error message.
21+
Detail string `json:"detail"`
22+
}
23+
24+
type HTTPErrorMeta struct {
25+
RequestID string `json:"request_id"`
26+
}
27+
28+
func (h *HTTPError) Error() string {
29+
return fmt.Sprintf("error: %s, code: %s, detail: %s", h.ErrorDetails.Type, h.ErrorDetails.Code, h.ErrorDetails.Detail)
30+
}
31+
32+
func (h *HTTPError) fullError() string {
33+
return fmt.Sprintf("error: %s, code: %s, detail: %s, request_id: %s", h.ErrorDetails.Type, h.ErrorDetails.Code, h.ErrorDetails.Detail, h.Meta.RequestID)
34+
}
35+
36+
// Format implements fmt.Formatter interface.
37+
// It adds request ID to the error message when called with %+v verb.
38+
func (h *HTTPError) Format(s fmt.State, verb rune) {
39+
switch verb {
40+
case 'v':
41+
if s.Flag('+') {
42+
_, _ = io.WriteString(s, h.fullError())
43+
return
44+
}
45+
fallthrough
46+
case 's':
47+
_, _ = io.WriteString(s, h.Error())
48+
case 'q':
49+
_, _ = fmt.Fprintf(s, "%q", h.Error())
50+
}
51+
}

example_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package temp_mail_go
2+
3+
import (
4+
"context"
5+
"fmt"
6+
)
7+
8+
func ExampleClient_RateLimit() {
9+
c := NewClient("YOUR_API_KEY", nil)
10+
resp, err := c.RateLimit(context.Background())
11+
if err != nil {
12+
panic(err)
13+
}
14+
fmt.Printf("limit: %d, used: %d, remaining: %d, reset: %d", resp.Limit, resp.Used, resp.Remaining, resp.Reset)
15+
// Output: limit: 1000, used: 0, remaining: 1000, reset: 1738367999
16+
}

rate_limit.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package temp_mail_go
2+
3+
import "context"
4+
5+
type RateLimitResponse struct {
6+
// Limit is the maximum number of requests that you can make per period.
7+
Limit int64 `json:"limit"`
8+
// Used is the number of requests you have made in the current rate limit window.
9+
Used int64 `json:"used"`
10+
// Remaining is the number of requests remaining in the current rate limit window.
11+
Remaining int64 `json:"remaining"`
12+
// Reset is the time at which the current rate limit window resets, in UTC epoch seconds.
13+
Reset int64 `json:"reset"`
14+
}
15+
16+
// RateLimit returns the current rate limit for the client.
17+
func (c *Client) RateLimit(ctx context.Context) (RateLimitResponse, error) {
18+
req, err := c.newRequest(ctx, "GET", "/v1/rate_limit", nil)
19+
if err != nil {
20+
return RateLimitResponse{}, err
21+
}
22+
23+
var resp RateLimitResponse
24+
if err := c.do(req, &resp); err != nil {
25+
return RateLimitResponse{}, err
26+
}
27+
28+
return resp, nil
29+
}

0 commit comments

Comments
 (0)