Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@discriminates opaqueType clashing with named type #24

Open
darylgraham opened this issue Oct 28, 2024 · 0 comments
Open

@discriminates opaqueType clashing with named type #24

darylgraham opened this issue Oct 28, 2024 · 0 comments

Comments

@darylgraham
Copy link

Alternate issue title: @Discriminates needs a hierarchy traversal restriction

I was using the standard schema from @frontside/backstage-plugin-graphql-backend-module-catalog and came across an interesting condition.

For reference, here is a snippet of the shipped schema file:

extend interface Entity @discriminates(with: "kind", opaqueType: "OpaqueEntity") {
  name: String! @field(at: "metadata.name")
  kind: String! @field(at: "kind")
  ...
}

interface Component
  @implements(interface: "Entity")
  @discriminates(with: "spec.type", opaqueType: "OpaqueComponent")
  @discriminationAlias(value: "service", type: "Service")
  @discriminationAlias(value: "website", type: "Website")
  @discriminationAlias(value: "library", type: "Library") {
  type: String! @field(at: "spec.type")
  ...
}

interface Resource
  @implements(interface: "Entity")
  @discriminates(with: "spec.type", opaqueType: "OpaqueResource")
  @discriminationAlias(value: "database", type: "Database") {
  type: String! @field(at: "spec.type")
  ...
}

Component and Resource are both entities that extend the Entity interface, and they both have a field spec.type which is used to drill down to more specific entity types via @discriminates.

In my catalog I have a Resource that is described with spec.type: service, which causes an error to occur when querying the graphql endpoint:

Query:

{
  entities(first: 10, filter: { match: { kind:"Resource"} }) {
    edges {
      node {
        kind
        name
        namespace
      }
    }
  }
}

Error message in the GraphiQL client:

{
  "errors": [
    {
      "message": "Unexpected error.",
      "locations": [
        {
          "line": 4,
          "column": 7
        }
      ],
      "path": [
        "entities",
        "edges",
        1,
        "node"
      ],
      "extensions": {
        "originalError": {
          "message": "Can't resolve type for node with \"Node@Catalog@{\"ref\":\"resource:digital/live-feeder-db\"}\" id. The \"Service\" type which was discriminated by Resource interface does not implement the \"Resource\" interface",
          "stack": "Error: Can't resolve type for node with \"Node@Catalog@{\"ref\":\"resource:digital/live-feeder-db\"}\" id. The \"Service\" type which was discriminated by Resource interface does not implement the \"Resource\" interface\n    at GraphQLInterfaceType.resolveType (/workspaces/backstage/backstage/node_modules/@frontside/hydraphql/src/mapInterfaceType.ts:242:19)\n    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n    at async /workspaces/backstage/backstage/node_modules/@graphql-tools/executor/cjs/execution/promiseForObject.js:18:35\n    at async Promise.all (index 0)"
        }
      }
    }
  ],
  "data": {
    "entities": null
  }
}

In the backend logs:

2024-10-27T23:58:42.545Z graphql error Can't resolve type for node with "Node@Catalog@{"ref":"resource:digital/live-feeder-db"}" id. The "Service" type which was discriminated by Resource interface does not implement the "Resource" interface

GraphQL request:4:7
3 |     edges {
4 |       node {
  |       ^
5 |         kind 

I can resolve the error by updating the schema to this:

interface Component
  @implements(interface: "Entity")
  @discriminates(with: "spec.type", opaqueType: "OpaqueComponent")
  @discriminationAlias(value: "service", type: "ServiceComponent")
  @discriminationAlias(value: "website", type: "WebsiteComponent")
  @discriminationAlias(value: "library", type: "LibraryComponent") {
  type: String! @field(at: "spec.type")
  ...
}

interface Resource
  @implements(interface: "Entity")
  @discriminates(with: "spec.type", opaqueType: "OpaqueResource")
  @discriminationAlias(value: "service", type: "ServiceResource")
  @discriminationAlias(value: "database", type: "DatabaseResource") {
  type: String! @field(at: "spec.type")
  ...
}

It looks like the request is matching the @discriminate function on Entity to map the entity to a Resource, but then when Resource discriminates the spec.type field, it is reading the definition from Component for type Service instead of using opaqueType.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant