gRPC Services
Easy AppServer exposes four core gRPC services for application communication: Marketplace, Hooks, Activity, and Settings. These services use Protocol Buffers for efficient serialization and support both unary and streaming RPCs.
Overview
All application-to-platform communication happens via gRPC, providing type safety, code generation, and efficient binary serialization. Services are defined in easy.proto/v2/protos/services.proto and implement comprehensive authentication, authorization, and error handling.
Service Catalog
1. Marketplace Service
Manages application lifecycle operations.
Code Reference: easy.proto/v2/protos/services.proto:161
RPCs:
service Marketplace {
// Validate an app's signature
rpc ValidateSignature(AppSignatureRequest) returns (AppSignatureResponse);
// Bidirectional streaming RPC for app registration and lifecycle
rpc Subscribe(stream StreamingAppRequest) returns (stream StreamingAppResponse);
// Install a registered app
rpc InstallApp(AppInstallRequest) returns (AppStateResponse);
// Uninstall an installed app
rpc UninstallApp(UninstallAppRequest) returns (AppStateResponse);
}
Key Operations:
- ValidateSignature: Validate an app's signature for authentication
- Subscribe: Bidirectional stream for app registration and lifecycle events (onRegister, onInstall, onUninstall)
- InstallApp: Install a registered application
- UninstallApp: Uninstall an installed application
Code Reference: pkg/v2/presentation/grpc/marketplace_server.go:79
2. Hooks Service
Event-driven communication between applications.
Code Reference: easy.proto/v2/protos/services.proto:29
RPCs:
service Hooks {
// Bidirectional streaming RPC for hook listeners and responses
rpc On(stream StreamingHookListenerRequest) returns (stream StreamingHookListenerResponse);
// Trigger a hook for registered listeners
rpc TriggerHook(HookTriggerRequest) returns (TriggerHookResponse);
}
Key Operations:
- On: Bidirectional stream for hook registration and event delivery
- TriggerHook: Fire hook and wait for responses from listeners
Code Reference: pkg/v2/presentation/grpc/hooks_server.go:89
3. Activity Service
Structured request/response workflows with routing strategies.
Code Reference: easy.proto/v2/protos/services.proto:267
RPCs:
service Activity {
// Register activity handler (streaming)
rpc RegisterActivity(stream StreamingActivityRequest) returns (stream StreamingActivityResponse);
// Request activity execution
rpc RequestActivity(ActivityRequest) returns (ActivityResponse);
}
Key Operations:
- RegisterActivity: Bidirectional stream for handler registration
- RequestActivity: Execute activity with routing strategy (single node or broadcast)
Code Reference: pkg/v2/presentation/grpc/activity_server.go:44
4. Settings Service
Schema-driven configuration management.
Code Reference: easy.proto/v2/protos/services.proto:403
RPCs:
service Settings {
// Register settings schema
rpc RegisterSettings(RegisterSettingsRequest) returns (RegisterSettingsResponse);
// Update setting values
rpc UpdateSettings(UpdateSettingsRequest) returns (UpdateSettingsResponse);
// Get all settings for an app
rpc GetSettings(GetSettingsRequest) returns (GetSettingsResponse);
// Get a specific setting value
rpc GetSettingValue(GetSettingValueRequest) returns (GetSettingValueResponse);
// Validate that all required settings have values
rpc ValidateRequiredSettings(ValidateRequiredSettingsRequest) returns (ValidateRequiredSettingsResponse);
// Delete all settings for an app
rpc DeleteSettings(DeleteSettingsRequest) returns (DeleteSettingsResponse);
}
Key Operations:
- RegisterSettings: Define schema from manifest
- UpdateSettings: Modify values with validation
- GetSettings: Retrieve all settings (masked if sensitive)
- GetSettingValue: Retrieve a specific setting value
- ValidateRequiredSettings: Check that all required settings have values
- DeleteSettings: Remove all settings for an app
Code Reference: pkg/v2/presentation/grpc/settings_server.go:49
Authentication & Authorization
All gRPC calls require authentication via metadata.
App Authentication
Apps authenticate using certificate-based signatures:
Metadata Headers:
X-App-Name: de.easy-m.todos
X-App-Timestamp: 1705329000000
X-App-Signature: base64-encoded-hmac-signature
Verification Flow:
1. Extract metadata from gRPC context
2. Look up app certificate in database
3. Verify signature using certificate
4. Check timestamp is within replay window (30s)
5. Populate AuthContext
6. Proceed to authorization check
Code Reference: pkg/v2/presentation/grpc/grpcauth/authenticator.go:85
Permission Enforcement
After authentication, permissions are checked:
Example: Can app:backend trigger hook:user.created?
↓
Check OpenFGA tuple: (app:backend, trigger, hook:user.created)
↓
Allow/Deny
Streaming Patterns
Bidirectional Streams
Used for long-lived connections (hooks, activities, lifecycle).
Example: Hook Registration:
const stream = hooksClient.On();
// Send registration
stream.write({
type: 'REGISTER',
hookName: 'user.created'
});
// Receive events
stream.on('data', (message) => {
if (message.type === 'TRIGGER') {
handleHook(message.payload);
// Send response
stream.write({
type: 'RESPONSE',
correlationId: message.correlationId,
result: { success: true }
});
}
});
Server Streaming
Used for event subscriptions.
Example: Lifecycle Events:
const stream = marketplaceClient.Subscribe();
stream.on('data', (event) => {
switch (event.type) {
case 'INSTALL':
await onInstall();
break;
case 'UNINSTALL':
await onUninstall();
break;
}
});
Error Handling
gRPC services return standard status codes with detailed error information.
Status Codes
OK: Success
INVALID_ARGUMENT: Validation failed
UNAUTHENTICATED: Missing or invalid credentials
PERMISSION_DENIED: Unauthorized
NOT_FOUND: Resource doesn't exist
ALREADY_EXISTS: Duplicate entity
DEADLINE_EXCEEDED: Request timeout
INTERNAL: Server error
Error Details
Errors include structured details:
{
"code": "INVALID_ARGUMENT",
"message": "Validation failed",
"details": [
{
"field": "api_key",
"error": "Value does not match pattern"
}
]
}
Versioning
Services are versioned via the proto package:
easy.proto/v2/protos/services.proto
Compatibility Rules:
- Backward compatible changes: Add optional fields, new RPCs
- Breaking changes: Increment major version (v2 → v3)
- Deprecation period: 6 months for removed fields
Best Practices
For App Developers
Implement Retries with Backoff:
async function callWithRetry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (err) {
if (err.code === 'UNAVAILABLE' && i < maxRetries - 1) {
await sleep(2 ** i * 1000); // Exponential backoff
continue;
}
throw err;
}
}
}
Handle Stream Disconnections:
function maintainStream() {
const stream = hooksClient.On();
stream.on('error', (err) => {
logger.error('Stream error', err);
setTimeout(maintainStream, 5000); // Reconnect after 5s
});
stream.on('end', () => {
logger.info('Stream ended');
setTimeout(maintainStream, 1000); // Reconnect immediately
});
}
Set Appropriate Deadlines:
const deadline = new Date();
deadline.setSeconds(deadline.getSeconds() + 30);
client.RegisterApp(request, { deadline }, callback);
For Platform Operators
Monitor RPC Latencies:
RegisterApp: p95 < 500ms
TriggerHook: p95 < 100ms
UpdateSettings: p95 < 50ms
Enable Health Checks:
healthServer.addCheck('grpc', () => {
// Check if gRPC server is healthy
return { status: 'SERVING' };
});
Related Concepts
- Authentication & Authorization - Auth flow details
- Hooks Architecture - Hook service implementation
- Activities & Background Workflows - Activity service implementation
- Settings Management - Settings service implementation
- Developer Platform & SDK - Client SDKgeneration
Further Reading
- Protocol Buffers - Proto syntax and best practices
- gRPC Documentation - Core gRPC concepts
- API Reference: gRPC Services - Complete RPC documentation