The gcp:networkservices/httpRoute:HttpRoute resource, part of the Pulumi GCP provider, defines HTTP traffic routing rules for Mesh or Gateway resources: hostname matching, request filtering, and traffic actions. This guide focuses on four capabilities: hostname and query parameter matching, service mesh attachment, request matching with headers and paths, and fault injection and header modification.
HttpRoute resources attach to Mesh or Gateway resources and reference backend services that must exist separately. The examples are intentionally small. Combine them with your own mesh infrastructure, gateways, and backend services.
Route traffic based on hostname and query parameters
Most HTTP routing starts with simple hostname matching and query parameter filtering to direct requests to different backend services.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.networkservices.HttpRoute("default", {
name: "my-http-route",
labels: {
foo: "bar",
},
description: "my description",
hostnames: ["example"],
rules: [{
matches: [{
queryParameters: [{
queryParameter: "key",
exactMatch: "value",
}],
fullPathMatch: "example",
}],
}],
});
import pulumi
import pulumi_gcp as gcp
default = gcp.networkservices.HttpRoute("default",
name="my-http-route",
labels={
"foo": "bar",
},
description="my description",
hostnames=["example"],
rules=[{
"matches": [{
"query_parameters": [{
"query_parameter": "key",
"exact_match": "value",
}],
"full_path_match": "example",
}],
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkservices"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := networkservices.NewHttpRoute(ctx, "default", &networkservices.HttpRouteArgs{
Name: pulumi.String("my-http-route"),
Labels: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
Description: pulumi.String("my description"),
Hostnames: pulumi.StringArray{
pulumi.String("example"),
},
Rules: networkservices.HttpRouteRuleArray{
&networkservices.HttpRouteRuleArgs{
Matches: networkservices.HttpRouteRuleMatchArray{
&networkservices.HttpRouteRuleMatchArgs{
QueryParameters: networkservices.HttpRouteRuleMatchQueryParameterArray{
&networkservices.HttpRouteRuleMatchQueryParameterArgs{
QueryParameter: pulumi.String("key"),
ExactMatch: pulumi.String("value"),
},
},
FullPathMatch: pulumi.String("example"),
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.NetworkServices.HttpRoute("default", new()
{
Name = "my-http-route",
Labels =
{
{ "foo", "bar" },
},
Description = "my description",
Hostnames = new[]
{
"example",
},
Rules = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleArgs
{
Matches = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchArgs
{
QueryParameters = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchQueryParameterArgs
{
QueryParameter = "key",
ExactMatch = "value",
},
},
FullPathMatch = "example",
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkservices.HttpRoute;
import com.pulumi.gcp.networkservices.HttpRouteArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new HttpRoute("default", HttpRouteArgs.builder()
.name("my-http-route")
.labels(Map.of("foo", "bar"))
.description("my description")
.hostnames("example")
.rules(HttpRouteRuleArgs.builder()
.matches(HttpRouteRuleMatchArgs.builder()
.queryParameters(HttpRouteRuleMatchQueryParameterArgs.builder()
.queryParameter("key")
.exactMatch("value")
.build())
.fullPathMatch("example")
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:networkservices:HttpRoute
properties:
name: my-http-route
labels:
foo: bar
description: my description
hostnames:
- example
rules:
- matches:
- queryParameters:
- queryParameter: key
exactMatch: value
fullPathMatch: example
The hostnames property defines which HTTP Host headers this route matches. The rules array contains matching criteria and actions. Each match can filter on query parameters (exactMatch, regexMatch, presentMatch) and path patterns (fullPathMatch, prefixMatch, regexMatch). Without an action block, matched requests use default routing behavior.
Attach routes to a service mesh
Service mesh deployments use HttpRoute to define traffic routing rules that apply across sidecar proxies in the mesh.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.networkservices.Mesh("default", {
name: "my-http-route",
labels: {
foo: "bar",
},
description: "my description",
});
const defaultHttpRoute = new gcp.networkservices.HttpRoute("default", {
name: "my-http-route",
labels: {
foo: "bar",
},
description: "my description",
hostnames: ["example"],
meshes: [_default.id],
rules: [{
matches: [{
queryParameters: [{
queryParameter: "key",
exactMatch: "value",
}],
fullPathMatch: "example",
}],
}],
});
import pulumi
import pulumi_gcp as gcp
default = gcp.networkservices.Mesh("default",
name="my-http-route",
labels={
"foo": "bar",
},
description="my description")
default_http_route = gcp.networkservices.HttpRoute("default",
name="my-http-route",
labels={
"foo": "bar",
},
description="my description",
hostnames=["example"],
meshes=[default.id],
rules=[{
"matches": [{
"query_parameters": [{
"query_parameter": "key",
"exact_match": "value",
}],
"full_path_match": "example",
}],
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkservices"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := networkservices.NewMesh(ctx, "default", &networkservices.MeshArgs{
Name: pulumi.String("my-http-route"),
Labels: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
Description: pulumi.String("my description"),
})
if err != nil {
return err
}
_, err = networkservices.NewHttpRoute(ctx, "default", &networkservices.HttpRouteArgs{
Name: pulumi.String("my-http-route"),
Labels: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
Description: pulumi.String("my description"),
Hostnames: pulumi.StringArray{
pulumi.String("example"),
},
Meshes: pulumi.StringArray{
_default.ID(),
},
Rules: networkservices.HttpRouteRuleArray{
&networkservices.HttpRouteRuleArgs{
Matches: networkservices.HttpRouteRuleMatchArray{
&networkservices.HttpRouteRuleMatchArgs{
QueryParameters: networkservices.HttpRouteRuleMatchQueryParameterArray{
&networkservices.HttpRouteRuleMatchQueryParameterArgs{
QueryParameter: pulumi.String("key"),
ExactMatch: pulumi.String("value"),
},
},
FullPathMatch: pulumi.String("example"),
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.NetworkServices.Mesh("default", new()
{
Name = "my-http-route",
Labels =
{
{ "foo", "bar" },
},
Description = "my description",
});
var defaultHttpRoute = new Gcp.NetworkServices.HttpRoute("default", new()
{
Name = "my-http-route",
Labels =
{
{ "foo", "bar" },
},
Description = "my description",
Hostnames = new[]
{
"example",
},
Meshes = new[]
{
@default.Id,
},
Rules = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleArgs
{
Matches = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchArgs
{
QueryParameters = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchQueryParameterArgs
{
QueryParameter = "key",
ExactMatch = "value",
},
},
FullPathMatch = "example",
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkservices.Mesh;
import com.pulumi.gcp.networkservices.MeshArgs;
import com.pulumi.gcp.networkservices.HttpRoute;
import com.pulumi.gcp.networkservices.HttpRouteArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new Mesh("default", MeshArgs.builder()
.name("my-http-route")
.labels(Map.of("foo", "bar"))
.description("my description")
.build());
var defaultHttpRoute = new HttpRoute("defaultHttpRoute", HttpRouteArgs.builder()
.name("my-http-route")
.labels(Map.of("foo", "bar"))
.description("my description")
.hostnames("example")
.meshes(default_.id())
.rules(HttpRouteRuleArgs.builder()
.matches(HttpRouteRuleMatchArgs.builder()
.queryParameters(HttpRouteRuleMatchQueryParameterArgs.builder()
.queryParameter("key")
.exactMatch("value")
.build())
.fullPathMatch("example")
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:networkservices:Mesh
properties:
name: my-http-route
labels:
foo: bar
description: my description
defaultHttpRoute:
type: gcp:networkservices:HttpRoute
name: default
properties:
name: my-http-route
labels:
foo: bar
description: my description
hostnames:
- example
meshes:
- ${default.id}
rules:
- matches:
- queryParameters:
- queryParameter: key
exactMatch: value
fullPathMatch: example
The meshes property attaches this route to a Mesh resource, making the routing rules available to all services in the mesh. The Mesh must be of type SIDECAR. This extends basic hostname and query parameter matching by distributing the routing configuration across mesh-managed services.
Match requests with headers and apply redirects
Advanced routing often requires matching on multiple request attributes and applying transformations like redirects or URL rewrites.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.networkservices.HttpRoute("default", {
name: "my-http-route",
labels: {
foo: "bar",
},
description: "my description",
hostnames: ["example"],
rules: [{
matches: [
{
headers: [{
header: "header",
invertMatch: false,
regexMatch: "header-value",
}],
queryParameters: [{
queryParameter: "key",
exactMatch: "value",
}],
prefixMatch: "example",
ignoreCase: false,
},
{
headers: [{
header: "header",
invertMatch: false,
presentMatch: true,
}],
queryParameters: [{
queryParameter: "key",
regexMatch: "value",
}],
regexMatch: "example",
ignoreCase: false,
},
{
headers: [{
header: "header",
invertMatch: false,
presentMatch: true,
}],
queryParameters: [{
queryParameter: "key",
presentMatch: true,
}],
fullPathMatch: "example",
ignoreCase: false,
},
],
action: {
redirect: {
hostRedirect: "new-host",
pathRedirect: "new-path",
prefixRewrite: "new-prefix",
httpsRedirect: true,
stripQuery: true,
portRedirect: 8081,
},
urlRewrite: {
pathPrefixRewrite: "new-prefix",
hostRewrite: "new-host",
},
retryPolicy: {
retryConditions: ["server_error"],
numRetries: 1,
perTryTimeout: "1s",
},
requestMirrorPolicy: {
destination: {
serviceName: "new",
weight: 1,
},
},
corsPolicy: {
allowOrigins: ["example"],
allowMethods: [
"GET",
"PUT",
],
allowHeaders: [
"version",
"type",
],
exposeHeaders: [
"version",
"type",
],
maxAge: "1s",
allowCredentials: true,
disabled: false,
},
},
}],
});
import pulumi
import pulumi_gcp as gcp
default = gcp.networkservices.HttpRoute("default",
name="my-http-route",
labels={
"foo": "bar",
},
description="my description",
hostnames=["example"],
rules=[{
"matches": [
{
"headers": [{
"header": "header",
"invert_match": False,
"regex_match": "header-value",
}],
"query_parameters": [{
"query_parameter": "key",
"exact_match": "value",
}],
"prefix_match": "example",
"ignore_case": False,
},
{
"headers": [{
"header": "header",
"invert_match": False,
"present_match": True,
}],
"query_parameters": [{
"query_parameter": "key",
"regex_match": "value",
}],
"regex_match": "example",
"ignore_case": False,
},
{
"headers": [{
"header": "header",
"invert_match": False,
"present_match": True,
}],
"query_parameters": [{
"query_parameter": "key",
"present_match": True,
}],
"full_path_match": "example",
"ignore_case": False,
},
],
"action": {
"redirect": {
"host_redirect": "new-host",
"path_redirect": "new-path",
"prefix_rewrite": "new-prefix",
"https_redirect": True,
"strip_query": True,
"port_redirect": 8081,
},
"url_rewrite": {
"path_prefix_rewrite": "new-prefix",
"host_rewrite": "new-host",
},
"retry_policy": {
"retry_conditions": ["server_error"],
"num_retries": 1,
"per_try_timeout": "1s",
},
"request_mirror_policy": {
"destination": {
"service_name": "new",
"weight": 1,
},
},
"cors_policy": {
"allow_origins": ["example"],
"allow_methods": [
"GET",
"PUT",
],
"allow_headers": [
"version",
"type",
],
"expose_headers": [
"version",
"type",
],
"max_age": "1s",
"allow_credentials": True,
"disabled": False,
},
},
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkservices"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := networkservices.NewHttpRoute(ctx, "default", &networkservices.HttpRouteArgs{
Name: pulumi.String("my-http-route"),
Labels: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
Description: pulumi.String("my description"),
Hostnames: pulumi.StringArray{
pulumi.String("example"),
},
Rules: networkservices.HttpRouteRuleArray{
&networkservices.HttpRouteRuleArgs{
Matches: networkservices.HttpRouteRuleMatchArray{
&networkservices.HttpRouteRuleMatchArgs{
Headers: networkservices.HttpRouteRuleMatchHeaderArray{
&networkservices.HttpRouteRuleMatchHeaderArgs{
Header: pulumi.String("header"),
InvertMatch: pulumi.Bool(false),
RegexMatch: pulumi.String("header-value"),
},
},
QueryParameters: networkservices.HttpRouteRuleMatchQueryParameterArray{
&networkservices.HttpRouteRuleMatchQueryParameterArgs{
QueryParameter: pulumi.String("key"),
ExactMatch: pulumi.String("value"),
},
},
PrefixMatch: pulumi.String("example"),
IgnoreCase: pulumi.Bool(false),
},
&networkservices.HttpRouteRuleMatchArgs{
Headers: networkservices.HttpRouteRuleMatchHeaderArray{
&networkservices.HttpRouteRuleMatchHeaderArgs{
Header: pulumi.String("header"),
InvertMatch: pulumi.Bool(false),
PresentMatch: pulumi.Bool(true),
},
},
QueryParameters: networkservices.HttpRouteRuleMatchQueryParameterArray{
&networkservices.HttpRouteRuleMatchQueryParameterArgs{
QueryParameter: pulumi.String("key"),
RegexMatch: pulumi.String("value"),
},
},
RegexMatch: pulumi.String("example"),
IgnoreCase: pulumi.Bool(false),
},
&networkservices.HttpRouteRuleMatchArgs{
Headers: networkservices.HttpRouteRuleMatchHeaderArray{
&networkservices.HttpRouteRuleMatchHeaderArgs{
Header: pulumi.String("header"),
InvertMatch: pulumi.Bool(false),
PresentMatch: pulumi.Bool(true),
},
},
QueryParameters: networkservices.HttpRouteRuleMatchQueryParameterArray{
&networkservices.HttpRouteRuleMatchQueryParameterArgs{
QueryParameter: pulumi.String("key"),
PresentMatch: pulumi.Bool(true),
},
},
FullPathMatch: pulumi.String("example"),
IgnoreCase: pulumi.Bool(false),
},
},
Action: &networkservices.HttpRouteRuleActionArgs{
Redirect: &networkservices.HttpRouteRuleActionRedirectArgs{
HostRedirect: pulumi.String("new-host"),
PathRedirect: pulumi.String("new-path"),
PrefixRewrite: pulumi.String("new-prefix"),
HttpsRedirect: pulumi.Bool(true),
StripQuery: pulumi.Bool(true),
PortRedirect: pulumi.Int(8081),
},
UrlRewrite: &networkservices.HttpRouteRuleActionUrlRewriteArgs{
PathPrefixRewrite: pulumi.String("new-prefix"),
HostRewrite: pulumi.String("new-host"),
},
RetryPolicy: &networkservices.HttpRouteRuleActionRetryPolicyArgs{
RetryConditions: pulumi.StringArray{
pulumi.String("server_error"),
},
NumRetries: pulumi.Int(1),
PerTryTimeout: pulumi.String("1s"),
},
RequestMirrorPolicy: &networkservices.HttpRouteRuleActionRequestMirrorPolicyArgs{
Destination: &networkservices.HttpRouteRuleActionRequestMirrorPolicyDestinationArgs{
ServiceName: pulumi.String("new"),
Weight: pulumi.Int(1),
},
},
CorsPolicy: &networkservices.HttpRouteRuleActionCorsPolicyArgs{
AllowOrigins: pulumi.StringArray{
pulumi.String("example"),
},
AllowMethods: pulumi.StringArray{
pulumi.String("GET"),
pulumi.String("PUT"),
},
AllowHeaders: pulumi.StringArray{
pulumi.String("version"),
pulumi.String("type"),
},
ExposeHeaders: pulumi.StringArray{
pulumi.String("version"),
pulumi.String("type"),
},
MaxAge: pulumi.String("1s"),
AllowCredentials: pulumi.Bool(true),
Disabled: pulumi.Bool(false),
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.NetworkServices.HttpRoute("default", new()
{
Name = "my-http-route",
Labels =
{
{ "foo", "bar" },
},
Description = "my description",
Hostnames = new[]
{
"example",
},
Rules = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleArgs
{
Matches = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchArgs
{
Headers = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchHeaderArgs
{
Header = "header",
InvertMatch = false,
RegexMatch = "header-value",
},
},
QueryParameters = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchQueryParameterArgs
{
QueryParameter = "key",
ExactMatch = "value",
},
},
PrefixMatch = "example",
IgnoreCase = false,
},
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchArgs
{
Headers = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchHeaderArgs
{
Header = "header",
InvertMatch = false,
PresentMatch = true,
},
},
QueryParameters = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchQueryParameterArgs
{
QueryParameter = "key",
RegexMatch = "value",
},
},
RegexMatch = "example",
IgnoreCase = false,
},
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchArgs
{
Headers = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchHeaderArgs
{
Header = "header",
InvertMatch = false,
PresentMatch = true,
},
},
QueryParameters = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleMatchQueryParameterArgs
{
QueryParameter = "key",
PresentMatch = true,
},
},
FullPathMatch = "example",
IgnoreCase = false,
},
},
Action = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionArgs
{
Redirect = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionRedirectArgs
{
HostRedirect = "new-host",
PathRedirect = "new-path",
PrefixRewrite = "new-prefix",
HttpsRedirect = true,
StripQuery = true,
PortRedirect = 8081,
},
UrlRewrite = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionUrlRewriteArgs
{
PathPrefixRewrite = "new-prefix",
HostRewrite = "new-host",
},
RetryPolicy = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionRetryPolicyArgs
{
RetryConditions = new[]
{
"server_error",
},
NumRetries = 1,
PerTryTimeout = "1s",
},
RequestMirrorPolicy = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionRequestMirrorPolicyArgs
{
Destination = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionRequestMirrorPolicyDestinationArgs
{
ServiceName = "new",
Weight = 1,
},
},
CorsPolicy = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionCorsPolicyArgs
{
AllowOrigins = new[]
{
"example",
},
AllowMethods = new[]
{
"GET",
"PUT",
},
AllowHeaders = new[]
{
"version",
"type",
},
ExposeHeaders = new[]
{
"version",
"type",
},
MaxAge = "1s",
AllowCredentials = true,
Disabled = false,
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkservices.HttpRoute;
import com.pulumi.gcp.networkservices.HttpRouteArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionRedirectArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionUrlRewriteArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionRetryPolicyArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionRequestMirrorPolicyArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionRequestMirrorPolicyDestinationArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionCorsPolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new HttpRoute("default", HttpRouteArgs.builder()
.name("my-http-route")
.labels(Map.of("foo", "bar"))
.description("my description")
.hostnames("example")
.rules(HttpRouteRuleArgs.builder()
.matches(
HttpRouteRuleMatchArgs.builder()
.headers(HttpRouteRuleMatchHeaderArgs.builder()
.header("header")
.invertMatch(false)
.regexMatch("header-value")
.build())
.queryParameters(HttpRouteRuleMatchQueryParameterArgs.builder()
.queryParameter("key")
.exactMatch("value")
.build())
.prefixMatch("example")
.ignoreCase(false)
.build(),
HttpRouteRuleMatchArgs.builder()
.headers(HttpRouteRuleMatchHeaderArgs.builder()
.header("header")
.invertMatch(false)
.presentMatch(true)
.build())
.queryParameters(HttpRouteRuleMatchQueryParameterArgs.builder()
.queryParameter("key")
.regexMatch("value")
.build())
.regexMatch("example")
.ignoreCase(false)
.build(),
HttpRouteRuleMatchArgs.builder()
.headers(HttpRouteRuleMatchHeaderArgs.builder()
.header("header")
.invertMatch(false)
.presentMatch(true)
.build())
.queryParameters(HttpRouteRuleMatchQueryParameterArgs.builder()
.queryParameter("key")
.presentMatch(true)
.build())
.fullPathMatch("example")
.ignoreCase(false)
.build())
.action(HttpRouteRuleActionArgs.builder()
.redirect(HttpRouteRuleActionRedirectArgs.builder()
.hostRedirect("new-host")
.pathRedirect("new-path")
.prefixRewrite("new-prefix")
.httpsRedirect(true)
.stripQuery(true)
.portRedirect(8081)
.build())
.urlRewrite(HttpRouteRuleActionUrlRewriteArgs.builder()
.pathPrefixRewrite("new-prefix")
.hostRewrite("new-host")
.build())
.retryPolicy(HttpRouteRuleActionRetryPolicyArgs.builder()
.retryConditions("server_error")
.numRetries(1)
.perTryTimeout("1s")
.build())
.requestMirrorPolicy(HttpRouteRuleActionRequestMirrorPolicyArgs.builder()
.destination(HttpRouteRuleActionRequestMirrorPolicyDestinationArgs.builder()
.serviceName("new")
.weight(1)
.build())
.build())
.corsPolicy(HttpRouteRuleActionCorsPolicyArgs.builder()
.allowOrigins("example")
.allowMethods(
"GET",
"PUT")
.allowHeaders(
"version",
"type")
.exposeHeaders(
"version",
"type")
.maxAge("1s")
.allowCredentials(true)
.disabled(false)
.build())
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:networkservices:HttpRoute
properties:
name: my-http-route
labels:
foo: bar
description: my description
hostnames:
- example
rules:
- matches:
- headers:
- header: header
invertMatch: false
regexMatch: header-value
queryParameters:
- queryParameter: key
exactMatch: value
prefixMatch: example
ignoreCase: false
- headers:
- header: header
invertMatch: false
presentMatch: true
queryParameters:
- queryParameter: key
regexMatch: value
regexMatch: example
ignoreCase: false
- headers:
- header: header
invertMatch: false
presentMatch: true
queryParameters:
- queryParameter: key
presentMatch: true
fullPathMatch: example
ignoreCase: false
action:
redirect:
hostRedirect: new-host
pathRedirect: new-path
prefixRewrite: new-prefix
httpsRedirect: true
stripQuery: true
portRedirect: 8081
urlRewrite:
pathPrefixRewrite: new-prefix
hostRewrite: new-host
retryPolicy:
retryConditions:
- server_error
numRetries: 1
perTryTimeout: 1s
requestMirrorPolicy:
destination:
serviceName: new
weight: 1
corsPolicy:
allowOrigins:
- example
allowMethods:
- GET
- PUT
allowHeaders:
- version
- type
exposeHeaders:
- version
- type
maxAge: 1s
allowCredentials: true
disabled: false
The matches array can include multiple criteria: headers (with regexMatch, presentMatch, invertMatch), query parameters, and path patterns. The action block defines what happens to matched requests. The redirect property sends HTTP 301/302 responses with new locations. The urlRewrite property modifies the request path before forwarding. The retryPolicy configures automatic retry behavior for failed requests. The corsPolicy controls cross-origin resource sharing headers.
Inject faults and modify headers for testing
Chaos engineering and integration testing require fault injection and header manipulation to simulate failure scenarios.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.networkservices.HttpRoute("default", {
name: "my-http-route",
labels: {
foo: "bar",
},
description: "my description",
hostnames: ["example"],
rules: [{
action: {
faultInjectionPolicy: {
delay: {
fixedDelay: "1s",
percentage: 1,
},
abort: {
httpStatus: 500,
percentage: 1,
},
},
urlRewrite: {
pathPrefixRewrite: "new-prefix",
hostRewrite: "new-host",
},
retryPolicy: {
retryConditions: ["server_error"],
numRetries: 1,
perTryTimeout: "1s",
},
requestMirrorPolicy: {
destination: {
serviceName: "new",
weight: 1,
},
},
corsPolicy: {
allowOrigins: ["example"],
allowMethods: [
"GET",
"PUT",
],
allowHeaders: [
"version",
"type",
],
exposeHeaders: [
"version",
"type",
],
maxAge: "1s",
allowCredentials: true,
disabled: false,
},
requestHeaderModifier: {
set: {
version: "1",
type: "json",
},
add: {
"minor-version": "1",
},
removes: ["arg"],
},
responseHeaderModifier: {
set: {
version: "1",
type: "json",
},
add: {
"minor-version": "1",
},
removes: ["removearg"],
},
},
}],
});
import pulumi
import pulumi_gcp as gcp
default = gcp.networkservices.HttpRoute("default",
name="my-http-route",
labels={
"foo": "bar",
},
description="my description",
hostnames=["example"],
rules=[{
"action": {
"fault_injection_policy": {
"delay": {
"fixed_delay": "1s",
"percentage": 1,
},
"abort": {
"http_status": 500,
"percentage": 1,
},
},
"url_rewrite": {
"path_prefix_rewrite": "new-prefix",
"host_rewrite": "new-host",
},
"retry_policy": {
"retry_conditions": ["server_error"],
"num_retries": 1,
"per_try_timeout": "1s",
},
"request_mirror_policy": {
"destination": {
"service_name": "new",
"weight": 1,
},
},
"cors_policy": {
"allow_origins": ["example"],
"allow_methods": [
"GET",
"PUT",
],
"allow_headers": [
"version",
"type",
],
"expose_headers": [
"version",
"type",
],
"max_age": "1s",
"allow_credentials": True,
"disabled": False,
},
"request_header_modifier": {
"set": {
"version": "1",
"type": "json",
},
"add": {
"minor-version": "1",
},
"removes": ["arg"],
},
"response_header_modifier": {
"set": {
"version": "1",
"type": "json",
},
"add": {
"minor-version": "1",
},
"removes": ["removearg"],
},
},
}])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkservices"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := networkservices.NewHttpRoute(ctx, "default", &networkservices.HttpRouteArgs{
Name: pulumi.String("my-http-route"),
Labels: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
Description: pulumi.String("my description"),
Hostnames: pulumi.StringArray{
pulumi.String("example"),
},
Rules: networkservices.HttpRouteRuleArray{
&networkservices.HttpRouteRuleArgs{
Action: &networkservices.HttpRouteRuleActionArgs{
FaultInjectionPolicy: &networkservices.HttpRouteRuleActionFaultInjectionPolicyArgs{
Delay: &networkservices.HttpRouteRuleActionFaultInjectionPolicyDelayArgs{
FixedDelay: pulumi.String("1s"),
Percentage: pulumi.Int(1),
},
Abort: &networkservices.HttpRouteRuleActionFaultInjectionPolicyAbortArgs{
HttpStatus: pulumi.Int(500),
Percentage: pulumi.Int(1),
},
},
UrlRewrite: &networkservices.HttpRouteRuleActionUrlRewriteArgs{
PathPrefixRewrite: pulumi.String("new-prefix"),
HostRewrite: pulumi.String("new-host"),
},
RetryPolicy: &networkservices.HttpRouteRuleActionRetryPolicyArgs{
RetryConditions: pulumi.StringArray{
pulumi.String("server_error"),
},
NumRetries: pulumi.Int(1),
PerTryTimeout: pulumi.String("1s"),
},
RequestMirrorPolicy: &networkservices.HttpRouteRuleActionRequestMirrorPolicyArgs{
Destination: &networkservices.HttpRouteRuleActionRequestMirrorPolicyDestinationArgs{
ServiceName: pulumi.String("new"),
Weight: pulumi.Int(1),
},
},
CorsPolicy: &networkservices.HttpRouteRuleActionCorsPolicyArgs{
AllowOrigins: pulumi.StringArray{
pulumi.String("example"),
},
AllowMethods: pulumi.StringArray{
pulumi.String("GET"),
pulumi.String("PUT"),
},
AllowHeaders: pulumi.StringArray{
pulumi.String("version"),
pulumi.String("type"),
},
ExposeHeaders: pulumi.StringArray{
pulumi.String("version"),
pulumi.String("type"),
},
MaxAge: pulumi.String("1s"),
AllowCredentials: pulumi.Bool(true),
Disabled: pulumi.Bool(false),
},
RequestHeaderModifier: &networkservices.HttpRouteRuleActionRequestHeaderModifierArgs{
Set: pulumi.StringMap{
"version": pulumi.String("1"),
"type": pulumi.String("json"),
},
Add: pulumi.StringMap{
"minor-version": pulumi.String("1"),
},
Removes: pulumi.StringArray{
pulumi.String("arg"),
},
},
ResponseHeaderModifier: &networkservices.HttpRouteRuleActionResponseHeaderModifierArgs{
Set: pulumi.StringMap{
"version": pulumi.String("1"),
"type": pulumi.String("json"),
},
Add: pulumi.StringMap{
"minor-version": pulumi.String("1"),
},
Removes: pulumi.StringArray{
pulumi.String("removearg"),
},
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.NetworkServices.HttpRoute("default", new()
{
Name = "my-http-route",
Labels =
{
{ "foo", "bar" },
},
Description = "my description",
Hostnames = new[]
{
"example",
},
Rules = new[]
{
new Gcp.NetworkServices.Inputs.HttpRouteRuleArgs
{
Action = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionArgs
{
FaultInjectionPolicy = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionFaultInjectionPolicyArgs
{
Delay = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionFaultInjectionPolicyDelayArgs
{
FixedDelay = "1s",
Percentage = 1,
},
Abort = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionFaultInjectionPolicyAbortArgs
{
HttpStatus = 500,
Percentage = 1,
},
},
UrlRewrite = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionUrlRewriteArgs
{
PathPrefixRewrite = "new-prefix",
HostRewrite = "new-host",
},
RetryPolicy = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionRetryPolicyArgs
{
RetryConditions = new[]
{
"server_error",
},
NumRetries = 1,
PerTryTimeout = "1s",
},
RequestMirrorPolicy = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionRequestMirrorPolicyArgs
{
Destination = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionRequestMirrorPolicyDestinationArgs
{
ServiceName = "new",
Weight = 1,
},
},
CorsPolicy = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionCorsPolicyArgs
{
AllowOrigins = new[]
{
"example",
},
AllowMethods = new[]
{
"GET",
"PUT",
},
AllowHeaders = new[]
{
"version",
"type",
},
ExposeHeaders = new[]
{
"version",
"type",
},
MaxAge = "1s",
AllowCredentials = true,
Disabled = false,
},
RequestHeaderModifier = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionRequestHeaderModifierArgs
{
Set =
{
{ "version", "1" },
{ "type", "json" },
},
Add =
{
{ "minor-version", "1" },
},
Removes = new[]
{
"arg",
},
},
ResponseHeaderModifier = new Gcp.NetworkServices.Inputs.HttpRouteRuleActionResponseHeaderModifierArgs
{
Set =
{
{ "version", "1" },
{ "type", "json" },
},
Add =
{
{ "minor-version", "1" },
},
Removes = new[]
{
"removearg",
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkservices.HttpRoute;
import com.pulumi.gcp.networkservices.HttpRouteArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionFaultInjectionPolicyArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionFaultInjectionPolicyDelayArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionFaultInjectionPolicyAbortArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionUrlRewriteArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionRetryPolicyArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionRequestMirrorPolicyArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionRequestMirrorPolicyDestinationArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionCorsPolicyArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionRequestHeaderModifierArgs;
import com.pulumi.gcp.networkservices.inputs.HttpRouteRuleActionResponseHeaderModifierArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new HttpRoute("default", HttpRouteArgs.builder()
.name("my-http-route")
.labels(Map.of("foo", "bar"))
.description("my description")
.hostnames("example")
.rules(HttpRouteRuleArgs.builder()
.action(HttpRouteRuleActionArgs.builder()
.faultInjectionPolicy(HttpRouteRuleActionFaultInjectionPolicyArgs.builder()
.delay(HttpRouteRuleActionFaultInjectionPolicyDelayArgs.builder()
.fixedDelay("1s")
.percentage(1)
.build())
.abort(HttpRouteRuleActionFaultInjectionPolicyAbortArgs.builder()
.httpStatus(500)
.percentage(1)
.build())
.build())
.urlRewrite(HttpRouteRuleActionUrlRewriteArgs.builder()
.pathPrefixRewrite("new-prefix")
.hostRewrite("new-host")
.build())
.retryPolicy(HttpRouteRuleActionRetryPolicyArgs.builder()
.retryConditions("server_error")
.numRetries(1)
.perTryTimeout("1s")
.build())
.requestMirrorPolicy(HttpRouteRuleActionRequestMirrorPolicyArgs.builder()
.destination(HttpRouteRuleActionRequestMirrorPolicyDestinationArgs.builder()
.serviceName("new")
.weight(1)
.build())
.build())
.corsPolicy(HttpRouteRuleActionCorsPolicyArgs.builder()
.allowOrigins("example")
.allowMethods(
"GET",
"PUT")
.allowHeaders(
"version",
"type")
.exposeHeaders(
"version",
"type")
.maxAge("1s")
.allowCredentials(true)
.disabled(false)
.build())
.requestHeaderModifier(HttpRouteRuleActionRequestHeaderModifierArgs.builder()
.set(Map.ofEntries(
Map.entry("version", "1"),
Map.entry("type", "json")
))
.add(Map.of("minor-version", "1"))
.removes("arg")
.build())
.responseHeaderModifier(HttpRouteRuleActionResponseHeaderModifierArgs.builder()
.set(Map.ofEntries(
Map.entry("version", "1"),
Map.entry("type", "json")
))
.add(Map.of("minor-version", "1"))
.removes("removearg")
.build())
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:networkservices:HttpRoute
properties:
name: my-http-route
labels:
foo: bar
description: my description
hostnames:
- example
rules:
- action:
faultInjectionPolicy:
delay:
fixedDelay: 1s
percentage: 1
abort:
httpStatus: 500
percentage: 1
urlRewrite:
pathPrefixRewrite: new-prefix
hostRewrite: new-host
retryPolicy:
retryConditions:
- server_error
numRetries: 1
perTryTimeout: 1s
requestMirrorPolicy:
destination:
serviceName: new
weight: 1
corsPolicy:
allowOrigins:
- example
allowMethods:
- GET
- PUT
allowHeaders:
- version
- type
exposeHeaders:
- version
- type
maxAge: 1s
allowCredentials: true
disabled: false
requestHeaderModifier:
set:
version: '1'
type: json
add:
minor-version: '1'
removes:
- arg
responseHeaderModifier:
set:
version: '1'
type: json
add:
minor-version: '1'
removes:
- removearg
The faultInjectionPolicy introduces artificial delays (fixedDelay) and errors (abort with httpStatus) to test resilience. The percentage field controls what fraction of requests experience the fault. The requestHeaderModifier and responseHeaderModifier blocks add, set, or remove headers. These actions combine with urlRewrite, retryPolicy, and corsPolicy to create comprehensive traffic management rules.
Beyond these examples
These snippets focus on specific HttpRoute features: hostname and path-based routing, request matching (headers, query parameters, paths), and traffic actions (redirects, rewrites, retries, CORS, fault injection). They’re intentionally minimal rather than full traffic management configurations.
The examples may reference pre-existing infrastructure such as Mesh resources for service mesh deployments, Gateway resources for ingress routing, and backend services referenced by routing rules. They focus on configuring the route rather than provisioning the surrounding infrastructure.
To keep things focused, common routing patterns are omitted, including:
- Traffic splitting and weighted routing (destinations with weights)
- Gateway attachment for ingress use cases
- Timeout configuration (timeout property)
- Request/response header modification in combination with other actions
These omissions are intentional: the goal is to illustrate how each routing feature is wired, not provide drop-in traffic management modules. See the HttpRoute resource reference for all available configuration options.
Let's configure GCP HTTP Routes
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Immutability
name and project properties are immutable and will force resource replacement if changed.hostnames (set of hosts to match against HTTP host header), name (resource name), and rules (traffic routing/handling rules).projects/{{project}}/locations/global/httpRoutes/{{name}}), project and name ({{project}}/{{name}}), or just name ({{name}}).Routing & Attachment
meshes to attach to mesh resources (for service mesh routing) or gateways to attach to gateway resources (for ingress routing). Each requires specific resource path patterns.meshes property with mesh IDs matching the pattern projects/*/locations/global/meshes/<mesh_name>. The attached mesh must be of type SIDECAR.Traffic Matching & Actions
queryParameters), headers (headers), and path patterns (fullPathMatch, prefixMatch, regexMatch). Each supports different match types like exact, regex, or presence checks.retryPolicy in the action block with retryConditions (like server_error), numRetries, and perTryTimeout (duration string like 1s).Advanced Features
faultInjectionPolicy in the action block to configure delay (with fixedDelay and percentage) and abort (with httpStatus and percentage).requestHeaderModifier or responseHeaderModifier in the action block. Both support set (replace), add (append), and removes (delete) operations on headers.Labels & Metadata
labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to see all labels present on the resource in GCP, including those set by other clients and services.Using a different cloud?
Explore networking guides for other cloud providers: