Hi guys, I am self hosting hive with composite server, and using a MS architecture coupled with several MS that push their schema to hive.
Apollo router then queries hive for the schema and router the traffic. All is working very well, except federation. I’m using federation V1, as hive does not seem to be compatible with V2 yet ( I was getting KeySet! value is not _KeySet! or something).
My question is I am getting this error when trying to set up federation:
{
"data": {
"property": null
},
"errors": [
{
"message": "service 'apartment' response was malformed: invalid value: integer `-1`, expected u32",
"extensions": {
"service": "apartment",
"reason": "invalid value: integer `-1`, expected u32",
"code": "SUBREQUEST_MALFORMED_RESPONSE"
}
}
],
"extensions": {
"valueCompletion": [
{
"message": "Cannot return null for non-nullable field Property.apartments",
"path": [
"property"
]
}
]
}
}
The query get’s to the property MS, but never I see any logs in the apartment MS that would indicate that the query get’s that far.
Here are the 2 subgraphs registered in hive for Apartments/Properties:
"Marks the field, argument, input field or enum value as deprecated"
directive @deprecated(
"The reason for the deprecation"
reason: String = "No longer supported"
) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION
"Marks target object as extending part of the federated schema"
directive @extends on OBJECT | INTERFACE
"Marks target field as external meaning it will be resolved by federated schema"
directive @external on FIELD_DEFINITION
"Directs the executor to include this field or fragment only when the `if` argument is true"
directive @include(
"Included when true."
if: Boolean!
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Space separated list of primary keys needed to access federated object"
directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE
"Specifies the base type field set that will be selectable by the gateway"
directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
"Specifies required input field set from the base type for a resolver"
directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(
"Skipped when true."
if: Boolean!
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Exposes a URL that specifies the behaviour of this scalar."
directive @specifiedBy(
"The URL that specifies the behaviour of this scalar."
url: String!
) on SCALAR
union _Entity = Property
type GraphqlPropertyDeleteOutput {
deleted: Boolean!
}
type Mutation {
"Create property mutation"
createProperty(input: GraphqlCreatePropertyInput!): Property
"Delete property mutation"
deleteProperty(input: GraphqlDeletePropertyInput!): GraphqlPropertyDeleteOutput
"Update property mutation"
updateProperty(input: GraphqlUpdatePropertyInput!): Property
}
type Property @key(fields: "primaryKey") {
capacity: Int!
city: String!
country: String!
createdAt: String!
currency: Currency!
description: String!
landlordName: String!
name: String!
numberOfFloors: Int!
numberOfRooms: Int!
ownerUUID: String!
postCode: String!
primaryKey: String!
propertyType: PropertyType!
sizeOfPropertyInSqM2: Int!
state: String!
street: String!
streetNr: Int!
updatedAt: String!
}
type Query @extends {
"Union of all types that use the @key directive, including both types native to the schema and extended types"
_entities(representations: [_Any!]!): [_Entity]!
_service: _Service!
"Filter properties query"
filterProperties(input: GraphqlFilterPropertiesInput!): [Property!]!
"Get property query"
getProperty(input: GraphqlGetPropertyInput!): Property
property(primaryKey: String!): Property
}
type _Service {
sdl: String!
}
enum Currency {
EURO
GBP
USD
}
enum PropertyType {
CO_LIVING_SPACES
SERVICED_APARTMENTS
STUDENT_ACCOMMODATION
}
"Federation scalar type used to represent any external entities passed to _entities query."
scalar _Any
"Federation type representing set of fields"
scalar _FieldSet
input GraphqlCreatePropertyInput {
capacity: Int!
city: String!
country: String!
currency: Currency!
description: String!
landlordName: String!
name: String!
numberOfFloors: Int!
numberOfRooms: Int!
ownerUUID: String!
postCode: String!
propertyType: PropertyType!
sizeOfPropertyInSqM2: Int!
state: String!
street: String!
streetNr: Int!
}
input GraphqlDeletePropertyInput {
primaryKey: String!
}
input GraphqlFilterPropertiesInput {
capacity: Int
city: String
country: String
name: String
ownerUUID: String
postCode: String
propertyType: PropertyType
state: String
}
input GraphqlGetPropertyInput {
primaryKey: String!
}
input GraphqlUpdatePropertyInput {
capacity: Int
city: String
country: String
currency: Currency
description: String
landlordName: String
name: String
numberOfFloors: Int
numberOfRooms: Int
ownerUUID: ID
postCode: String
primaryKey: String!
propertyType: PropertyType
sizeOfPropertyInSqM2: Int
state: String
street: String
streetNr: Int
}
"Marks the field, argument, input field or enum value as deprecated"
directive @deprecated(
"The reason for the deprecation"
reason: String = "No longer supported"
) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION
"Marks target object as extending part of the federated schema"
directive @extends on OBJECT | INTERFACE
"Marks target field as external meaning it will be resolved by federated schema"
directive @external on FIELD_DEFINITION
"Directs the executor to include this field or fragment only when the `if` argument is true"
directive @include(
"Included when true."
if: Boolean!
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Space separated list of primary keys needed to access federated object"
directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE
"Specifies the base type field set that will be selectable by the gateway"
directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
"Specifies required input field set from the base type for a resolver"
directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
"Directs the executor to skip this field or fragment when the `if` argument is true."
directive @skip(
"Skipped when true."
if: Boolean!
) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
"Exposes a URL that specifies the behaviour of this scalar."
directive @specifiedBy(
"The URL that specifies the behaviour of this scalar."
url: String!
) on SCALAR
union _Entity = Property
type Apartment {
apartmentType: ApartmentType!
capacity: Int!
cost: String!
createdAt: String!
description: String!
ensuite: Boolean!
name: String!
numberOfRooms: Int!
optionalAmenities: [String!]!
ownerUUID: String!
primaryKey: String!
secondaryKey: String!
sharedKitchen: Boolean!
sizeInSqm2: Int!
standardAmenities: [StandardAmenities!]!
updatedAt: String!
}
type GraphqlApartmentDeleteOutput {
deleted: Boolean!
}
type Mutation {
"Create apartment mutation"
createApartment(input: GraphqlCreateApartmentInput!): Apartment
"Delete apartment mutation"
deleteApartment(input: GraphqlDeleteApartmentInput!): GraphqlApartmentDeleteOutput
"Update apartment mutation"
updateApartment(input: GraphqlUpdateApartmentInput!): Apartment
}
type Property @extends @key(fields: "primaryKey") {
apartments: [Apartment!]!
primaryKey: String! @external
}
type Query @extends {
"Union of all types that use the @key directive, including both types native to the schema and extended types"
_entities(representations: [_Any!]!): [_Entity]!
_service: _Service!
apartment(primaryKey: String!): [Apartment!]
"Get all apartments for property query"
getAllApartmentsForProperty(input: GraphqlGetAllApartmentsInput!): [Apartment!]!
"Get apartment query"
getApartment(input: GraphqlGetApartmentInput!): Apartment
}
type _Service {
sdl: String!
}
enum ApartmentType {
CONDO
DUPLEX
GARDEN_APARTMENT
LOFT
PENTHOUSE
SERVICED_APARTMENT
SHARED_APARTMENT
STUDIO
}
enum StandardAmenities {
BEDDING
BICYCLE_STORAGE
CUBY_SUPPORT
FURNISHED
GYM
INDOOR_PARKING_SPACE
INDOOR_POOL
IN_HOUSE_SUPERMARKET
LETTER_BOX
OUTDOOR_PARKING_SPACE
OUTDOOR_POOL
POST_BOX
PUBLIC_PARKING
ROOFTOP_TERRACE
SAUNA
SHARED_LOBBY
SHARED_LOUNGE
STORAGE
TOWELS
TV
UTILITIES_EXPENSES
WI_FI
YOGA_STUDIO
}
"Federation scalar type used to represent any external entities passed to _entities query."
scalar _Any
"Federation type representing set of fields"
scalar _FieldSet
input GraphqlCreateApartmentInput {
apartmentType: ApartmentType!
capacity: Int!
cost: String!
description: String!
ensuite: Boolean!
name: String!
numOfRooms: Int!
optionalAmenities: [String!]!
ownerUUID: String!
primaryKey: String!
sharedKitchen: Boolean!
sizeInSqm2: Int!
standardAmenities: [StandardAmenities!]!
}
input GraphqlDeleteApartmentInput {
primaryKey: String!
secondaryKey: String!
}
input GraphqlGetAllApartmentsInput {
primaryKey: String!
}
input GraphqlGetApartmentInput {
primaryKey: String!
secondaryKey: String!
}
input GraphqlUpdateApartmentInput {
apartmentType: ApartmentType
capacity: Int
cost: String
description: String
ensuite: Boolean
name: String
numOfRooms: Int
optionalAmenities: [String!]
ownerUUID: String
primaryKey: String!
secondaryKey: String!
sharedKitchen: Boolean
sizeInSqm2: Int
standardAmenities: [StandardAmenities!]
}
I run Apollo router with this command
docker run --net=host --env HIVE_CDN_ENDPOINT="http://IP:8082/artifacts/v1/08cda34e-9dc0-4c3b-90cc-1b7782bca97e" --env HIVE_CDN_KEY="$TOKEN==" --env HIVE_TOKEN="$SECRET" --env HIVE_CDN_ACCEPT_INVALID_CERTS="true" --env APOLLO_ROUTER_SUPERGRAPH_URLS="http://IP:8082/artifacts/v1/08cda34e-9dc0-4c3b-90cc-1b7782bca97e/supergraph" --env APOLLO_ROUTER_LOG="debug" --env HIVE_ENDPOINT="http://IP:8081/usage" --mount "type=bind,source=/home/ec2-user/router.yaml,target=/dist/config/router.yaml" --rm -d --name=apollo-router ghcr.io/kamilkisiela/graphql-hive/apollo-router:latest```
and router.yaml file
```supergraph:
listen: 0.0.0.0:4000
introspection: true
plugins:
hive.usage:
{}
include_subgraph_errors:
all: true
cors:
allow_any_origin: true
health-check:
listen: 0.0.0.0:8088
enabled: true
homepage:
enabled: false
sandbox:
enabled: true
Any ideas guys?