OpenAPI Integration
The gateway can automatically generate REST connectors from OpenAPI (Swagger) specification files. This enables quick integration of REST APIs without manual endpoint configuration.
Supported Formats
| Format | Extension | Feature Required |
|---|---|---|
| OpenAPI 3.0.x | .json |
None |
| OpenAPI 3.1.x | .json |
None |
| Swagger 2.0 | .json |
None |
| YAML (any version) | .yaml, .yml |
yaml |
Quick Start
use grpc_graphql_gateway::{Gateway, OpenApiParser};
// Parse OpenAPI spec and create REST connector
let connector = OpenApiParser::from_file("petstore.yaml")?
.with_base_url("https://api.petstore.io/v2")
.build()?;
let gateway = Gateway::builder()
.add_rest_connector("petstore", connector)
.build()?;Loading Options
From a File
// JSON file
let connector = OpenApiParser::from_file("api.json")?.build()?;
// YAML file (requires 'yaml' feature)
let connector = OpenApiParser::from_file("api.yaml")?.build()?;From a URL
let connector = OpenApiParser::from_url("https://api.example.com/openapi.json")
.await?
.build()?;From a String
let json_content = r#"{"openapi": "3.0.0", ...}"#;
let connector = OpenApiParser::from_string(json_content, false)?.build()?;
// For YAML content
let yaml_content = "openapi: '3.0.0'\n...";
let connector = OpenApiParser::from_string(yaml_content, true)?.build()?;From JSON Value
let json_value: serde_json::Value = serde_json::from_str(content)?;
let connector = OpenApiParser::from_json(json_value)?.build()?;Configuration Options
Base URL Override
Override the server URL from the spec:
let connector = OpenApiParser::from_file("api.json")?
.with_base_url("https://api.staging.example.com") // Use staging
.build()?;Timeout
Set a default timeout for all endpoints:
use std::time::Duration;
let connector = OpenApiParser::from_file("api.json")?
.with_timeout(Duration::from_secs(60))
.build()?;Operation Prefix
Add a prefix to all operation names to avoid conflicts:
let connector = OpenApiParser::from_file("petstore.json")?
.with_prefix("petstore_") // listPets -> petstore_listPets
.build()?;Filtering Operations
By Tags
Only include operations with specific tags:
let connector = OpenApiParser::from_file("api.json")?
.with_tags(vec!["pets".to_string(), "store".to_string()])
.build()?;Custom Filter
Use a predicate function for fine-grained control:
let connector = OpenApiParser::from_file("api.json")?
.filter_operations(|operation_id, path| {
// Only include non-deprecated v2 endpoints
!operation_id.contains("deprecated") && path.starts_with("/api/v2")
})
.build()?;What Gets Generated
The parser automatically generates:
Endpoints
Each path operation becomes a GraphQL field:
| OpenAPI | GraphQL |
|---|---|
GET /pets |
listPets query |
POST /pets |
createPet mutation |
GET /pets/{petId} |
getPet query |
DELETE /pets/{petId} |
deletePet mutation |
Arguments
- Path parameters → Required field arguments
- Query parameters → Optional field arguments
- Request body → Input arguments (auto-templated)
Response Types
Response schemas are converted to GraphQL types:
# OpenAPI
Pet:
type: object
properties:
id:
type: integer
name:
type: string
tag:
type: stringBecomes a GraphQL type with field selection.
Listing Operations
Before building, you can list all available operations:
let parser = OpenApiParser::from_file("api.json")?;
for op in parser.list_operations() {
println!("{}: {} {} (tags: {:?})",
op.operation_id,
op.method,
op.path,
op.tags
);
if let Some(summary) = op.summary {
println!(" {}", summary);
}
}Accessing Spec Information
let parser = OpenApiParser::from_file("api.json")?;
let info = parser.info();
println!("API: {} v{}", info.title, info.version);
if let Some(desc) = &info.description {
println!("Description: {}", desc);
}YAML Support
To enable YAML parsing, add the yaml feature:
[dependencies]
grpc_graphql_gateway = { version = "0.3", features = ["yaml"] }Example: Petstore Integration
use grpc_graphql_gateway::{Gateway, OpenApiParser};
use std::time::Duration;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Parse the Petstore OpenAPI spec
let petstore = OpenApiParser::from_url(
"https://petstore3.swagger.io/api/v3/openapi.json"
)
.await?
.with_base_url("https://petstore3.swagger.io/api/v3")
.with_timeout(Duration::from_secs(30))
.with_tags(vec!["pet".to_string()]) // Only pet operations
.with_prefix("pet_") // Namespace operations
.build()?;
// Create the gateway
let gateway = Gateway::builder()
.with_descriptor_set_bytes(DESCRIPTORS)
.add_grpc_client("service", grpc_client)
.add_rest_connector("petstore", petstore)
.serve("0.0.0.0:8888".to_string())
.await?;
Ok(())
}Multiple REST APIs
Combine multiple OpenAPI specs:
// Payment API
let stripe = OpenApiParser::from_file("stripe-openapi.json")?
.with_prefix("stripe_")
.build()?;
// Email API
let sendgrid = OpenApiParser::from_file("sendgrid-openapi.json")?
.with_prefix("email_")
.build()?;
// User service (gRPC)
let gateway = Gateway::builder()
.with_descriptor_set_bytes(USER_DESCRIPTORS)
.add_grpc_client("users", users_client)
.add_rest_connector("stripe", stripe)
.add_rest_connector("sendgrid", sendgrid)
.build()?;Best Practices
Use prefixes when combining multiple APIs to avoid naming conflicts
Filter by tags to include only the operations you need
Override base URLs for different environments (dev, staging, prod)
Check available operations before building to understand what will be generated
Enable YAML feature only if you need it (adds serde_yaml dependency)
Limitations
- Authentication: OpenAPI security schemes are not automatically applied. Use request interceptors for auth.
- Complex schemas: Very complex schemas (allOf, oneOf, anyOf) may be simplified.
- Webhooks: OpenAPI 3.1 webhooks are not supported.
- Callbacks: Async callbacks are not supported.