Skip to content

Apply Apollo Federation

A common use-case when having multiple components (and/or external SaaS services) with a GraphQL API is to expose the APIs using a federated gateway.

This setup consists of two things:

  • A GraphQL (federated) Gateway component
  • One or more components exposing their own GraphQL API

Managed Apollo Federation Gateway setup

The Gateway components needs to implement the ApolloGateway and be connected to the Apollo Studio configured in the Site configuration.

Any component that uses the Apollo Federation integration must have the following Terraform variable defined:

variable "apollo_federation" {
  type = object({
    api_key       = string
    graph         = string
    graph_variant = string
  })
}

Make sure that in your runtime settings you set the following environment variables defined:

APOLLO_KEY = var.apollo_federation.api_key
APOLLO_GRAPH_VARIANT = var.apollo_federation.graph_variant

Downstream federated services apollo integration

Once a component is deployed (either added to your MACH stack or updated) it needs to update its schema in the Apollo Federation.

To do so we need to make this update call part of our deployment processes.

Apollo CLI

Make sure the Apollo CLI is available in the context where you're running mach.

Updating a downstream service

While there are some edge cases, in general you want to push after the new service is completely deployed. An example on how to do this:

locals {
  # URL which the gateway uses to access this service
  service_url       = "http://internal.some-gateway.com/some-component/graphql"
  # Exported schema of the service that is being deployed
  local_schema_file = "${path.module}/generated/schema.graphql"
  # identifier of the service for Apollo Studio
  service_name      = "some-component"
}

resource "null_resource" "apollo_push_schema_after_deploy" {
  triggers = {
    schema_hash  = filesha256(local.local_schema_file)
    service_name = local.service_name
    graph        = var.apollo_federation.graph
    variant      = var.apollo_federation.variant
  }

  provisioner "local-exec" {
    command = "apollo service:push --localSchemaFile=${local.local_schema_file} --key=${var.apollo_federation.api_key} --graph=${var.apollo_federation.graph} --variant=${var.apollo_federation.graph_variant} --serviceName=${local.serviceName} --serviceURL=${local.service_url}"
  }

  depends_on = [
    # list dependencies to make sure this is run before or after deployment of the service, f.e. an ecs service
    aws_ecs_service.some_component,
  ]
}

Deleting a downstream service

Deleting a service automatically is possible with some caveats:

resource "null_resource" "apollo_push_schema_after_deploy" {
  triggers = {
    schema_hash = filesha256(local.local_schema_file)
    # for destroy we can't use local variables, so include them in triggers
    service_name = local.service_name
    api_key = var.apollo_federation.api_key
    graph = var.apollo_federation.graph
    variant = var.apollo_federation.variant
  }

  provisioner "local-exec" {
    command = "apollo service:push --localSchemaFile=${local.local_schema_file} --key=${var.apollo_federation.api_key} --graph=${var.apollo_federation.graph} --variant=${var.apollo_federation.graph_variant} --serviceName=${local.serviceName} --serviceURL=${local.service_url}"
  }

  # note this command fails if it's the last federated service
  provisioner "local-exec" {
    when = destroy
    command = "apollo service:delete --yes --key=${self.triggers.api_key} --serviceName=${self.triggers.service_name} --variant=${self.triggers.variant} || true"
  }
}