Builds an OpenAPI specification for the provided descriptor sources.
(
sources: &[DescriptorSource<'_>],
info: &DocumentInfo<'_>,
)
| 226 | |
| 227 | /// Builds an OpenAPI specification for the provided descriptor sources. |
| 228 | pub fn generate_document( |
| 229 | sources: &[DescriptorSource<'_>], |
| 230 | info: &DocumentInfo<'_>, |
| 231 | ) -> Result<String> { |
| 232 | if sources.is_empty() { |
| 233 | bail!("at least one descriptor source is required"); |
| 234 | } |
| 235 | |
| 236 | let mut registry = DescriptorRegistry::default(); |
| 237 | for (source_id, source) in sources.iter().enumerate() { |
| 238 | let descriptor_set = FileDescriptorSet::decode(source.descriptor) |
| 239 | .context("failed to decode descriptor set")?; |
| 240 | registry.ingest(descriptor_set, source_id); |
| 241 | } |
| 242 | |
| 243 | let mut schema_builder = SchemaBuilder::new(®istry); |
| 244 | let mut paths = BTreeMap::<String, Value>::new(); |
| 245 | |
| 246 | for (source_id, source) in sources.iter().enumerate() { |
| 247 | for svc_cfg in &source.services { |
| 248 | let service = registry |
| 249 | .resolve_service(source_id, svc_cfg.name.as_ref()) |
| 250 | .with_context(|| format!("service {} not found in descriptor", svc_cfg.name))?; |
| 251 | |
| 252 | for method in &service.methods { |
| 253 | if method.client_streaming || method.server_streaming { |
| 254 | bail!( |
| 255 | "streaming method {}.{} is not supported by the HTTP bridge", |
| 256 | service.full_name, |
| 257 | method.name |
| 258 | ); |
| 259 | } |
| 260 | |
| 261 | let base = normalize_mount_path(svc_cfg.mount_path.as_ref()); |
| 262 | let method_segment = format!("{}{}", svc_cfg.method_prefix, method.name); |
| 263 | let path = join_path(&base, &method_segment); |
| 264 | let post_operation = |
| 265 | build_operation(service, method, svc_cfg, &mut schema_builder)?; |
| 266 | |
| 267 | let mut op_map = Map::new(); |
| 268 | op_map.insert("post".to_string(), post_operation); |
| 269 | paths.insert(path, Value::Object(op_map)); |
| 270 | } |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | if paths.is_empty() { |
| 275 | bail!("no RPC methods were registered for OpenAPI export"); |
| 276 | } |
| 277 | |
| 278 | let mut schemas = schema_builder.finish(); |
| 279 | schemas.insert("RpcError".to_string(), rpc_error_schema()); |
| 280 | |
| 281 | let mut doc = Map::new(); |
| 282 | doc.insert("openapi".into(), Value::String("3.1.0".into())); |
| 283 | |
| 284 | let mut info_obj = Map::new(); |
| 285 | info_obj.insert("title".into(), Value::String(info.title.to_string())); |