Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manual request/response validation #195

Closed
ahx opened this issue Nov 7, 2023 · 6 comments
Closed

Manual request/response validation #195

ahx opened this issue Nov 7, 2023 · 6 comments
Milestone

Comments

@ahx
Copy link
Owner

ahx commented Nov 7, 2023

The idea is to programatically validate requests/responses.

See also #169 (comment) #140.

Api proposal:

OpenapiFirst::RequestValidator.new('my/openapi.yaml')

request = Rack::Request.new(env)
validator.validate(request)  # Returns an object with details about the validation result (error?, schema, data, etc.)
validator.validate!(request) # Raises an exception if request is invalid

UPDATE: See Variant 1

@MrBananaLord
Copy link
Contributor

That looks great!

I suppose the validator.validate(request) will handle all descendants of OpenapiFirst::Error and return them as a list of validation errors? :)

@ahx ahx added this to the 1.0.0 milestone Nov 7, 2023
@ahx
Copy link
Owner Author

ahx commented Nov 7, 2023

I would rather go the other way around and catching and returning things in .validate and raise exception in .validate!, but that's just implementation details.

@ahx
Copy link
Owner Author

ahx commented Dec 4, 2023

Hi @MrBananaLord and @twe4ked and others,

This text is mainly for me to clarify the different interface approaches, but any thoughts on this would be much appreciated.

I am working on changing the structure of the gem to make it simpler to either use a ready-made middleware or build your own middleware. In my head I am aiming for the following high level interface and would love to get feedback on this:

Variant 1 – Runtime request interface

definition = OpenapiFirst.load('petstore.yaml')
definition.request(rack_request).validate # or validate! to validate the request
# #request will never return nil even if the request is not defind in the API description

# Inspect how the current request matches the API description. (Low level interface)
request = definition.request(rack_request)
request.defined? # (or similar name) return true if request is defined (operation and path_item are defined), false if not.
request.operation #  returns nil if the request method is not defined
request.path_item # returns nil if the path is unknown

# Validate the response
definition.request(rack_request).response(rack_response).validate # or validate! to validate the response

One good thing about this interface is that the user does not need to know about OpenAPI internals (path items, operations) to validate a request. This interface should also work with the current state of the OpenAPI 4.0 discussion.
The idea is that the return value of request can be used to either inspect the request definition that matches the incoming request (Rack::Request or rack env Hash) or call validate to validate the request. request will never return nil, but something like a "runtime request" or the like that holds information about the incoming request and the related parts in the API description (path_item, operation). The #response method works the same.

Variant 2 – Document tree interface

definition = OpenapiFirst.load('petstore.yaml')

# Navigate through the API description document until you find the operation for the current request and validate it.
# Note that path_item and operation methods return nil if the request does not match the API description.
definition.path_item(rack_request.path).operation(request.method).validate(request)

## Validate the response
operation = definition.path_item(rack_request.path).operation(request.method)
operation.response(rack_response.status).validate(rack_response)

This is very simple, but the user needs at least know about how to find path items and operations in an OpenAPI document. Also this interface wont't work with the current state of OpenAPI 4.0.

Any thoughts?

@twe4ked
Copy link
Contributor

twe4ked commented Dec 4, 2023

Thanks for this @ahx! Variant 1 looks good to me, good that it should be future proof for OpenAPI 4.0 too. 💯

@MrBananaLord
Copy link
Contributor

Hi @ahx, Variant 1 would be my preferred one :) thanks for the work on this!

@ahx
Copy link
Owner Author

ahx commented Jan 2, 2024

Should be solved with #202

@ahx ahx closed this as completed Jan 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants