@api-components/amf-helper-mixin
Version:
A mixin with common functions user by most AMF components to compute AMF values
334 lines (248 loc) • 8.75 kB
Markdown
gRPC Helper Methods
This document describes the new helper methods added to `AmfHelperMixin` to support gRPC APIs in API Console components.
# Test Data
Tests use the files `apis/grpc-api.json` and `apis/grpc-api-compact.json` which contain real AMF models of a gRPC API in regular and compact format respectively, following the repository's standard pattern.
# AmfLoader Helper Methods
In addition to the mixin methods, helper methods have been added to `AmfLoader` to facilitate searching for specific gRPC services and methods in tests:
## `AmfLoader.lookupGrpcService(model, serviceName)`
Finds a specific gRPC service by name.
```javascript
const service = AmfLoader.lookupGrpcService(grpcModel, 'Greeter');
if (service) {
const serviceName = this._computeGrpcServiceName(service);
console.log('Found service:', serviceName);
}
```
## `AmfLoader.lookupGrpcMethod(model, serviceName, methodName)`
Finds a specific gRPC method within a service.
```javascript
const method = AmfLoader.lookupGrpcMethod(grpcModel, 'Greeter', 'SayHello');
if (method) {
const streamType = this._getGrpcStreamType(method);
const signature = this._computeGrpcMethodSignature(method, service);
console.log('Method signature:', signature, 'Stream type:', streamType);
}
```
# Main Methods
## gRPC Detection
### `_isGrpcApi(api)`
Determines if the current API is a gRPC API by checking media types.
```javascript
const isGrpc = this._isGrpcApi(this.amf);
if (isGrpc) {
// Process as gRPC API
}
```
### `_isGrpcOperation(operation)`
Determines if a specific operation is a gRPC operation.
```javascript
const method = this._computeMethodModel(webApi, methodId);
if (this._isGrpcOperation(method)) {
// Process as gRPC method
}
```
### `_isGrpcService(endpoint)`
Checks if an endpoint represents a gRPC service.
```javascript
const endpoints = this._computeEndpoints(webApi);
const grpcServices = endpoints.filter(ep => this._isGrpcService(ep));
```
## Stream Types
### `_getGrpcStreamType(operation)`
Gets the stream type for a gRPC operation.
**Return values:**
- `'unary'` - One request, one response
- `'client_streaming'` - Multiple requests, one response
- `'server_streaming'` - One request, multiple responses
- `'bidi_streaming'` - Multiple requests, multiple responses
```javascript
const streamType = this._getGrpcStreamType(operation);
// 'unary', 'client_streaming', 'server_streaming', 'bidi_streaming'
```
### `_getGrpcStreamTypeDisplayName(streamType)`
Gets the human-readable name for a stream type.
```javascript
const displayName = this._getGrpcStreamTypeDisplayName('client_streaming');
// 'Client Streaming'
```
### `_getGrpcStreamTypeBadge(streamType)`
Gets the badge identifier for UI display.
```javascript
const badge = this._getGrpcStreamTypeBadge('unary');
// 'U'
```
## Services and Methods
### `_computeGrpcServices(webApi)`
Gets all gRPC services from a WebAPI.
```javascript
const webApi = this._computeWebApi(this.amf);
const services = this._computeGrpcServices(webApi);
```
### `_computeGrpcMethods(service)`
Gets all gRPC methods for a service.
```javascript
const methods = this._computeGrpcMethods(service);
```
### `_computeGrpcServiceName(endpoint)`
Gets the gRPC service name from an endpoint.
```javascript
const serviceName = this._computeGrpcServiceName(service);
// 'Greeter'
```
### `_computeGrpcMethodName(operation)`
Gets the gRPC method name from an operation.
```javascript
const methodName = this._computeGrpcMethodName(operation);
// 'SayHello'
```
### `_computeGrpcMethodSignature(operation, service)`
Builds a method signature for display.
```javascript
const signature = this._computeGrpcMethodSignature(operation, service);
// 'Greeter.SayHello'
```
## Schemas and Messages
### `_computeGrpcRequestSchema(operation)`
Gets the request message schema for a gRPC operation.
```javascript
const requestSchema = this._computeGrpcRequestSchema(operation);
```
### `_computeGrpcResponseSchema(operation)`
Gets the response message schema for a gRPC operation.
```javascript
const responseSchema = this._computeGrpcResponseSchema(operation);
```
### `_computeGrpcMessageTypes(api)`
Extracts all message types (schemas) from a gRPC API for the Types section.
```javascript
const messageTypes = this._computeGrpcMessageTypes(this.amf);
```
### `_isGrpcMessageType(shape)`
Checks if a shape represents a gRPC message type.
```javascript
const isMessageType = this._isGrpcMessageType(shape);
```
## Utilities
### `_computeGrpcPackageName(api)`
Gets the gRPC package name from the API.
```javascript
const packageName = this._computeGrpcPackageName(this.amf);
// 'helloworld'
```
### `_computeGrpcHttpMethod(operation)`
Gets the HTTP method equivalent for gRPC operations (typically POST).
```javascript
const httpMethod = this._computeGrpcHttpMethod(operation);
// 'POST'
```
### `_computeGrpcOperationId(operation, service)`
Computes a friendly operation ID for gRPC methods.
```javascript
const operationId = this._computeGrpcOperationId(operation, service);
```
### `_hasGrpcEndpoints(api)`
Determines if the API has any gRPC endpoints.
```javascript
const hasGrpc = this._hasGrpcEndpoints(this.amf);
```
### `_computeGrpcSummary(webApi)`
Gets a summary of gRPC services and method counts.
```javascript
const summary = this._computeGrpcSummary(webApi);
// {
// serviceCount: 1,
// services: [{
// name: 'Greeter',
// id: '/service/Greeter',
// methodCount: 2,
// methods: [...]
// }]
// }
```
# Usage in Components
## API Navigation
```javascript
class ApiNavigation extends AmfHelperMixin(LitElement) {
computeNavigationItems() {
const webApi = this._computeWebApi(this.amf);
const items = [];
// Add gRPC services
const grpcServices = this._computeGrpcServices(webApi);
if (grpcServices) {
grpcServices.forEach(service => {
const methods = this._computeGrpcMethods(service);
items.push({
name: this._computeGrpcServiceName(service),
type: 'grpc-service',
children: methods.map(method => ({
name: this._computeGrpcMethodName(method),
streamType: this._getGrpcStreamType(method),
badge: this._getGrpcStreamTypeBadge(this._getGrpcStreamType(method))
}))
});
});
}
return items;
}
}
```
## API Method Documentation
```javascript
class ApiMethodDocumentation extends AmfHelperMixin(LitElement) {
computeMethodData() {
const method = this._computeMethodModel(this.webApi, this.selectedMethod);
if (this._isGrpcOperation(method)) {
return {
type: 'grpc',
streamType: this._getGrpcStreamType(method),
requestSchema: this._computeGrpcRequestSchema(method),
responseSchema: this._computeGrpcResponseSchema(method),
showUrlPanel: false, // Hide URL panel for gRPC
showSnippets: false // Hide HTTP snippets for gRPC
};
}
return this.computeRestMethodData(method);
}
}
```
## API Summary
```javascript
class ApiSummary extends AmfHelperMixin(LitElement) {
computeApiSummary() {
const webApi = this._computeWebApi(this.amf);
if (this._isGrpcApi(this.amf)) {
const grpcSummary = this._computeGrpcSummary(webApi);
return {
type: 'grpc',
packageName: this._computeGrpcPackageName(this.amf),
...grpcSummary
};
}
return this.computeRestApiSummary(webApi);
}
}
```
# Namespace Support
Support for gRPC-specific properties has been added to the namespace:
```javascript
// Namespace.js
ns.aml.vocabularies.core.grpcStreamType = `${coreKey}grpcStreamType`;
```
# Media Type Detection
The helpers detect gRPC operations by checking the following media types:
- `application/grpc`
- `application/grpc+proto`
- `application/protobuf` (for responses)
# Complete Example
See `examples/grpc-usage.js` for complete usage examples in different scenarios.
# Compatibility
These helpers are fully compatible with existing REST/RAML APIs. The methods return `undefined` or `false` when used with non-gRPC APIs, allowing components to handle both API types transparently.
# Current Limitations
1. **Stream Types**: Currently defaults to 'unary' until AMF provides stream type metadata.
2. **Examples**: Automatic examples for gRPC require additional AMF metadata.
3. **gRPC Metadata**: Options like deadlines and HTTP/2 headers require additional AMF support.
# Next Steps
1. Coordinate with AMF team to add stream type metadata
2. Implement support for automatic examples
3. Add support for gRPC metadata (options, deadlines, etc.)
4. Extend streaming support in the Try Panel