Skip to content

Commit 08da081

Browse files
authored
Use http library instead of chi (#48)
- Reduce the number of external dependencies by using standart http library instead of chi. - Use text/template for text based responses.
1 parent b242afc commit 08da081

File tree

11 files changed

+139
-133
lines changed

11 files changed

+139
-133
lines changed

.github/workflows/checks.yaml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,33 +26,33 @@ jobs:
2626

2727
steps:
2828
- name: Checkout repository
29-
uses: actions/checkout@v4
29+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
3030

3131
- name: Initialize CodeQL
32-
uses: github/codeql-action/init@v3
32+
uses: github/codeql-action/init@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4
3333
with:
3434
languages: go
3535

3636
- name: Perform CodeQL Analysis
37-
uses: github/codeql-action/analyze@v3
37+
uses: github/codeql-action/analyze@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # v3.27.4
3838

3939
UnitTests:
4040
runs-on: ubuntu-latest
4141

4242
steps:
4343
- name: Checkout repository
44-
uses: actions/checkout@v4
44+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
4545

4646
- name: Install Go
47-
uses: actions/setup-go@v5
47+
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
4848
with:
4949
go-version: ${{ env.GO }}
5050

5151
- name: Run Unit Tests
5252
run: go test -race -cover -coverprofile=coverage.out -covermode=atomic
5353

5454
- name: Codecov
55-
uses: codecov/[email protected]
55+
uses: codecov/codecov-action@985343d70564a82044c1b7fcb84c2fa05405c1a2 # v5.0.4
5656
with:
5757
file: ./coverage.out
5858

@@ -61,15 +61,14 @@ jobs:
6161

6262
steps:
6363
- name: Checkout repository
64-
uses: actions/checkout@v4
64+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
6565

6666
- name: Install Go
67-
uses: actions/setup-go@v5
67+
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
6868
with:
6969
go-version: ${{ env.GO }}
7070

7171
- name: Run GolangCi-Lint
72-
uses: golangci/[email protected]
72+
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
7373
with:
7474
version: latest
75-
skip-build-cache: true

.github/workflows/release.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ jobs:
1919
DOCKER_CLI_EXPERIMENTAL: "enabled"
2020
steps:
2121
- name: Checkout code
22-
uses: actions/checkout@v4
22+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
2323

2424
- name: Install Go
25-
uses: actions/setup-go@v5
25+
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
2626
with:
2727
go-version: ${{ env.GO }}
2828

@@ -43,7 +43,7 @@ jobs:
4343
password: ${{ secrets.DOCKER_HUB_TOKEN }}
4444

4545
- name: Run GoReleaser
46-
uses: goreleaser/goreleaser-action@v6
46+
uses: goreleaser/goreleaser-action@9ed2f89a662bf1735a48bc8557fd212fa902bebf # v6.1.0
4747
with:
4848
version: latest
4949
args: release --config .github/goreleaser-cli.yml

.golangci.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ linters:
55
enable: # keep in ascending order
66
- asciicheck
77
- bodyclose
8+
- copyloopvar
89
- dupl
910
- durationcheck
11+
- err113
1012
- exhaustive
11-
- exportloopref
1213
- gci
1314
- goconst
1415
- gocritic
15-
- goerr113
1616
- gofumpt
1717
- goprintffuncname
1818
- gosec
@@ -41,7 +41,10 @@ linters-settings:
4141
disable:
4242
- shadow
4343
gci:
44-
local-prefixes: github.com/sv-tools/mock-http-server
44+
sections:
45+
- standard
46+
- default
47+
- prefix(github.com/sv-tools/mock-http-server)
4548
gocognit:
4649
min-complexity: 15
4750
gocyclo:

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,23 @@
55

66
A simple HTTP Server to be used for the unit or end-to-end or integrations tests.
77
* yaml based configuration, see an [example config file](example_config.yaml).
8-
* docker image is published in this repo or docker hub
8+
* docker image is published in this repo and on the docker hub
9+
10+
## Usage
11+
12+
```shell
13+
docker run -p 8080:8080 -v $(pwd)/example_config.yaml:/config.yaml -e CONFIG=config.yaml ghcr.io/sv-tools/mock-http-server:latest
14+
```
15+
16+
in second shell
17+
```shell
18+
curl http://localhost:8080/users -H"X-Request-Id: 123"
19+
> {"id":1,"name":"John","id":2,"name":"Jane"}
20+
21+
curl http://localhost:8080/users/1 -H"X-Request-Id: 123"
22+
> {"id":1,"name":"John"}
23+
```
24+
925

1026
## License
1127

config.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package main
22

33
import (
4+
"bytes"
5+
"fmt"
46
"net/http"
57
"os"
8+
"text/template"
69

710
"golang.org/x/exp/slog"
811
)
@@ -14,7 +17,6 @@ type Config struct {
1417
}
1518

1619
type Route struct {
17-
Method string `json:"method,omitempty" yaml:"method,omitempty"`
1820
Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"`
1921
Responses []Response `json:"responses" yaml:"responses"`
2022
}
@@ -53,8 +55,12 @@ func responsesWriter(responses []Response, log *slog.Logger) http.HandlerFunc {
5355
http.Error(writer, err.Error(), http.StatusInternalServerError)
5456
return
5557
}
56-
} else if response.Body != "" {
57-
data = []byte(response.Body)
58+
} else if body := response.Body; body != "" {
59+
var err error
60+
data, err = executeTemplate(body, request)
61+
if err != nil {
62+
panic(err)
63+
}
5864
}
5965

6066
for name, header := range response.Headers {
@@ -71,10 +77,22 @@ func responsesWriter(responses []Response, log *slog.Logger) http.HandlerFunc {
7177

7278
if len(data) > 0 {
7379
if _, err := writer.Write(data); err != nil {
74-
log.Error("sending response failed", err)
80+
log.ErrorContext(request.Context(), "sending response failed", slog.String("error", err.Error()))
7581
}
7682
}
7783
return
7884
}
7985
}
8086
}
87+
88+
func executeTemplate(body string, request *http.Request) ([]byte, error) {
89+
tmpl, err := template.New("response").Parse(body)
90+
if err != nil {
91+
return nil, fmt.Errorf("parse template failed: %w", err)
92+
}
93+
buf := bytes.NewBuffer(nil)
94+
if err := tmpl.Execute(buf, request); err != nil {
95+
return nil, fmt.Errorf("execute template failed: %w", err)
96+
}
97+
return buf.Bytes(), nil
98+
}

config.schema.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@
2121
"items": {
2222
"type": "object",
2323
"properties": {
24-
"method": {
25-
"description": "The HTTP method, any of the standard or custom.",
26-
"default": "GET",
27-
"type": "string"
28-
},
2924
"pattern": {
3025
"description": "An url pattern",
3126
"default": "/",

example_config.yaml

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,46 @@
1+
request_id_header: "X-Request-ID" # to be logged if present in the request headers
12
routes:
2-
- method: get
3-
pattern: /users
3+
- pattern: GET /users # see https://go.dev/blog/routing-enhancements for more information about patterns
44
responses:
5-
- code: 200
5+
- code: 200 # first 3 responses: 200 OK
66
body: |
77
[
88
{
9-
"name": "foo"
9+
"id": 1,
10+
"name": "John"
1011
},
1112
{
12-
"name": "bar"
13+
"id": 2,
14+
"name": "Jane"
1315
}
1416
]
1517
is_json: true
1618
repeat: 3
17-
- code: 500
19+
- code: 500 # 4th response: 500 Internal Server Error
1820
repeat: 1
1921
body: "something is broken"
20-
- code: 200
22+
- code: 200 # all other responses: 200 OK
2123
body: |
2224
[
2325
{
24-
"name": "foo"
26+
"id": 1,
27+
"name": "John"
2528
},
2629
{
27-
"name": "bar"
30+
"id": 2,
31+
"name": "Jane"
2832
}
2933
]
3034
is_json: true
35+
- pattern: GET /users/{id}
36+
responses:
37+
- code: 200
38+
body: | # supports Go templates: https://pkg.go.dev/text/template
39+
{
40+
"id": "{{.PathValue "id"}}",
41+
"name": "John"
42+
}
43+
is_json: true
44+
repeat: 1
45+
- code: 404
46+
body: user "{{.PathValue "id"}}" not found

go.mod

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ module github.com/sv-tools/mock-http-server
33
go 1.23.0
44

55
require (
6-
github.com/go-chi/chi/v5 v5.1.0
76
github.com/spf13/pflag v1.0.5
8-
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948
7+
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f
98
gopkg.in/yaml.v3 v3.0.1
109
)

go.sum

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
2-
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
31
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
42
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
5-
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
6-
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
3+
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
4+
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
75
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
86
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
97
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

0 commit comments

Comments
 (0)