Skip to content

Commit 4388803

Browse files
committed
update readme
1 parent 03017df commit 4388803

File tree

2 files changed

+65
-40
lines changed

2 files changed

+65
-40
lines changed

README.md

Lines changed: 63 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,55 @@ The goal of OpenAPI is to define a standard, language-agnostic interface to REST
99

1010
Check out [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) for additional information about the OpenAPI project, including additional libraries with support for other languages and more.
1111

12-
## How do I use this?
13-
14-
### Code Generation
12+
## Code Generation
1513

1614
Use [instructions](https://openapi-generator.tech/docs/generators) provided for the Julia OpenAPI code generator plugin to generate Julia code.
1715

1816
## Generated Code Structure
1917

18+
### Models
19+
20+
Each model from the specification is generated into a file named `model_<modelname>.jl`. It is represented as a `mutable struct` that is a subtype of the abstract type `APIModel`. Models have the following methods defined:
21+
22+
- constructor that takes keyword arguments to fill in values for all model properties.
23+
- [`propertynames`](https://docs.julialang.org/en/v1/base/base/#Base.propertynames)
24+
- [`hasproperty`](https://docs.julialang.org/en/v1/base/base/#Base.hasproperty)
25+
- [`getproperty`](https://docs.julialang.org/en/v1/base/base/#Base.getproperty)
26+
- [`setproperty!`](https://docs.julialang.org/en/v1/base/base/#Base.setproperty!)
27+
28+
In addition to these standard Julia methods, these convenience methods are also generated that help in checking value at a hierarchical path of the model.
29+
30+
- `function haspropertyat(o::T, path...) where {T<:APIModel}`
31+
- `function getpropertyat(o::T, path...) where {T<:APIModel}`
32+
33+
E.g:
34+
35+
```julia
36+
# access o.field.subfield1.subfield2
37+
if haspropertyat(o, "field", "subfield1", "subfield2")
38+
getpropertyat(o, "field", "subfield1", "subfield2")
39+
end
40+
41+
# access nested array elements, e.g. o.field2.subfield1[10].subfield2
42+
if haspropertyat(o, "field", "subfield1", 10, "subfield2")
43+
getpropertyat(o, "field", "subfield1", 10, "subfield2")
44+
end
45+
```
46+
47+
### Validations
48+
49+
Following validations are incorporated into models:
50+
51+
- maximum value: must be a numeric value less than or equal to a specified value
52+
- minimum value: must be a numeric value greater than or equal to a specified value
53+
- maximum length: must be a string value of length less than or equal to a specified value
54+
- minimum length: must be a string value of length greater than or equal to a specified value
55+
- maximum item count: must be a list value with number of items less than or equal to a specified value
56+
- minimum item count: must be a list value with number of items greater than or equal to a specified value
57+
- enum: value must be from a list of allowed values
58+
59+
Validations are imposed in the constructor and `setproperty!` methods of models.
60+
2061
### Client APIs
2162

2263
Each client API set is generated into a file named `api_<apiname>.jl`. It is represented as a `struct` and the APIs under it are generated as methods. An API set can be constructed by providing the OpenAPI client instance that it can use for communication.
@@ -78,45 +119,29 @@ An API call involves the following steps:
78119
- Convert (deserialize) the response data into the return type and return.
79120
- In case of any errors, throw an instance of `ApiException`
80121

81-
### Models
122+
## Server APIs
82123

83-
Each model from the specification is generated into a file named `model_<modelname>.jl`. It is represented as a `mutable struct` that is a subtype of the abstract type `APIModel`. Models have the following methods defined:
124+
The server code is generated as a package. It contains API stubs and validations of API inputs. It requires the caller to
125+
have implemented the APIs, the signatures of which are provided in the generated package module docstring.
84126

85-
- constructor that takes keyword arguments to fill in values for all model properties.
86-
- [`propertynames`](https://docs.julialang.org/en/v1/base/base/#Base.propertynames)
87-
- [`hasproperty`](https://docs.julialang.org/en/v1/base/base/#Base.hasproperty)
88-
- [`getproperty`](https://docs.julialang.org/en/v1/base/base/#Base.getproperty)
89-
- [`setproperty!`](https://docs.julialang.org/en/v1/base/base/#Base.setproperty!)
127+
A `register` function is made available that when provided with a `Router` instance, registers handlers
128+
for all the APIs.
90129

91-
In addition to these standard Julia methods, these convenience methods are also generated that help in checking value at a hierarchical path of the model.
130+
`register(router, impl; path_prefix="", optional_middlewares...) -> HTTP.Router`
92131

93-
- `function haspropertyat(o::T, path...) where {T<:APIModel}`
94-
- `function getpropertyat(o::T, path...) where {T<:APIModel}`
132+
Paramerets:
133+
- `router`: `HTTP.Router` to register handlers in, the same instance is also returned
134+
- `impl`: module that implements the server APIs
95135

96-
E.g:
136+
Optional parameters:
137+
- `path_prefix`: prefix to be applied to all paths
138+
- `optional_middlewares`: Register one or more optional middlewares to be applied to all requests.
97139

98-
```julia
99-
# access o.field.subfield1.subfield2
100-
if haspropertyat(o, "field", "subfield1", "subfield2")
101-
getpropertyat(o, "field", "subfield1", "subfield2")
102-
end
140+
Optional middlewares can be one or more of:
141+
- `init`: called before the request is processed
142+
- `pre_validation`: called after the request is parsed but before validation
143+
- `pre_invoke`: called after validation but before the handler is invoked
144+
- `post_invoke`: called after the handler is invoked but before the response is sent
103145

104-
# access nested array elements, e.g. o.field2.subfield1[10].subfield2
105-
if haspropertyat(o, "field", "subfield1", 10, "subfield2")
106-
getpropertyat(o, "field", "subfield1", 10, "subfield2")
107-
end
108-
```
109-
110-
### Validations
111-
112-
Following validations are incorporated into models:
113-
114-
- maximum value: must be a numeric value less than or equal to a specified value
115-
- minimum value: must be a numeric value greater than or equal to a specified value
116-
- maximum length: must be a string value of length less than or equal to a specified value
117-
- minimum length: must be a string value of length greater than or equal to a specified value
118-
- maximum item count: must be a list value with number of items less than or equal to a specified value
119-
- minimum item count: must be a list value with number of items greater than or equal to a specified value
120-
- enum: value must be from a list of allowed values
121-
122-
Validations are imposed in the constructor and `setproperty!` methods of models.
146+
The order in which middlewares are invoked are:
147+
`init |> read |> pre_validation |> validate |> pre_invoke |> invoke |> post_invoke`

src/val.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ const VAL_API_PARAM = Dict{Symbol,Function}([
4444
:enum => val_enum,
4545
])
4646

47-
function validate_param(param, operation, rule, value, args...)
47+
function validate_param(param, operation_or_model, rule, value, args...)
4848
# do not validate missing values
4949
(value === nothing) && return
5050

5151
VAL_API_PARAM[rule](value, args...) && return
5252

53-
msg = string("Invalid value ($value) of parameter ", param, " for ", operation, ", ", MSG_INVALID_API_PARAM[rule](args...))
53+
msg = string("Invalid value ($value) of parameter ", param, " for ", operation_or_model, ", ", MSG_INVALID_API_PARAM[rule](args...))
5454
throw(ValidationException(msg))
5555
end
5656

0 commit comments

Comments
 (0)