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

Adding OpenAPI Export and Rib to OpenAPI Converter #1206

Open
wants to merge 46 commits into
base: main
Choose a base branch
from

Conversation

zelosleone
Copy link

OpenAPI Export for API Definition Implementation

This PR implements the OpenAPI export functionality for API Definitions as specified in issue #1178 and feedback from @jdegoes The implementation provides a complete solution for converting User and Golem API Definitions to OpenAPI Specifications and includes comprehensive testing.

Key Features

  • Full and lossless conversion of API Definitions to OpenAPI 3.0 Specifications
  • Support for all binding types (Default and File Server)
  • Preservation of type information from Rib to OpenAPI schemas
  • Integration with Worker Gateway for serving OpenAPI specs
  • Swagger UI binding type for API documentation
  • Comprehensive test suite validating the export functionality

Implementation Details

  1. OpenAPI Export

    • Added OpenApiExporter for converting API definitions to OpenAPI specs
    • Implemented type conversion from Rib types to OpenAPI schemas
    • Added support for security schemes and CORS configurations
  2. Swagger UI Integration

    • Added new SwaggerUI binding type
    • Implemented dynamic Swagger UI generation inspired by @jdegoes's comment on my old pull request
    • Added configuration options for customization
  3. Testing

    • Added unit tests for type conversion
    • Added integration tests validating generated clients
    • Added system tests for Python to check if my schema is correct and Rust clients
    • Included complex test scenarios with nested types and security configurations

API Changes

Added new endpoint mentioned in the issue

/claim #1178

This time there are only 4 files that need review in honesty. Majority of the files are test files in order for it to be tested. I decided to re-invent the wheel after jdgoes's review, making me think "I can do this in smaller numbers, as he said use more of golem's library and I though, It's better for me to actually blend in the repo instead of trying to get overwhelmed by its" Since Swagger was absolutely a mess in rust, i used a dynamical client generation using Golem's existing file server already, it should serve the jsons and yalms to user in memory.

Plus unit tests, some documentation.
@jdegoes
Copy link
Contributor

jdegoes commented Dec 24, 2024

@zelosleone Before I do a fine-grained review, let me commend you on major improvements, and then point out one area which, at a high-level, is still not right: the integration testing.

The essential task of integration testing is to prove that, if a user builds a component with a complex API (meaning, use of WIT types including variants, flags, records, lists, results, etc.--fully and exhaustively sampling all the different types that WIT supports in the exports of the component), and then stands up an API using the Worker Gateway, by defining a number of different endpoints using Rib; that the resulting OpenAPI Export of this API definition is in fact both correct and precise, and such correctness and precision is evident in client libraries that have been auto-generated from the OpenAPI export.

So, the integration test will first need to start with a component that you write (there are test components already in Golem -- you could simply add one here). This test component will need to have a number of exports, let's call it 10 - 20, each of which accepts and returns a sampling of WIT types. This is to fully exercise your logic and your embedding of the knowledge of how Rib types map to canonical JSON types.

Once you have the test component, then the integration test will:

  1. Construct an API definition with a number of routes. Since API definitions can be imported from JSON/YAML, you could just hard code this in a fixtures directory and load it for testing purposes.
  2. Invoke your export code on the API definition, which should result in an OpenAPI schema that precisely describes the API, including input and output types for all 10 - 20 exports on the test component.
  3. Once you have this OpenAPI schema, dynamically generating client libraries (the choice of Python and TypeScript is fine; I think two client libraries is a good number and certainly one of them should be strongly statically typed; could be TS & Rust too, btw).
  4. Firing up a Worker Gateway (etc.) to serve the API definition (you can look at other integration tests for how this is done--you can spin up whatever portion of the Golem stack is necessary to actually execute workers; see the CLI tests for examples). When this step is done, there will be a server created by the worker gateway that is dynamically serving the API powered by your test component.
  5. Using hand-written test code for each client library, interacting with the API using the generated client libraries, and verifying the results have the structure ascribed to them and are sensible (how you do this depends on how you constructed the test component -- but the goal should be to catch any format or encoding/decoding problems so all your 10 - 20 exports need to return meaningful information, ideally derived from inputs so it can be somewhat dynamic).
  6. Spin everything down.

Such an integration test will reasonably demonstrate that all the pieces fit together, and that when a user exports an OpenAPI Schema from their API (defined in Rib, using the default/worker binding type, but also with file server and swagger UI binding types--which should also be tested in the integration test), this OpenAPI schema is in fact a 100% valid and usable schema for the API being served by the worker gateway. It is so correct and precise that you can generate client libraries from it, and use them in a typed and safe way; or, of course, you can interact with the API using Swagger UI (if you added such a binding type as part of your API definition) directly from the browser of your choice.

Other things important to test include CORS (to ensure that when a deployment is using CORs, that's reflected in the OpenAPI as the preflight options request, etc.), and security (because if an API is secured using Golem auth, then we want the security requirements to be expressed in OpenAPI so that auto-generated clients know they need to provide security).

You might want to use https://console.golem.cloud to play around with adding APIs to see the big picture, which will help you understand how to structure the integration test.

Once all the high-level architecture is correct, I will do a more fine-grained review.

Btw some parts of #1208 seem to be copied from your PR (see, for example, test server). Can you confirm or reject?

* Delete client-generation-tests directory
* Update openapi_converter.rs
* Update openapi_export.rs
* Update rib_converter.rs
* Update openapi_export.rs
* Update openapi_converter.rs
* Update swagger_ui.rs
* Delete golem-worker-service-base/src/gateway_api_definition/http/tests directory
* Update mod.rs
* Update mod.rs
* Create openapi-integration-tests.yaml
* Update openapi-integration-tests.yaml
* Update rib_converter.rs
@zelosleone
Copy link
Author

zelosleone commented Dec 24, 2024

Thanks for the helpful tips and helpful lessons @jdegoes You are really better than my professors in my university, thank you very much. I updated everything, made an unit test:

defines a non-trivial API, which complex input and output types
generates OAPI schema for the API
generates a client library for the OAPI
interacts with the original API and verifies successful communication

Which you mentioned it is needed in discord, I used github actions for this because building golem in windows was a pain due to wasm version conflict in cargo files. Here is the output file generated:
-this one is wrong, brb new one incoming-

Also significantly reduced the files changed for this, as i simply used the existing files to place unit tests. As for the copying issue, I did not give any permission to do so, neither I know him.

@uurl
Copy link

uurl commented Dec 24, 2024

My sincere apologies @jdegoes , my integration tests were performed by an AI, I now realize that it plagiarized code from @zelosleone , a huge apology to both of you, it was not my intention.

@jdegoes
Copy link
Contributor

jdegoes commented Dec 25, 2024

@zelosleone There's still a lot of work that has to be done. Please ping me when you have all the pieces put together and you are ready for a review.

- Added multiple new test files for API integration, OpenAPI conversion, and schema validation.
- Introduced new test cases for complex workflows and validation of JSON schemas against OpenAPI specifications.
- Updated `Cargo.toml` to include additional dependencies for testing and API functionality.
- Removed outdated tests related to Swagger UI and OpenAPI export.
- Improved the structure and organization of test cases for better maintainability and clarity.
@zelosleone
Copy link
Author

zelosleone commented Dec 26, 2024

@jdegoes Everything is finished, hopefully. Added docs as well. The linker error on windows (due to double versioning of wasm) makes it harder to manually test by the way. But all these testes i made returned 0 errors and passed, just the linker error makes it unable for me to give you the json and yaml files now.

@zelosleone zelosleone requested a review from jdegoes December 27, 2024 01:41
…n (finally manually tested, 5/7 tests passed, couldnt test it further because of RAM size)

- Updated `Cargo.toml` to enable harness for multiple test cases.
- Refactored `openapi_converter.rs` to improve path merging logic and component handling.
- Enhanced test cases across various modules, including API integration, OpenAPI conversion, and JSON schema validation, to utilize a dynamic test registration framework.
- Improved test structure for clarity and maintainability, ensuring comprehensive coverage of complex workflows and validation scenarios.
- Removed outdated tests and streamlined existing ones for better performance.
@zelosleone
Copy link
Author

zelosleone commented Dec 27, 2024

@jdegoes Finished manual testing as well after
wasm-wave = { version = "=0.6.0", default-features = false } on my cargo.toml due to version problems, didnt upload that one as that is got to be windows specific.

- Updated `Cargo.toml` to enable harness for multiple test cases and adjusted test configurations.
- Refactored `rib_converter.rs` to improve schema conversion logic, including the addition of new types and validation mechanisms.
- Enhanced test cases across various modules, including API integration, OpenAPI conversion, and JSON schema validation, to utilize a dynamic test registration framework.
- Improved the structure and organization of tests for better maintainability and clarity, ensuring comprehensive coverage of complex workflows and validation scenarios.
- Removed outdated tests and streamlined existing ones for better performance and reliability.
@jdegoes
Copy link
Contributor

jdegoes commented Dec 31, 2024

@zelosleone

I will have more time to review just after the new year, and can do a Zoom meeting since that may be the fastest way of discussion what remains to be done in the PR.

However, until then, I have two major comments:

  1. First off, the revisions necessary for doing end-to-end integration tests are not done. In particular, you have not added a new component with a large, exported API that tests all WIT types, and verified you can talk to the component through a client generated by the OpenAPI schema created by your code for that exportedAPI. See this comment for more details.
  2. Second, I don't think you've implemented the API in such a way that Console or CLI can actually utilize it, so I added a new requirement that will be quite easy when all parts are connected in the right way -- but impossible otherwise. I've reproduced the requirement below:
- [ ] Golem CLI modified to add a new subcommand 'golem-cli api-definition swagger' (launches a browser to a generated swagger UI for the api definition) and another new subcommand 'golem-cli api-definition export', which exports an API definition to OpenAPI schema

This basically says you need to add two new commands to golem-cli that (1) open up the Swagger UI, and (2) do an OpenAPI export. In order to realize those two new commands, the proper REST API with associated plumbing will need to be created, which will motivate part of the functionality that is missing now.

Happy New Year!

fn create_test_rib_mapping(function_name: &str) -> ResponseMapping {
let rib_expr = match function_name {
// No parameters
"healthcheck" | "version" | "get-primitive-types" => format!(r#"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can (and should) define the Rib scripts that "glue" your front-end API to your component inside an API Definition. I noticed you are using OpenAPI for the API definition, so you can actually use Golem-specific extensions to define the bindings.

See here for more details.

Learning what the "import OpenAPI" looks like will also help guide the "export OpenAPI".

- Added new methods for exporting OpenAPI specifications and launching Swagger UI in the `ApiDefinitionClient` and `ApiDefinitionService` traits.
- Refactored the `rib_converter` and `swagger_ui` modules to improve API route handling and CORS middleware integration.
- Enhanced test coverage for API endpoints and Swagger UI functionality, ensuring robust validation and error handling.
- Removed outdated tests and streamlined existing ones for improved performance and maintainability.
@zelosleone
Copy link
Author

All export results which I’ve validated also manually with https://editor.swagger.io/#

target.zip

zelosleone and others added 11 commits January 5, 2025 10:53
- Added new methods for exporting OpenAPI specifications and launching Swagger UI in the `ApiDefinitionClient` and `ApiDefinitionService` traits.
- Refactored the `rib_converter` and `swagger_ui` modules to improve API route handling and CORS middleware integration.
- Enhanced test coverage for API endpoints and Swagger UI functionality, ensuring robust validation and error handling.
- Removed outdated tests and streamlined existing ones for improved performance and maintainability.
This reverts commit 02665f3.
- Introduced a new RPC method `GetSwaggerUiContents` in the `WorkerExecutor` service to retrieve Swagger UI content dynamically.
- Updated the `WorkerService` trait to include `get_swagger_ui_contents` for fetching Swagger UI data.
- Enhanced Swagger UI configuration with authentication options and worker binding capabilities.
- Added new tests for dynamic Swagger UI worker binding and improved existing test coverage for API endpoints.
- Refactored error handling in the API to accommodate new functionalities and ensure better response management.
@zelosleone
Copy link
Author

@jdegoes Everything is done, also added Swagger UI binding in a dynamical way using golem workers, though its optional, users can use fixed paths too.

- Updated the conversion logic for `Value::Char` to handle invalid Unicode scalar values gracefully.
- Introduced error handling that returns a descriptive error message when an invalid character is encountered.
Gonna test it manually on cloud later
…LETS GO)

- Renamed and reorganized API definition commands for clarity, changing `export` to `swagger` and `ui` to `export`.
- Updated the `ApiDefinitionClient` and `ApiDefinitionService` traits to reflect new command structure.
- Implemented logic to open Swagger UI in the default browser upon invoking the `swagger` command.
- Enhanced Swagger UI content retrieval with a new RPC method `GetSwaggerUiContents` in the `WorkerExecutor` service.
- Added tests for the new command structure and Swagger UI functionality, ensuring proper integration and coverage.
- Updated dependencies in `Cargo.toml` for improved compatibility and functionality.
- Added additional CORS headers to the preflight tests for valid and simple input scenarios.
- Updated test cases to include 'Origin', 'Access-Control-Request-Method', and 'Access-Control-Request-Headers' in the CORS configuration, improving test coverage for API gateway functionality.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants