Skip to content

Commit 7f66c89

Browse files
authored
add functional options for adding/removing headers (#57)
1 parent 504ba6f commit 7f66c89

File tree

3 files changed

+793
-3
lines changed

3 files changed

+793
-3
lines changed

runnables/httpserver/middleware/headers/headers.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,18 @@ func JSON() httpserver.HandlerFunc {
5656
// // Development setup with all methods
5757
// CORS("http://localhost:3000", "GET,POST,PUT,PATCH,DELETE,OPTIONS", "*")
5858
func CORS(allowOrigin, allowMethods, allowHeaders string) httpserver.HandlerFunc {
59-
headers := HeaderMap{
59+
corsHeaders := HeaderMap{
6060
"Access-Control-Allow-Origin": allowOrigin,
6161
"Access-Control-Allow-Methods": allowMethods,
6262
"Access-Control-Allow-Headers": allowHeaders,
6363
}
6464

6565
// Add credentials header if origin is not wildcard
6666
if allowOrigin != "*" {
67-
headers["Access-Control-Allow-Credentials"] = "true"
67+
corsHeaders["Access-Control-Allow-Credentials"] = "true"
6868
}
6969

70-
return New(headers)
70+
return NewWithOperations(WithSet(corsHeaders))
7171
}
7272

7373
// Security creates a middleware that sets common security headers.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package headers
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/robbyt/go-supervisor/runnables/httpserver"
7+
)
8+
9+
// HeaderOperation represents a single header manipulation operation
10+
type HeaderOperation func(*headerOperations)
11+
12+
type headerOperations struct {
13+
setHeaders http.Header
14+
addHeaders http.Header
15+
removeHeaders []string
16+
}
17+
18+
// WithSet creates an operation to set (replace) headers
19+
func WithSet(headers HeaderMap) HeaderOperation {
20+
return func(ops *headerOperations) {
21+
if ops.setHeaders == nil {
22+
ops.setHeaders = make(http.Header)
23+
}
24+
for key, value := range headers {
25+
ops.setHeaders.Set(key, value)
26+
}
27+
}
28+
}
29+
30+
// WithSetHeader creates an operation to set a single header
31+
func WithSetHeader(key, value string) HeaderOperation {
32+
return func(ops *headerOperations) {
33+
if ops.setHeaders == nil {
34+
ops.setHeaders = make(http.Header)
35+
}
36+
ops.setHeaders.Set(key, value)
37+
}
38+
}
39+
40+
// WithAdd creates an operation to add (append) headers
41+
func WithAdd(headers HeaderMap) HeaderOperation {
42+
return func(ops *headerOperations) {
43+
if ops.addHeaders == nil {
44+
ops.addHeaders = make(http.Header)
45+
}
46+
for key, value := range headers {
47+
ops.addHeaders.Add(key, value)
48+
}
49+
}
50+
}
51+
52+
// WithAddHeader creates an operation to add a single header
53+
func WithAddHeader(key, value string) HeaderOperation {
54+
return func(ops *headerOperations) {
55+
if ops.addHeaders == nil {
56+
ops.addHeaders = make(http.Header)
57+
}
58+
ops.addHeaders.Add(key, value)
59+
}
60+
}
61+
62+
// WithRemove creates an operation to remove headers
63+
func WithRemove(headerNames ...string) HeaderOperation {
64+
return func(ops *headerOperations) {
65+
ops.removeHeaders = append(ops.removeHeaders, headerNames...)
66+
}
67+
}
68+
69+
// NewWithOperations creates a middleware with full header control using functional options.
70+
// Operations are executed in order: remove → set → add
71+
func NewWithOperations(operations ...HeaderOperation) httpserver.HandlerFunc {
72+
ops := &headerOperations{}
73+
for _, operation := range operations {
74+
operation(ops)
75+
}
76+
77+
return func(rp *httpserver.RequestProcessor) {
78+
writer := rp.Writer()
79+
80+
// 1. Remove headers first
81+
for _, key := range ops.removeHeaders {
82+
writer.Header().Del(key)
83+
}
84+
85+
// 2. Set headers (replace)
86+
for key, values := range ops.setHeaders {
87+
if len(values) > 0 {
88+
writer.Header().Set(key, values[0])
89+
}
90+
}
91+
92+
// 3. Add headers (append)
93+
for key, values := range ops.addHeaders {
94+
for _, value := range values {
95+
writer.Header().Add(key, value)
96+
}
97+
}
98+
99+
rp.Next()
100+
}
101+
}

0 commit comments

Comments
 (0)