@conduit-client/service-bindings-imperative
v3.5.0
Published
Conduit services for imperative bindings
Readme
@conduit-client/service-bindings-imperative
Conduit services for imperative bindings, providing flexible data invocation strategies and patterns.
Overview
This package provides imperative data fetching and mutation services for the Conduit ecosystem. It offers multiple invoker strategies to handle different data fetching patterns including GraphQL, legacy systems, and subscribable data streams. It then wraps these in services to be used as needed within an environment.
Key Features
- Multiple Invoker Strategies: Support for various data fetching patterns
- GraphQL Support: Full GraphQL query and mutation support
- Legacy System Integration: Backward compatibility with legacy APIs
- Subscribable Data: Real-time data subscriptions and updates
- Flexible Architecture: Pluggable invoker system for custom implementations
Service Types
Available Services
DefaultImperativeBindingsService
Standard invoker for general-purpose data fetching.
- Handles standard REST API calls
- Provides error handling and retry logic
- Can be used for subscribable and non-subscribable results
QueryImperativeBindingsService
Specialized invoker for query operations.
- Supports all properties of the default invoker
GraphQLImperativeBindingsService
GraphQL-specific invoker for modern GraphQL APIs.
- Executes GraphQL queries
- Handles GraphQL errors
- Supports variables and fragments
GraphQLMutationBindingsService
Dedicated invoker for GraphQL mutations.
- Executes GraphQL mutations
- Handles optimistic updates
- Manages mutation side effects
GraphQLLegacyImperativeBindingsService
Bridge invoker for legacy GraphQL implementations.
- Backward compatibility with older GraphQL systems
- Handles legacy response formats
LegacyImperativeBindingsService
Compatibility invoker for legacy systems.
- Supports older REST APIs
SubscribableImperativeBindingsService
Real-time data subscription invoker.
- Specific to subscribable results
Usage Examples
Basic Data Fetching
import { buildDefaultImperativeBindingsServiceDescriptor } from '@conduit-client/services/bindings-imperative/v1';
// Build the service
const { service: defaultImperativeBindingsService } =
buildDefaultImperativeBindingsServiceDescriptor();
// Create a command that returns data
const getCommand = () => ({
execute: () =>
Promise.resolve({
isOk: () => true,
value: {
data: { foo: 'bar' },
subscribe: (callback) => {
// Optional subscription logic
return () => {}; // Return unsubscribe function
},
},
}),
});
// Bind the command to the service
const invoker = defaultImperativeBindingsService.bind(getCommand);
// Execute and get the result
const result = await invoker({ required: 'param' });
console.log(result); // { foo: 'bar' }GraphQL Query
import { buildGraphQLImperativeBindingsServiceDescriptor } from '@conduit-client/services/bindings-imperative/v1';
// Build the service
const { service: graphQLImperativeBindingsService } =
buildGraphQLImperativeBindingsServiceDescriptor();
// Create a GraphQL command
const getGraphQLCommand = () => ({
execute: () =>
Promise.resolve({
isOk: () => true,
value: {
data: {
data: { user: { id: '1', name: 'John' } },
errors: [],
},
subscribe: (callback) => {
// Handle GraphQL subscriptions
return () => {};
},
refresh: async () => {
// Optional refresh logic
},
},
}),
});
// Bind with refresh support
const invoker = graphQLImperativeBindingsService.bind(getGraphQLCommand, true);
// Execute GraphQL query
const result = await invoker('query { user { id name } }', { id: '123' });
console.log(result.data); // { user: { id: '1', name: 'John' } }
console.log(result.errors); // undefined or array of errors
console.log(result.subscribe); // Subscription function
console.log(result.refresh); // Refresh function (if enabled)GraphQL Mutation
import { buildGraphQLMutationBindingsServiceDescriptor } from '@conduit-client/services/bindings-imperative/v1';
// Build the service
const { service: graphQLMutationBindingsService } = buildGraphQLMutationBindingsServiceDescriptor();
// Create a mutation command
const getMutationCommand = () => ({
execute: (overrides) => {
// Note: Mutations automatically use no-cache
console.log(overrides.cacheControlConfig); // { type: 'no-cache' }
return Promise.resolve({
isOk: () => true,
value: {
data: {
data: { doThing: { id: '123' } },
errors: [],
},
},
});
},
});
// Bind the command
const invoker = graphQLMutationBindingsService.bind(getMutationCommand);
// Execute mutation
const result = await invoker({
query: 'mutation DoThing { doThing { id } }',
variables: {
/* variables */
},
});
console.log(result); // { data: { doThing: { id: '123' } }, errors: [] }Subscribable Data
import { buildSubscribableImperativeBindingsServiceDescriptor } from '@conduit-client/services/bindings-imperative/v1';
// Build the service
const { service: subscribableImperativeBindingsService } =
buildSubscribableImperativeBindingsServiceDescriptor();
// Create a subscribable command
const getSubscribableCommand = () => ({
execute: () =>
Promise.resolve({
isOk: () => true,
value: {
data: { foo: 'bar' },
subscribe: (callback) => {
// Set up subscription
const interval = setInterval(() => {
callback({
isOk: () => true,
value: { data: { foo: 'updated' } },
});
}, 1000);
// Return unsubscribe function
return () => clearInterval(interval);
},
refresh: async () => {
// Optional refresh logic
return { isOk: () => true, value: undefined };
},
},
}),
});
// Bind with refresh support
const invoker = subscribableImperativeBindingsService.bind(getSubscribableCommand, true);
// Get subscribable result
const result = await invoker({ required: 'param' });
console.log(result.data); // { foo: 'bar' }
// Subscribe to updates
const unsubscribe = result.subscribe((update) => {
console.log('Updated:', update);
});
// Refresh data
if (result.refresh) {
await result.refresh();
}
// Later: unsubscribe
unsubscribe();Legacy System Integration
import { buildLegacyImperativeBindingsServiceDescriptor } from '@conduit-client/services/bindings-imperative/v1';
// Build the service
const { service: legacyImperativeBindingsService } =
buildLegacyImperativeBindingsServiceDescriptor();
// Create a legacy command
const getLegacyCommand = () => ({
execute: (overrides) => {
// Handle cache policy if provided
const cachePolicy = overrides?.cacheControlConfig;
return Promise.resolve({
isOk: () => true,
value: {
data: { foo: 'legacy data' },
subscribe: (callback) => {
// Legacy subscription pattern
return () => {};
},
},
});
},
});
// Bind the command
const legacyAdapter = legacyImperativeBindingsService.bind(getLegacyCommand);
// Use legacy invoke pattern
legacyAdapter.invoke(
{ test: 'param' },
{ cachePolicy: { type: 'no-cache' } }, // Optional request context
(result) => {
console.log(result); // { data: { foo: 'legacy data' }, error: undefined }
}
);
// Use legacy subscribe pattern
const unsubscribe = legacyAdapter.subscribe({ test: 'param' }, {}, (result) => {
console.log('Updated:', result);
});
// Later: unsubscribe
unsubscribe();Query Service
import { buildQueryImperativeBindingsServiceDescriptor } from '@conduit-client/services/bindings-imperative/v1';
// Build the service
const { service: queryImperativeBindingsService } = buildQueryImperativeBindingsServiceDescriptor();
// Create a query command
const getQueryCommand = () => ({
execute: () =>
Promise.resolve({
isOk: () => true,
value: { message: 'query result' },
}),
});
// Bind the command
const invoker = queryImperativeBindingsService.bind(getQueryCommand);
// Execute query
const result = await invoker('queryParam', 42);
console.log(result); // { data: { message: 'query result' } }API Reference
Service Descriptors
Each service type is exported as a service descriptor builder function:
buildDefaultImperativeBindingsServiceDescriptor()- Returns default service descriptorbuildQueryImperativeBindingsServiceDescriptor()- Returns query service descriptorbuildSubscribableImperativeBindingsServiceDescriptor()- Returns subscribable service descriptorbuildLegacyImperativeBindingsServiceDescriptor()- Returns legacy service descriptorbuildGraphQLImperativeBindingsServiceDescriptor()- Returns GraphQL service descriptorbuildGraphQLLegacyImperativeBindingsServiceDescriptor()- Returns GraphQL legacy service descriptorbuildGraphQLMutationBindingsServiceDescriptor()- Returns GraphQL mutation service descriptor
Service Methods
Each service provides a bind method:
bind<TParams extends unknown[]>(getCommand: CommandFactory, exposeRefresh?: boolean): Invoker
Binds a command factory to the service and returns an invoker function.
getCommand: A function that returns a command object with anexecutemethodexposeRefresh: Optional boolean to enable refresh functionality (for subscribable services)- Returns: An invoker function that accepts parameters and returns a promise
Command Interface
Commands must implement the interface from @conduit-client/command-base
Dependencies
@conduit-client/utils: Core utility functions@conduit-client/bindings-utils: Shared binding utilities@conduit-client/jsonschema-validate: JSON schema validation@conduit-client/command-base: Base command interfaces@conduit-client/onestore-graphql-parser: GraphQL parsing utilities
