Skip to content

Commit 04a4a1f

Browse files
authored
refactor: adopt lua-resty-etcd code style conventions (#2)
1 parent 279e47d commit 04a4a1f

17 files changed

Lines changed: 530 additions & 409 deletions

.github/workflows/test.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,8 @@ jobs:
4141
run: |
4242
export PATH=$OPENRESTY_PREFIX/nginx/sbin:$OPENRESTY_PREFIX/bin:$PATH
4343
make test
44+
45+
- name: Lint
46+
run: |
47+
sudo luarocks install luacheck
48+
make lint

.luacheckrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
std = "ngx_lua"
2+
ignore = {
3+
"542", -- empty if branch
4+
}
5+
redefined = false

Makefile

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,51 @@
1-
.PHONY: test test-unit test-conformance benchmark lint clean
1+
INST_PREFIX ?= /usr/local/openresty
2+
INST_LUADIR ?= $(INST_PREFIX)/lualib
3+
INSTALL ?= install
24

35
RESTY := /usr/local/openresty/bin/resty --shdict "test 1m"
46

57
UNIT_TESTS := $(sort $(wildcard t/unit/test_*.lua))
68
CONFORMANCE_TESTS := $(sort $(wildcard t/conformance/test_*.lua))
79

10+
.PHONY: test test-unit test-conformance benchmark lint dev install clean help
11+
12+
### help: Show Makefile rules
13+
help:
14+
@echo Makefile rules:
15+
@echo
16+
@grep -E '^### [-A-Za-z0-9_]+:' Makefile | sed 's/###/ /'
17+
18+
### dev: Create a development ENV
19+
dev:
20+
luarocks install rockspec/lua-resty-openapi-validator-master-0.1-0.rockspec --only-deps --local
21+
22+
### install: Install the library to runtime
23+
install:
24+
$(INSTALL) -d $(INST_LUADIR)/resty/openapi_validator/
25+
$(INSTALL) lib/resty/openapi_validator/*.lua $(INST_LUADIR)/resty/openapi_validator/
26+
27+
### test: Run all tests
828
test: test-unit test-conformance
929
@echo "All tests passed."
1030

31+
### test-unit: Run unit tests
1132
test-unit:
1233
@echo "=== Unit tests ==="
1334
@for f in $(UNIT_TESTS); do $(RESTY) -e "dofile('$$f')" || exit 1; done
1435

36+
### test-conformance: Run conformance tests
1537
test-conformance:
1638
@echo "=== Conformance tests ==="
1739
@for f in $(CONFORMANCE_TESTS); do $(RESTY) -e "dofile('$$f')" || exit 1; done
1840

41+
### benchmark: Run microbenchmark
1942
benchmark:
2043
@$(RESTY) -e 'dofile("benchmark/bench.lua")'
2144

45+
### lint: Lint Lua source code
2246
lint:
23-
@luacheck lib/ --std ngx_lua
47+
luacheck -q lib/
2448

49+
### clean: Remove build artifacts
2550
clean:
26-
@rm -rf *.rock benchmark/logs/ benchmark/nginx.conf
51+
rm -rf *.rock benchmark/logs/ benchmark/nginx.conf

README.md

Lines changed: 70 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,66 @@
1-
# lua-resty-openapi-validator
1+
Name
2+
====
23

3-
Pure Lua OpenAPI request validator for OpenResty / LuaJIT.
4+
lua-resty-openapi-validator - Pure Lua OpenAPI request validator for OpenResty / LuaJIT.
5+
6+
![CI](https://github.com/api7/lua-resty-openapi-validator/actions/workflows/test.yml/badge.svg)
7+
![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)
8+
9+
Table of Contents
10+
=================
11+
12+
* [Description](#description)
13+
* [Install](#install)
14+
* [Quick Start](#quick-start)
15+
* [API](api.md)
16+
* [Validation Scope](#validation-scope)
17+
* [OpenAPI 3.1 Support](#openapi-31-support)
18+
* [Benchmark](#benchmark)
19+
* [Testing](#testing)
20+
21+
Description
22+
===========
423

524
Validates HTTP requests against OpenAPI 3.0 and 3.1 specifications using
625
[lua-resty-radixtree](https://github.com/api7/lua-resty-radixtree) for path
726
matching and [api7/jsonschema](https://github.com/api7/jsonschema) for schema
827
validation. No Go FFI or external processes required.
928

10-
## Performance
29+
Install
30+
=======
1131

12-
**~45% higher throughput** than the Go FFI-based validator under concurrent load
13-
(single worker, 50 connections). See [benchmark/RESULTS.md](benchmark/RESULTS.md).
32+
> Dependencies
1433
15-
## Installation
34+
- [api7/jsonschema](https://github.com/api7/jsonschema) — JSON Schema Draft 4/6/7 validation
35+
- [lua-resty-radixtree](https://github.com/api7/lua-resty-radixtree) — radix tree path routing
36+
- [lua-cjson](https://github.com/openresty/lua-cjson) — JSON encoding/decoding
37+
38+
> install by luarocks
1639
17-
```bash
40+
```shell
1841
luarocks install lua-resty-openapi-validator
1942
```
2043

21-
Or add the `lib/` directory to your `lua_package_path`.
44+
> install by source
2245
23-
### Dependencies
46+
```shell
47+
git clone https://github.com/api7/lua-resty-openapi-validator.git
48+
cd lua-resty-openapi-validator
49+
make dev
50+
sudo make install
51+
```
2452

25-
- [api7/jsonschema](https://github.com/api7/jsonschema) — JSON Schema Draft 4/6/7 validation
26-
- [lua-resty-radixtree](https://github.com/api7/lua-resty-radixtree) — radix tree path routing
27-
- [lua-cjson](https://github.com/openresty/lua-cjson) — JSON encoding/decoding
53+
[Back to TOC](#table-of-contents)
2854

29-
## Quick Start
55+
Quick Start
56+
===========
3057

3158
```lua
3259
local ov = require("resty.openapi_validator")
3360

3461
-- compile once (cache the result)
3562
local validator, err = ov.compile(spec_json_string, {
36-
strict = true, -- error on unsupported 3.1 keywords (default: true)
37-
coerce_types = true, -- coerce query/header string values to schema types (default: true)
38-
fail_fast = false, -- return on first error (default: false)
63+
strict = true, -- error on unsupported 3.1 keywords (default: true)
3964
})
4065
if not validator then
4166
ngx.log(ngx.ERR, "spec compile error: ", err)
@@ -59,38 +84,37 @@ if not ok then
5984
end
6085
```
6186

62-
### Selective Validation
87+
See [API documentation](api.md) for details on all methods and options.
6388

64-
Skip specific validation steps:
89+
[Back to TOC](#table-of-contents)
6590

66-
```lua
67-
local ok, err = validator:validate_request(req, {
68-
skip_query = true, -- skip query parameter validation
69-
skip_body = true, -- skip request body validation
70-
})
71-
```
72-
73-
## Validation Scope
91+
Validation Scope
92+
================
7493

7594
| Feature | Status |
7695
|---|---|
7796
| Path parameter matching & validation ||
7897
| Query parameter validation (with type coercion) ||
7998
| Header validation ||
8099
| Request body validation (JSON) ||
100+
| Request body validation (form-urlencoded) ||
81101
| `style` / `explode` parameter serialization ||
82102
| `$ref` resolution (document-internal) ||
83103
| Circular `$ref` support ||
84104
| `allOf` / `oneOf` / `anyOf` composition ||
85105
| `additionalProperties` ||
86106
| OpenAPI 3.0 `nullable` ||
87107
| OpenAPI 3.1 type arrays (`["string", "null"]`) ||
108+
| `readOnly` / `writeOnly` validation ||
88109
| Response validation | ❌ (not planned for v1) |
89110
| Security scheme validation ||
90111
| External `$ref` (URLs, files) ||
91-
| `multipart/form-data` body | ⚠️ (skipped, returns OK) |
112+
| `multipart/form-data` body | ⚠️ basic support |
113+
114+
[Back to TOC](#table-of-contents)
92115

93-
## OpenAPI 3.1 Support
116+
OpenAPI 3.1 Support
117+
===================
94118

95119
OpenAPI 3.1 uses JSON Schema Draft 2020-12. Since the underlying jsonschema
96120
library supports up to Draft 7, schemas are normalized at compile time:
@@ -104,15 +128,29 @@ library supports up to Draft 7, schemas are normalized at compile time:
104128
| `$ref` with sibling keywords |`allOf: [resolved, {siblings}]` |
105129
| `$dynamicRef`, `unevaluatedProperties` | Error (strict) / Warning (lenient) |
106130

107-
## Testing
131+
[Back to TOC](#table-of-contents)
132+
133+
Benchmark
134+
=========
108135

109-
```bash
136+
**~45% higher throughput** than the Go FFI-based validator under concurrent load
137+
(single worker, 50 connections). See [benchmark/RESULTS.md](benchmark/RESULTS.md).
138+
139+
[Back to TOC](#table-of-contents)
140+
141+
Testing
142+
=======
143+
144+
```shell
110145
make test
111146
```
112147

113-
Runs 200 tests across unit tests and conformance tests ported from
148+
Runs unit tests and conformance tests ported from
114149
[kin-openapi](https://github.com/getkin/kin-openapi).
115150

116-
## License
151+
[Back to TOC](#table-of-contents)
152+
153+
License
154+
=======
117155

118156
Apache 2.0

api.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
API
2+
===
3+
4+
Table of Contents
5+
=================
6+
7+
* [compile](#compile)
8+
* [validate_request](#validate_request)
9+
10+
compile
11+
-------
12+
13+
`syntax: validator, err = ov.compile(spec_str, opts)`
14+
15+
Compiles an OpenAPI specification JSON string into a reusable validator object.
16+
The spec is parsed, `$ref` pointers are resolved, and schemas are normalized to
17+
JSON Schema Draft 7. The returned validator should be cached and reused across
18+
requests.
19+
20+
- `spec_str`: string — raw JSON of an OpenAPI 3.0 or 3.1 specification.
21+
- `opts`: table (optional) — compilation options:
22+
- `strict`: boolean (default `true`) — if `true`, returns an error when
23+
unsupported OpenAPI 3.1 keywords are encountered (`$dynamicRef`,
24+
`unevaluatedProperties`, etc.); if `false`, these keywords are silently
25+
dropped with a warning.
26+
27+
Returns a validator object on success, or `nil` and an error string on failure.
28+
29+
```lua
30+
local ov = require("resty.openapi_validator")
31+
32+
local validator, err = ov.compile(spec_json, { strict = true })
33+
if not validator then
34+
ngx.log(ngx.ERR, "compile: ", err)
35+
return
36+
end
37+
```
38+
39+
[Back to TOC](#table-of-contents)
40+
41+
validate_request
42+
----------------
43+
44+
`syntax: ok, err = validator:validate_request(req, skip)`
45+
46+
Validates an incoming HTTP request against the compiled OpenAPI spec. Returns
47+
`true` on success, or `false` and a formatted error string on failure.
48+
49+
- `req`: table — request data with the following fields:
50+
- `method`: string (required) — HTTP method (e.g. `"GET"`, `"POST"`)
51+
- `path`: string (required) — request URI path (e.g. `"/users/123"`)
52+
- `query`: table (optional) — query parameters `{ name = value | {values} }`
53+
- `headers`: table (optional) — request headers `{ name = value }`
54+
- `body`: string (optional) — raw request body
55+
- `content_type`: string (optional) — Content-Type header value
56+
57+
- `skip`: table (optional) — selectively skip validation steps:
58+
- `path`: boolean — skip path parameter validation
59+
- `query`: boolean — skip query parameter validation
60+
- `header`: boolean — skip header validation
61+
- `body`: boolean — skip request body validation
62+
- `read_only`: boolean — skip readOnly property checks in request body
63+
- `write_only`: boolean — skip writeOnly property checks
64+
65+
```lua
66+
local ok, err = validator:validate_request({
67+
method = ngx.req.get_method(),
68+
path = ngx.var.uri,
69+
query = ngx.req.get_uri_args(),
70+
headers = ngx.req.get_headers(0, true),
71+
body = ngx.req.get_body_data(),
72+
content_type = ngx.var.content_type,
73+
})
74+
75+
if not ok then
76+
ngx.status = 400
77+
ngx.say(err)
78+
return
79+
end
80+
```
81+
82+
Skip specific validation:
83+
84+
```lua
85+
local ok, err = validator:validate_request(req, {
86+
body = true, -- skip body validation
87+
read_only = true, -- skip readOnly checks
88+
})
89+
```
90+
91+
[Back to TOC](#table-of-contents)

0 commit comments

Comments
 (0)