GraphQL / Absinthe Architecture
The API layer uses Absinthe for GraphQL with WebSocket subscriptions via absinthe_graphql_ws.
Schema Organization
The main schema is CFXWeb.Schema (apps/cfx_web/lib/cfx_web/schema.ex):
apps/cfx_web/lib/cfx_web/
├── schema.ex # Root schema — imports all types/queries/mutations/subscriptions
├── schema/
│ ├── middleware/ # Absinthe middleware (auth, errors, localization)
│ ├── mutations/ # Mutation field definitions
│ ├── queries/ # Query field definitions
│ ├── subscriptions/ # Subscription field definitions
│ └── notation.ex # Shared notation helpers
├── resolvers/ # Resolver modules (business logic)
├── types/ # Absinthe type definitions (objects, enums, inputs, scalars)
Naming Conventions
- Types:
CFXWeb.Types.<DomainName>(e.g.,Types.Options,Types.Feed,Types.User) - Queries:
CFXWeb.Schema.Queries.<DomainName>— import viaimport_fields :domain_queries - Mutations:
CFXWeb.Schema.Mutations.<DomainName>— import viaimport_fields :domain_mutations - Subscriptions:
CFXWeb.Schema.Subscriptions.<DomainName> - Resolvers:
CFXWeb.Resolvers.<DomainName>
Middleware Pipeline
All queries and mutations run through:
Middleware.SessionAdminAuthorization— checks session/admin permissions- (field resolvers)
Middleware.ErrorHandler— normalizes errors
Subscriptions get SessionAdminAuthorization only. Localization fields use Middleware.Localization.
Dataloader
def context(ctx) do
source = Dataloader.Ecto.new(Schemas.Repo)
dataloader = Dataloader.add_source(Dataloader.new(), Schemas.Accounts, source)
Map.put(ctx, :loader, dataloader)
end
Subscriptions
Feed data subscriptions:
- Client subscribes with filter params
- Resolver routes to feed node via
CFXRpc - Feed server (or ETS state) returns current data
- PubSub events trigger subscription updates
Absinthe Context
%{context: ctx} contains:
:current_user— authenticated user (fromSessionContextPlug):loader— Dataloader instance:ip_address— client IP- Session/admin role info from auth middleware
Adding New GraphQL Fields
- Define types in
CFXWeb.Types.<Domain>usinguse Absinthe.Schema.Notation - Define query/mutation fields in
CFXWeb.Schema.Queries.<Domain>orSchema.Mutations.<Domain> - Import types and fields in
CFXWeb.Schema - Implement resolver logic in
CFXWeb.Resolvers.<Domain> - For subscriptions, define in
CFXWeb.Schema.Subscriptions.<Domain>withconfigandtriggercallbacks
Source: MikaAK/elixir_rpc_load_balancer — distributed by TomeVault.