-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample_test.go
More file actions
170 lines (154 loc) · 6.46 KB
/
Copy pathexample_test.go
File metadata and controls
170 lines (154 loc) · 6.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package problemjson_test
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"net/http/httptest"
problemjson "lowbit.dev/problemjson"
)
// Example demonstrates creating an RFC 7807 Problem Details object from the canonical spec example.
func Example() {
p := problemjson.New(
problemjson.Type("https://example.com/probs/out-of-credit"),
problemjson.Title("You do not have enough credit."),
problemjson.Status(403),
problemjson.Detail("Your current balance is 30, but that costs 50."),
problemjson.Instance("/account/12345/msgs/abc"),
)
b, _ := json.Marshal(p)
fmt.Println(string(b))
// Output:
// {"detail":"Your current balance is 30, but that costs 50.","instance":"/account/12345/msgs/abc","status":403,"title":"You do not have enough credit.","type":"https://example.com/probs/out-of-credit"}
}
// ExampleProblem_MarshalJSON shows how the struct marshals to RFC 7807 JSON.
func ExampleProblem_MarshalJSON() {
p := &problemjson.Problem{
Type: "https://example.com/probs/resource-not-found",
Title: "Resource Not Found",
Status: http.StatusNotFound,
Detail: "The item does not exist.",
}
b, _ := json.Marshal(p)
fmt.Println(string(b))
// Output:
// {"detail":"The item does not exist.","status":404,"title":"Resource Not Found","type":"https://example.com/probs/resource-not-found"}
}
// ExampleProblem_Write shows writing a problem response to an http.ResponseWriter.
func ExampleProblem_Write() {
w := httptest.NewRecorder()
p := problemjson.NotFound()
_ = p.Write(w)
fmt.Println(w.Code)
fmt.Println(w.Header().Get("Content-Type"))
// Output:
// 404
// application/problem+json
}
// ExampleProblem_ServeHTTP shows using a Problem as an http.Handler.
// The request path is automatically assigned to Instance when not already set.
func ExampleProblem_ServeHTTP() {
p := problemjson.NotFound()
req := httptest.NewRequest(http.MethodGet, "/items/42", nil)
w := httptest.NewRecorder()
p.ServeHTTP(w, req)
fmt.Println(w.Code)
fmt.Println(w.Header().Get("Content-Type"))
// Output:
// 404
// application/problem+json
}
// ExampleDetailf shows overriding the default detail with a formatted string.
func ExampleDetailf() {
p := problemjson.TooManyRequests(problemjson.Detailf("Retry after %d seconds.", 60))
b, _ := json.Marshal(p)
fmt.Println(string(b))
// Output:
// {"detail":"Retry after 60 seconds.","status":429,"title":"Too Many Requests","type":"https://httpstatuscodes.io/429"}
}
// ExampleError wraps a Go error as the "reason" extension field.
func ExampleError() {
err := errors.New("connection refused")
p := problemjson.InternalServerError(problemjson.Error(err))
b, _ := json.Marshal(p)
fmt.Println(string(b))
// Output:
// {"detail":"The server encountered an internal error and was unable to complete your request.","reason":"connection refused","status":500,"title":"Internal Server Error","type":"https://httpstatuscodes.io/500"}
}
// ExampleFrom shows deriving a problem from a reusable base, overriding only what differs.
func ExampleFrom() {
base := problemjson.NotFound()
p := problemjson.From(base, problemjson.Detail("Order with ID 99 was not found."))
b, _ := json.Marshal(p)
fmt.Println(string(b))
// Output:
// {"detail":"Order with ID 99 was not found.","status":404,"title":"Not Found","type":"https://httpstatuscodes.io/404"}
}
// ExampleInstanceFromRequest sets the instance field from the incoming request path.
func ExampleInstanceFromRequest() {
req := httptest.NewRequest(http.MethodGet, "/users/99", nil)
p := problemjson.NotFound(problemjson.InstanceFromRequest(req))
b, _ := json.Marshal(p)
fmt.Println(string(b))
// Output:
// {"detail":"The requested resource could not be found.","instance":"/users/99","status":404,"title":"Not Found","type":"https://httpstatuscodes.io/404"}
}
// ExampleInternalServerError shows attaching a specific instance URI to a 500 response.
func ExampleInternalServerError() {
p := problemjson.InternalServerError(problemjson.Instance("/ops/request/xyz"))
b, _ := json.Marshal(p)
fmt.Println(string(b))
// Output:
// {"detail":"The server encountered an internal error and was unable to complete your request.","instance":"/ops/request/xyz","status":500,"title":"Internal Server Error","type":"https://httpstatuscodes.io/500"}
}
// ExampleNew shows building a custom problem type with the functional-options builder.
func ExampleNew() {
p := problemjson.New(
problemjson.Type("https://example.com/probs/insufficient-permissions"),
problemjson.Title("Insufficient Permissions"),
problemjson.Status(http.StatusForbidden),
problemjson.Detail("You need admin privileges to perform this action."),
)
b, _ := json.Marshal(p)
fmt.Println(string(b))
// Output:
// {"detail":"You need admin privileges to perform this action.","status":403,"title":"Insufficient Permissions","type":"https://example.com/probs/insufficient-permissions"}
}
// ExampleNotFound shows the convenience constructor with a custom detail override.
func ExampleNotFound() {
p := problemjson.NotFound(problemjson.Detail("Order 99 does not exist."))
b, _ := json.Marshal(p)
fmt.Println(string(b))
// Output:
// {"detail":"Order 99 does not exist.","status":404,"title":"Not Found","type":"https://httpstatuscodes.io/404"}
}
// ExampleTitlef shows overriding the default title with a formatted string.
func ExampleTitlef() {
p := problemjson.NotFound(problemjson.Titlef("User %d not found", 42))
b, _ := json.Marshal(p)
fmt.Println(string(b))
// Output:
// {"detail":"The requested resource could not be found.","status":404,"title":"User 42 not found","type":"https://httpstatuscodes.io/404"}
}
// ExampleTypef shows building a typed problem URL with a formatted string.
func ExampleTypef() {
p := problemjson.New(
problemjson.Typef("https://example.com/probs/%s", "resource-not-found"),
problemjson.Title("Resource Not Found"),
problemjson.Status(http.StatusNotFound),
)
b, _ := json.Marshal(p)
fmt.Println(string(b))
// Output:
// {"status":404,"title":"Resource Not Found","type":"https://example.com/probs/resource-not-found"}
}
// ExampleWith shows attaching structured extension fields to a problem.
func ExampleWith() {
p := problemjson.UnprocessableEntity(
problemjson.With("violations", []string{"name is required", "email is invalid"}),
)
b, _ := json.Marshal(p)
fmt.Println(string(b))
// Output:
// {"detail":"The request was well-formed but could not be followed due to semantic errors.","status":422,"title":"Unprocessable Entity","type":"https://httpstatuscodes.io/422","violations":["name is required","email is invalid"]}
}