Skip to content

Commit

Permalink
Merge pull request #9 from eWaterCycle/nested-string-response
Browse files Browse the repository at this point in the history
Nested string response
  • Loading branch information
sverhoeven committed Sep 25, 2024
2 parents 4dc8b6b + bf5105c commit ff8a468
Show file tree
Hide file tree
Showing 24 changed files with 456 additions and 98 deletions.
9 changes: 2 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,12 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install Redocly
run: npm install -g @redocly/cli@latest

- name: Lint OpenAPI with Redocly
run: redocly lint openapi.yaml

- name: Install spectral
run: npm install -g @stoplight/spectral-cli
run: npx --package @redocly/cli@latest redocly lint openapi.yaml

- name: Lint OpenAPI with Spectral
run: spectral lint openapi.yaml
run: npx --package @stoplight/spectral-cli spectral lint openapi.yaml

- name: Setup Python
uses: actions/setup-python@v5
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@ __pycache__
/venv
python/.venv/
python/heat.toml
RemoteBMI.jl/example/Project.toml
RemoteBMI.jl/example/Project.toml
RemoteBMI.jl/example/heat.toml
openapi-generator-cli.jar
openapitools.json
3 changes: 2 additions & 1 deletion RemoteBMI.jl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ BestieTemplate.generate("RemoteBMI.jl")
The openapi server stubs where generated using the following command:

```shell
npx @openapitools/openapi-generator-cli generate -i ./openapi.yaml -g julia-server -o julia-server --additional-properties=packageName=BmiServer --additional-properties=exportModels=true
wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.8.0/openapi-generator-cli-7.8.0.jar -O openapi-generator-cli.jar
java -jar ./openapi-generator-cli.jar generate -i ./openapi.yaml -g julia-server -o julia-server --additional-properties=packageName=BmiServer --additional-properties=exportModels=true
# Copy the generated files to RemoteBMI.jl/src/
```
17 changes: 14 additions & 3 deletions RemoteBMI.jl/example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ add https://github.com/csdms/bmi-example-julia#b5d963e6bf864f5d42769e6cc0814dd7b
dev ..
CTRL-D
# Run server
export BMI_SERVER_PORT=50555
export BMI_PORT=50555
julia --project=$PWD heat_bmi_server.jl
```

Expand All @@ -24,16 +24,27 @@ Interact with it using the Python client.

```python
from remotebmi.client.client import RemoteBmiClient
from remotebmi.client.reserve import reserve_values
from remotebmi.reserve import reserve_values

client = RemoteBmiClient('http://localhost:50555')
# TODO use placeholder for path
# client.initialize('<absolute path>/heat.toml')
client.initialize('/home/stefanv/git/eWaterCycle/remotebmi/python/heat.toml')
# TODO Julia server throws error here
client.get_component_name()
'The 2D Heat Equation'
client.update()
client.get_current_time()
0.25
client.get_time_units()
's'
client.get_var_location('plate_surface__temperature')
'node'
client.get_var_type('plate_surface__temperature')
numpy.float64
client.get_var_grid('plate_surface__temperature')
0
client.get_grid_type(0)
'uniform_rectilinear'
dest = reserve_values(client, 'plate_surface__temperature')
r = client.get_value('plate_surface__temperature', dest)
r
Expand Down
24 changes: 14 additions & 10 deletions RemoteBMI.jl/src/BmiServer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The following server methods must be implemented:
- **get_component_name**
- *invocation:* GET /get_component_name
- *signature:* get_component_name(req::HTTP.Request;) -> String
- *signature:* get_component_name(req::HTTP.Request;) -> GetComponentNameResponse
- **get_input_item_count**
- *invocation:* GET /get_input_item_count
- *signature:* get_input_item_count(req::HTTP.Request;) -> Int64
Expand All @@ -36,13 +36,13 @@ The following server methods must be implemented:
- *signature:* get_grid_size(req::HTTP.Request, grid::Int64;) -> Int64
- **get_grid_type**
- *invocation:* GET /get_grid_type/{grid}
- *signature:* get_grid_type(req::HTTP.Request, grid::Int64;) -> BmiGetGridTypeResponse
- *signature:* get_grid_type(req::HTTP.Request, grid::Int64;) -> GetGridTypeResponse
- **finalize**
- *invocation:* DELETE /finalize
- *signature:* finalize(req::HTTP.Request;) -> Nothing
- **initialize**
- *invocation:* POST /initialize
- *signature:* initialize(req::HTTP.Request, bmi_initialize_request::BmiInitializeRequest;) -> Nothing
- *signature:* initialize(req::HTTP.Request, initialize_request::InitializeRequest;) -> Nothing
- **update**
- *invocation:* POST /update
- *signature:* update(req::HTTP.Request;) -> Nothing
Expand All @@ -63,7 +63,7 @@ The following server methods must be implemented:
- *signature:* set_value(req::HTTP.Request, name::String, request_body::Vector{Float64};) -> Nothing
- **set_value_at_indices**
- *invocation:* POST /set_value_at_indices/{name}
- *signature:* set_value_at_indices(req::HTTP.Request, name::String, bmi_set_value_at_indices_request::BmiSetValueAtIndicesRequest;) -> Nothing
- *signature:* set_value_at_indices(req::HTTP.Request, name::String, set_value_at_indices_request::SetValueAtIndicesRequest;) -> Nothing
- **get_current_time**
- *invocation:* GET /get_current_time
- *signature:* get_current_time(req::HTTP.Request;) -> Float64
Expand All @@ -78,7 +78,7 @@ The following server methods must be implemented:
- *signature:* get_time_step(req::HTTP.Request;) -> Float64
- **get_time_units**
- *invocation:* GET /get_time_units
- *signature:* get_time_units(req::HTTP.Request;) -> String
- *signature:* get_time_units(req::HTTP.Request;) -> GetTimeUnitsResponse
- **get_grid_origin**
- *invocation:* GET /get_grid_origin/{grid}
- *signature:* get_grid_origin(req::HTTP.Request, grid::Int64;) -> Vector{Float64}
Expand Down Expand Up @@ -123,10 +123,10 @@ The following server methods must be implemented:
- *signature:* get_var_nbytes(req::HTTP.Request, name::String;) -> Int64
- **get_var_type**
- *invocation:* GET /get_var_type/{name}
- *signature:* get_var_type(req::HTTP.Request, name::String;) -> String
- *signature:* get_var_type(req::HTTP.Request, name::String;) -> GetVarTypeResponse
- **get_var_units**
- *invocation:* GET /get_var_units/{name}
- *signature:* get_var_units(req::HTTP.Request, name::String;) -> String
- *signature:* get_var_units(req::HTTP.Request, name::String;) -> GetVarUnitsResponse
"""
module BmiServer

Expand Down Expand Up @@ -187,10 +187,14 @@ function register(router::HTTP.Router, impl; path_prefix::String="", optional_mi
end

# export models
export BmiGetGridTypeResponse
export BmiInitializeRequest
export BmiSetValueAtIndicesRequest
export GetComponentNameResponse
export GetGridTypeResponse
export GetTimeUnitsResponse
export GetVarLocationResponseLocation
export GetVarTypeResponse
export GetVarUnitsResponse
export InitializeRequest
export ProblemDetails
export SetValueAtIndicesRequest

end # module BmiServer
35 changes: 19 additions & 16 deletions RemoteBMI.jl/src/RemoteBMI.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import BasicModelInterface as BMI

# TODO move route implementations to own module

function initialize(req::HTTP.Request, bmi_initialize_request::BmiInitializeRequest)::Nothing
function initialize(req::HTTP.Request, initialize_request::InitializeRequest)::Nothing
global m
m = BMI.initialize(MyModel, bmi_initialize_request.config_file)
m = BMI.initialize(MyModel, initialize_request.config_file)
return nothing
end

function get_component_name(req::HTTP.Request;)::String
return BMI.get_component_name(m)
function get_component_name(req::HTTP.Request)::GetComponentNameResponse
return GetComponentNameResponse(BMI.get_component_name(m))
end

function get_input_item_count(req::HTTP.Request;)::Int64
Expand Down Expand Up @@ -89,8 +89,8 @@ function get_grid_size(req::HTTP.Request, grid::Int64;)::Int64
return BMI.get_grid_size(m, grid)
end

function get_grid_type(req::HTTP.Request, grid::Int64;)::BmiGetGridTypeResponse
return BMI.get_grid_type(m, grid)
function get_grid_type(req::HTTP.Request, grid::Int64;)::GetGridTypeResponse
return GetGridTypeResponse(type=BMI.get_grid_type(m, grid))
end

function finalize(req::HTTP.Request;)::Nothing
Expand Down Expand Up @@ -119,6 +119,7 @@ function reserve_grid_coords(m, grid::Int64, dim_index::Int8)::Vector{Float64}
size = BMI.get_grid_node_count(m, grid)
else
error("Unsupported grid type: $mtype")
end
return zeros(Float64, size)
end

Expand All @@ -141,15 +142,17 @@ function set_value(req::HTTP.Request, name::String, request_body::Vector{Float64
BMI.set_value(m, name, request_body)
end

function set_value_at_indices(req::HTTP.Request, name::String, bmi_set_value_at_indices_request::BmiSetValueAtIndicesRequest;)::Nothing
BMI.set_value_at_indices(m, name, bmi_set_value_at_indices_request)
function set_value_at_indices(req::HTTP.Request, name::String, set_value_at_indices_request::SetValueAtIndicesRequest;)::Nothing
BMI.set_value_at_indices(m, name, set_value_at_indices_request)
end

function get_current_time(req::HTTP.Request;)::Float64
return BMI.get_current_time(m)
end

function get_end_time(req::HTTP.Request;)::Float64
# Julia Heat model returns Inf, but that is not a valid JSON number.
# Therefore, it gets converted to null in the JSON response.
return BMI.get_end_time(m)
end

Expand All @@ -161,8 +164,8 @@ function get_time_step(req::HTTP.Request;)::Float64
return BMI.get_time_step(m)
end

function get_time_units(req::HTTP.Request;)::String
return BMI.get_time_units(m)
function get_time_units(req::HTTP.Request;)::GetTimeUnitsResponse
return GetTimeUnitsResponse(BMI.get_time_units(m))
end

function get_grid_origin(req::HTTP.Request, grid::Int64;)::Vector{Float64}
Expand Down Expand Up @@ -247,17 +250,17 @@ function get_var_itemsize(req::HTTP.Request, name::String;)::Int64
end

function get_var_location(req::HTTP.Request, name::String;)::GetVarLocationResponseLocation
return BMI.get_var_location(m, name)
return GetVarLocationResponseLocation(BMI.get_var_location(m, name))
end

function get_var_nbytes(req::HTTP.Request, name::String;)::Int64
return BMI.get_var_nbytes(m, name)
end

function get_var_type(req::HTTP.Request, name::String;)::String
function get_var_type(req::HTTP.Request, name::String;)::GetVarTypeResponse
raw_type = BMI.get_var_type(m, name)
map = Dict(
"Float64" => "float64",
"Float64" => "double",
"Float32" => "float32",
"Int64" => "int64",
"Int32" => "int32",
Expand All @@ -267,11 +270,11 @@ function get_var_type(req::HTTP.Request, name::String;)::String
if type == Any
error("Invalid data type returned by model: $raw_type, allowed types are: Float64, Float32, Int64, Int32")
end
return type
return GetVarTypeResponse(type)
end

function get_var_units(req::HTTP.Request, name::String;)::String
return BMI.get_var_units(m, name)
function get_var_units(req::HTTP.Request, name::String;)::GetVarUnitsResponse
return GetVarUnitsResponse(BMI.get_var_units(m, name))
end

function run(model, host, port)
Expand Down
4 changes: 4 additions & 0 deletions RemoteBMI.jl/src/apis/api_GettersApi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ function get_value_validate(handler)
function get_value_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_value", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down Expand Up @@ -46,6 +48,8 @@ function get_value_at_indices_validate(handler)
function get_value_at_indices_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_value_at_indices", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down
4 changes: 2 additions & 2 deletions RemoteBMI.jl/src/apis/api_IRFApi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ end
function initialize_read(handler)
function initialize_read_handler(req::HTTP.Request)
openapi_params = Dict{String,Any}()
openapi_params["BmiInitializeRequest"] = OpenAPI.Servers.to_param_type(BmiInitializeRequest, String(req.body))
openapi_params["InitializeRequest"] = OpenAPI.Servers.to_param_type(InitializeRequest, String(req.body))
req.context[:openapi_params] = openapi_params

return handler(req)
Expand All @@ -49,7 +49,7 @@ end
function initialize_invoke(impl; post_invoke=nothing)
function initialize_invoke_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]
ret = impl.initialize(req::HTTP.Request, openapi_params["BmiInitializeRequest"];)
ret = impl.initialize(req::HTTP.Request, openapi_params["InitializeRequest"];)
resp = OpenAPI.Servers.server_response(ret)
return (post_invoke === nothing) ? resp : post_invoke(req, resp)
end
Expand Down
8 changes: 6 additions & 2 deletions RemoteBMI.jl/src/apis/api_SettersApi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ function set_value_validate(handler)
function set_value_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "set_value", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand All @@ -36,7 +38,7 @@ function set_value_at_indices_read(handler)
openapi_params = Dict{String,Any}()
path_params = HTTP.getparams(req)
openapi_params["name"] = OpenAPI.Servers.to_param(String, path_params, "name", required=true, )
openapi_params["BmiSetValueAtIndicesRequest"] = OpenAPI.Servers.to_param_type(BmiSetValueAtIndicesRequest, String(req.body))
openapi_params["SetValueAtIndicesRequest"] = OpenAPI.Servers.to_param_type(SetValueAtIndicesRequest, String(req.body))
req.context[:openapi_params] = openapi_params

return handler(req)
Expand All @@ -47,14 +49,16 @@ function set_value_at_indices_validate(handler)
function set_value_at_indices_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "set_value_at_indices", :minLength, openapi_params["name"], 1)

return handler(req)
end
end

function set_value_at_indices_invoke(impl; post_invoke=nothing)
function set_value_at_indices_invoke_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]
ret = impl.set_value_at_indices(req::HTTP.Request, openapi_params["name"], openapi_params["BmiSetValueAtIndicesRequest"];)
ret = impl.set_value_at_indices(req::HTTP.Request, openapi_params["name"], openapi_params["SetValueAtIndicesRequest"];)
resp = OpenAPI.Servers.server_response(ret)
return (post_invoke === nothing) ? resp : post_invoke(req, resp)
end
Expand Down
12 changes: 12 additions & 0 deletions RemoteBMI.jl/src/apis/api_VariableInformationApi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ function get_var_grid_validate(handler)
function get_var_grid_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_var_grid", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down Expand Up @@ -45,6 +47,8 @@ function get_var_itemsize_validate(handler)
function get_var_itemsize_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_var_itemsize", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down Expand Up @@ -73,6 +77,8 @@ function get_var_location_validate(handler)
function get_var_location_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_var_location", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down Expand Up @@ -101,6 +107,8 @@ function get_var_nbytes_validate(handler)
function get_var_nbytes_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_var_nbytes", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down Expand Up @@ -129,6 +137,8 @@ function get_var_type_validate(handler)
function get_var_type_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_var_type", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down Expand Up @@ -157,6 +167,8 @@ function get_var_units_validate(handler)
function get_var_units_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_var_units", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down
Loading

0 comments on commit ff8a468

Please sign in to comment.