Skip to content

GraphQL API Implementation Status

This document tracks the implementation progress of the GraphQL API adapter for the Essert MES system.

Overview

The GraphQL API is built using HotChocolate v15.1.3 and follows the hexagonal architecture pattern, consuming the same Application layer services as the REST API.

Project Structure

Essert.MF.API.GraphQL/
├── Program.cs                    # Application entry point & GraphQL configuration
├── Queries/                      # GraphQL query resolvers
│   ├── ProductQueries.cs
│   ├── ManufacturingQueries.cs
│   ├── RobotQueries.cs
│   ├── StatisticsQueries.cs
│   ├── WorkPieceCarrierQueries.cs
│   └── SystemQueries.cs
├── Mutations/                    # GraphQL mutation resolvers
│   ├── ProductMutations.cs
│   ├── ManufacturingMutations.cs
│   ├── RobotMutations.cs
│   ├── StatisticsMutations.cs
│   ├── WorkPieceCarrierMutations.cs
│   └── SystemMutations.cs
├── Subscriptions/                # GraphQL subscription resolvers
│   └── StatisticsSubscriptions.cs
├── appsettings.json
└── appsettings.Development.json

Essert.MF.Application/
├── Ports/
│   └── ICurrentMessageEventService.cs  # Event service interface (cross-API)

Essert.MF.Infrastructure/
├── Services/
│   └── CurrentMessageEventService.cs   # Event service implementation (singleton)

Essert.MF.API.GraphQL.Tests/
├── Infrastructure/
│   ├── TestWebApplicationFactory.cs
│   └── IntegrationTestBase.cs
├── Queries/
│   ├── ProductQueriesTests.cs
│   ├── ManufacturingQueriesTests.cs
│   ├── RobotQueriesTests.cs
│   ├── StatisticsQueriesTests.cs
│   ├── WorkPieceCarrierQueriesTests.cs
│   └── SystemQueriesTests.cs
├── Mutations/
│   ├── ProductMutationsTests.cs
│   ├── ManufacturingMutationsTests.cs
│   ├── RobotMutationsTests.cs
│   ├── StatisticsMutationsTests.cs
│   ├── WorkPieceCarrierMutationsTests.cs
│   └── SystemMutationsTests.cs
├── Subscriptions/
│   └── StatisticsSubscriptionsTests.cs
├── Services/
│   └── CurrentMessageEventServiceTests.cs
└── HealthCheckTests.cs

Implementation Status

Queries (24 total)

Domain Query Status Description
Products searchProducts Done Search products and versions by name
productById Done Get product by UID
versionsForProduct Done Get all versions for a product
Manufacturing activeProcesses Done Get active manufacturing processes (paginated)
processById Done Get process by UID
processByOrderNumber Done Get process by order number
processesByWpcId Done Get processes by WPC ID
Robots availableRobots Done Get all available robots
robotById Done Get robot by UID
robotsByPositionDataId Done Get robots by position data ID
calculatedPosition Done Get calculated robot position
Statistics processStatistics Done Get process statistics by order UID and process ID
processStatisticsByVersion Done Get statistics by version, process, and date range
recentCycleTimes Done Get recent cycle times
cycleTimeStatistics Done Get cycle time statistics
WorkPieceCarriers availableWorkPieceCarriers Done Get all available WPCs
workPieceCarriersByType Done Get WPCs by carrier type
System allVariables Done Get all system variables
allBatteryStatuses Done Get all battery statuses
systemHealth Done Get system health status
systemSummary Done Get system summary
versionHistory Done Get database version history
downtimeRecords Done Get downtime records by date range
recentDowntimeRecords Done Get recent downtime records

Mutations (26 total)

Domain Mutation Status Description
Products createProduct Done Create product with CRC
createProductWithParameters Done Create product with version and parameter mappings
updateProduct Done Update product information
deleteProduct Done Delete product with all versions
createVersion Done Create new version for product
updateVersion Done Update version information
setFactorySetup Done Set factory setup flag
deleteVersion Done Delete a version
Manufacturing createManufacturingProcess Done Create new manufacturing process
completeManufacturingProcess Done Complete a manufacturing process
deleteManufacturingProcess Done Delete a manufacturing process
Robots executeRobotMasterTeach Done Execute robot master teaching
storeMasterData Done Store master position data
storePositionData Done Store position data with offsets
Statistics addCurrentMessage Done Add a current message
removeCurrentMessage Done Remove a current message
archiveMessage Done Archive a message
recordValveMeasurement Done Record valve measurement
recordEgpMeasurement Done Record EGP measurement
recordKannMeasurement Done Record Kann measurement
recordLengthMeasurement Done Record length measurement
WorkPieceCarriers deleteWorkPieceCarrier Done Delete a WPC
System setVariable Done Set/update system variable
addVersion Done Add database version entry
recordDowntime Done Record system downtime
updateBatteryStatus Done Update battery status

Test Coverage (62 tests total)

Test File Tests Status
HealthCheckTests.cs 2 Done
ProductQueriesTests.cs 3 Done
ManufacturingQueriesTests.cs 4 Done
RobotQueriesTests.cs 3 Done
StatisticsQueriesTests.cs 4 Done
WorkPieceCarrierQueriesTests.cs 2 Done
SystemQueriesTests.cs 6 Done
ProductMutationsTests.cs 6 Done
ManufacturingMutationsTests.cs 3 Done
RobotMutationsTests.cs 3 Done
StatisticsMutationsTests.cs 7 Done
WorkPieceCarrierMutationsTests.cs 1 Done
SystemMutationsTests.cs 4 Done
StatisticsSubscriptionsTests.cs 7 Done
CurrentMessageEventServiceTests.cs 9 Done

Solution Integration

  • Add Essert.MF.API.GraphQL to Essert.MF.sln
  • Add Essert.MF.API.GraphQL.Tests to Essert.MF.sln

Subscriptions (4 total)

Domain Subscription Status Description
Statistics onCurrentMessageChanged Done Subscribe to all current message changes (added/removed)
onCurrentMessageAdded Done Subscribe to message added events only
onCurrentMessageRemoved Done Subscribe to message removed events only
onAllCurrentMessages Done Subscribe to periodic snapshots of all current messages

Subscription Architecture

The subscription system follows the hexagonal architecture pattern, ensuring that all API adapters (REST, GraphQL, OPC UA) can trigger real-time notifications to GraphQL subscribers.

┌─────────────────────────────────────────────────────────────────────────────────┐
│                           Event Flow Architecture                                │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                  │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐                              │
│  │  REST API   │  │ GraphQL API │  │  OPC UA API │    API Adapters              │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘                              │
│         │                │                │                                      │
│         └────────────────┼────────────────┘                                      │
│                          ▼                                                       │
│  ┌───────────────────────────────────────────────────────────────────────────┐  │
│  │                    Application Layer (Command Handlers)                    │  │
│  │                                                                            │  │
│  │  AddCurrentMessageHandler ──► ICurrentMessageEventService.PublishAdded()  │  │
│  │  RemoveCurrentMessageHandler ► ICurrentMessageEventService.PublishRemoved()│  │
│  │                                                                            │  │
│  └───────────────────────────────────────────────────────────────────────────┘  │
│                          │                                                       │
│                          ▼                                                       │
│  ┌───────────────────────────────────────────────────────────────────────────┐  │
│  │                    Infrastructure Layer (Singleton Service)                │  │
│  │                                                                            │  │
│  │  CurrentMessageEventService (using System.Reactive)                        │  │
│  │  ├── Subject<CurrentMessageChangeEvent>                                    │  │
│  │  ├── OnCurrentMessageChanged() → IObservable<event>                        │  │
│  │  ├── OnCurrentMessageAdded() → IObservable<event> (filtered)               │  │
│  │  └── OnCurrentMessageRemoved() → IObservable<event> (filtered)             │  │
│  │                                                                            │  │
│  └───────────────────────────────────────────────────────────────────────────┘  │
│                          │                                                       │
│                          ▼                                                       │
│  ┌───────────────────────────────────────────────────────────────────────────┐  │
│  │                    GraphQL Subscriptions (WebSocket)                       │  │
│  │                                                                            │  │
│  │  StatisticsSubscriptions                                                   │  │
│  │  ├── onCurrentMessageChanged                                               │  │
│  │  ├── onCurrentMessageAdded                                                 │  │
│  │  ├── onCurrentMessageRemoved                                               │  │
│  │  └── onAllCurrentMessages (periodic refresh + change trigger)              │  │
│  │                                                                            │  │
│  └───────────────────────────────────────────────────────────────────────────┘  │
│                          │                                                       │
│                          ▼                                                       │
│  ┌───────────────────────────────────────────────────────────────────────────┐  │
│  │                    GraphQL Clients (Browser, Mobile, etc.)                 │  │
│  └───────────────────────────────────────────────────────────────────────────┘  │
│                                                                                  │
└─────────────────────────────────────────────────────────────────────────────────┘

Key Design Decisions:

  1. Event Service in Infrastructure Layer: The ICurrentMessageEventService interface is defined in Application.Ports, with the implementation in Infrastructure.Services. This ensures all APIs share the same event stream.

  2. Singleton Registration: The service is registered as a singleton to maintain a single event stream across all API requests.

  3. Application-Layer Publishing: Events are published from command handlers (not API adapters), ensuring consistency regardless of which API triggers the operation.

  4. Reactive Extensions: Uses System.Reactive for pub/sub pattern with type-safe event filtering.

Future Enhancements (Low Priority)

Additional Subscriptions (Real-time updates)

  • onProcessCompleted - Subscribe to process completion events
  • onMeasurementRecorded - Subscribe to new measurements
  • onWpcStateChanged - Subscribe to WPC state changes

Performance Optimizations

  • Implement DataLoaders to prevent N+1 queries
  • Add response caching for frequently accessed data
  • Configure query complexity analysis

Security

  • Add authentication middleware
  • Implement authorization policies
  • Configure rate limiting
  • Disable introspection in production

Configuration

GraphQL Endpoint

  • Development: http://localhost:5000/graphql
  • Banana Cake Pop IDE: Available at /graphql in browser (Development mode)

Key Configuration in Program.cs

builder.Services
    .AddGraphQLServer()
    .BindRuntimeType<sbyte, HotChocolate.Types.ShortType>()  // sbyte mapping
    .AddType(new ObjectType<Robot>(d => d.Ignore(r => r.DomainEvents)))  // Hide domain events
    .AddQueryType()
    .AddTypeExtension<ProductQueries>()
    // ... other query extensions
    .AddMutationType()
    .AddTypeExtension<ProductMutations>()
    // ... other mutation extensions
    .AddSubscriptionType()
    .AddTypeExtension<StatisticsSubscriptions>()
    .AddInMemorySubscriptions()
    .AddFiltering()
    .AddSorting()
    .AddProjections()
    .ModifyRequestOptions(opt => opt.IncludeExceptionDetails = builder.Environment.IsDevelopment())
    .DisableIntrospection(!builder.Environment.IsDevelopment() && !builder.Environment.IsEnvironment("Test"));

// WebSocket support for subscriptions
app.UseWebSockets();
app.MapGraphQL();

Example Queries

Search Products

query {
  searchProducts(searchTerm: "test") {
    uid
    name
    type
    displayName
  }
}

Get Product with Versions

query {
  productById(uid: 1) {
    id { value }
    name
    isActive
  }
  versionsForProduct(productUid: 1) {
    uid
    versionName
    favorite
    released
  }
}

Get Active Manufacturing Processes

query {
  activeProcesses(skip: 0, take: 10) {
    orderNumber { value }
    serialNumber { value }
  }
}

Create Product with Parameters

mutation {
  createProductWithParameters(input: {
    productName: "NewProduct"
    displayName: "New Product"
    articleNumber: "ART-001"
    versionName: "V1.0"
    creator: "System"
    parameterSetups: [
      { systemType: "TH", mapping: "TH_Main", setupUid: 1 }
    ]
  }) {
    productUid
    versionUid
    success
    message
    parameterMappings {
      systemType
      mappingUid
      success
    }
  }
}

Example Subscriptions

Subscribe to Current Message Changes

subscription {
  onCurrentMessageChanged {
    changeType
    messageId
    timestamp
    message {
      messageId
      messageDE
      messageEN
      classId
    }
  }
}

Subscribe to All Current Messages (with periodic refresh)

subscription {
  onAllCurrentMessages {
    timestamp
    messages {
      messageId
      messageDE
      messageEN
      classNameDE
      classNameEN
    }
  }
}

Running the API

# Build
cd Essert.MF.API.GraphQL
dotnet build

# Run
dotnet run

# Run tests
cd Essert.MF.API.GraphQL.Tests
dotnet test

Last updated: 2025-12-03