Update headline of the "removal of types" doc page to match changes in 7.0. (#40868)

Currently it describes what broke in 6.0.

[[removal-of-types]]
== Removal of mapping types

IMPORTANT: Indices created in Elasticsearch 7.0.0 or later no longer accept a
`_default_` mapping. Indices created in 6.x will continue to function as before
in Elasticsearch 6.x. Types are deprecated in APIs in 7.0, with breaking changes
to the index creation, put mapping, get mapping, put template, get template and
get field mappings APIs.

[float]
=== What are mapping types?

Since the first release of Elasticsearch, each document has been stored in a
single index and assigned a single mapping type.  A mapping type was used to
represent the type of document or entity being indexed, for instance a
`twitter` index might have a `user` type and a `tweet` type.

Each mapping type could have its own fields, so the `user` type might have a
`full_name` field, a `user_name` field, and an `email` field, while the
`tweet` type could have a `content` field, a `tweeted_at` field and, like the
`user` type, a `user_name` field.

Each document had a `_type` meta-field containing the type name, and searches
could be limited to one or more types by specifying the type name(s) in the
URL:

[source,js]
----
GET twitter/user,tweet/_search
{
  "query": {
    "match": {
      "user_name": "kimchy"
    }
  }
}
----
// NOTCONSOLE

The `_type` field was combined with the document's `_id` to generate a `_uid`
field, so documents of different types with the same `_id` could exist in a
single index.

Mapping types were also used to establish a
<<mapping-parent-field,parent-child relationship>>
between documents, so documents of type `question` could be parents to
documents of type `answer`.

[float]
=== Why are mapping types being removed?

Initially, we spoke about an ``index'' being similar to a ``database'' in an
SQL database, and a ``type'' being equivalent to a
``table''.

This was a bad analogy that led to incorrect assumptions. In an SQL database,
tables are independent of each other.  The columns in one table have no
bearing on columns with the same name in another table.  This is not the case
for fields in a mapping type.

In an Elasticsearch index, fields that have the same name in different mapping
types are backed by the same Lucene field internally.  In other words, using
the example above, the `user_name` field in the `user` type is stored in
exactly the same field as the `user_name` field in the `tweet` type, and both
`user_name` fields must have the same mapping (definition) in both types.

This can lead to frustration when, for example, you want `deleted` to be a
`date` field in one type and a `boolean` field in another type in the same
index.

On top of that, storing different entities that have few or no fields in
common in the same index leads to sparse data and interferes with Lucene's
ability to compress documents efficiently.

For these reasons, we have decided to remove the concept of mapping types from
Elasticsearch.

[float]
=== Alternatives to mapping types

[float]
==== Index per document type

The first alternative is to have an index per document type.  Instead of
storing tweets and users in a single `twitter` index, you could store tweets
in the `tweets` index and users in the `user` index. Indices are completely
independent of each other and so there will be no conflict of field types
between indices.

This approach has two benefits:

* Data is more likely to be dense and so benefit from compression techniques
  used in Lucene.

* The term statistics used for scoring in full text search are more likely to
  be accurate because all documents in the same index represent a single
  entity.

Each index can be sized appropriately for the number of documents it will
contain: you can use a smaller number of primary shards for `users` and a
larger number of primary shards for `tweets`.

[float]
==== Custom type field

Of course, there is a limit to how many primary shards can exist in a cluster
so you may not want to waste an entire shard for a collection of only a few
thousand documents.  In this case, you can implement your own custom `type`
field which will work in a similar way to the old `_type`.

Let's take the `user`/`tweet` example above.  Originally, the workflow would
have looked something like this:

[source,js]
----
PUT twitter
{
  "mappings": {
    "user": {
      "properties": {
        "name": { "type": "text" },
        "user_name": { "type": "keyword" },
        "email": { "type": "keyword" }
      }
    },
    "tweet": {
      "properties": {
        "content": { "type": "text" },
        "user_name": { "type": "keyword" },
        "tweeted_at": { "type": "date" }
      }
    }
  }
}

PUT twitter/user/kimchy
{
  "name": "Shay Banon",
  "user_name": "kimchy",
  "email": "shay@kimchy.com"
}

PUT twitter/tweet/1
{
  "user_name": "kimchy",
  "tweeted_at": "2017-10-24T09:00:00Z",
  "content": "Types are going away"
}

GET twitter/tweet/_search
{
  "query": {
    "match": {
      "user_name": "kimchy"
    }
  }
}
----
// NOTCONSOLE

You can achieve the same thing by adding a custom `type` field as follows:

[source,js]
----
PUT twitter
{
  "mappings": {
    "_doc": {
      "properties": {
        "type": { "type": "keyword" }, <1>
        "name": { "type": "text" },
        "user_name": { "type": "keyword" },
        "email": { "type": "keyword" },
        "content": { "type": "text" },
        "tweeted_at": { "type": "date" }
      }
    }
  }
}

PUT twitter/_doc/user-kimchy
{
  "type": "user", <1>
  "name": "Shay Banon",
  "user_name": "kimchy",
  "email": "shay@kimchy.com"
}

PUT twitter/_doc/tweet-1
{
  "type": "tweet", <1>
  "user_name": "kimchy",
  "tweeted_at": "2017-10-24T09:00:00Z",
  "content": "Types are going away"
}

GET twitter/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "user_name": "kimchy"
        }
      },
      "filter": {
        "match": {
          "type": "tweet" <1>
        }
      }
    }
  }
}
----
// NOTCONSOLE
<1> The explicit `type` field takes the place of the implicit `_type` field.

[float]
==== Parent/Child without mapping types

Previously, a parent-child relationship was represented by making one mapping
type the parent, and one or more other mapping types the children.  Without
types, we can no longer use this syntax.  The parent-child feature will
continue to function as before, except that the way of expressing the
relationship between documents has been changed to use the new
<<parent-join,`join` field>>.

[float]
=== Schedule for removal of mapping types

This is a big change for our users, so we have tried to make it as painless as
possible.  The change will roll out as follows:

Elasticsearch 5.6.0::

* Setting `index.mapping.single_type: true` on an index will enable the
  single-type-per-index behaviour which will be enforced in 6.0.

* The <<parent-join,`join` field>> replacement for parent-child is available
  on indices created in 5.6.

Elasticsearch 6.x::

* Indices created in 5.x will continue to function in 6.x as they did in 5.x.

* Indices created in 6.x only allow a single-type per index.  Any name
  can be used for the type, but there can be only one. The preferred type name
  is `_doc`, so that index APIs have the same path as they will have in 7.0:
  `PUT {index}/_doc/{id}` and `POST {index}/_doc`

* The `_type` name can no longer be combined with the `_id` to form the `_uid`
  field. The `_uid` field has become an alias for the `_id` field.

* New indices no longer support the old-style of parent/child and should
  use the <<parent-join,`join` field>> instead.

* The `_default_` mapping type is deprecated.

* In 6.7, the index creation, index template, and mapping APIs support a query
  string parameter (`include_type_name`) which indicates whether requests and
  responses should include a type name. It defaults to `true`, and should be set
  to an explicit value to prepare to upgrade to 7.0. Not setting `include_type_name`
  will result in a deprecation warning. Indices which don't have an explicit type will
  use the dummy type name `_doc`.

Elasticsearch 7.x::

* Specifying types in requests is deprecated. For instance, indexing a
  document no longer requires a document `type`.  The new index APIs
  are `PUT {index}/_doc/{id}` in case of explicit ids and `POST {index}/_doc`
  for auto-generated ids.

* The `include_type_name` parameter in the index creation, index template,
  and mapping APIs will default to `false`. Setting the parameter at all will
  result in a deprecation warning.

* The `_default_` mapping type is removed.

Elasticsearch 8.x::

* Specifying types in requests is no longer supported.

* The `include_type_name` parameter is removed.

[float]
=== Migrating multi-type indices to single-type

The <<docs-reindex,Reindex API>> can be used to convert multi-type indices to
single-type indices. The following examples can be used in Elasticsearch 5.6
or Elasticsearch 6.x.  In 6.x, there is no need to specify
`index.mapping.single_type` as that is the default.

[float]
==== Index per document type

This first example splits our `twitter` index into a `tweets` index and a
`users` index:

[source,js]
----
PUT users
{
  "settings": {
    "index.mapping.single_type": true
  },
  "mappings": {
    "_doc": {
      "properties": {
        "name": {
          "type": "text"
        },
        "user_name": {
          "type": "keyword"
        },
        "email": {
          "type": "keyword"
        }
      }
    }
  }
}

PUT tweets
{
  "settings": {
    "index.mapping.single_type": true
  },
  "mappings": {
    "_doc": {
      "properties": {
        "content": {
          "type": "text"
        },
        "user_name": {
          "type": "keyword"
        },
        "tweeted_at": {
          "type": "date"
        }
      }
    }
  }
}

POST _reindex
{
  "source": {
    "index": "twitter",
    "type": "user"
  },
  "dest": {
    "index": "users"
  }
}

POST _reindex
{
  "source": {
    "index": "twitter",
    "type": "tweet"
  },
  "dest": {
    "index": "tweets"
  }
}
----
// NOTCONSOLE

[float]
==== Custom type field

This next example adds a custom `type` field and sets it to the value of the
original `_type`.  It also adds the type to the `_id` in case there are any
documents of different types which have conflicting IDs:

[source,js]
----
PUT new_twitter
{
  "mappings": {
    "_doc": {
      "properties": {
        "type": {
          "type": "keyword"
        },
        "name": {
          "type": "text"
        },
        "user_name": {
          "type": "keyword"
        },
        "email": {
          "type": "keyword"
        },
        "content": {
          "type": "text"
        },
        "tweeted_at": {
          "type": "date"
        }
      }
    }
  }
}

POST _reindex
{
  "source": {
    "index": "twitter"
  },
  "dest": {
    "index": "new_twitter"
  },
  "script": {
    "source": """
      ctx._source.type = ctx._type;
      ctx._id = ctx._type + '-' + ctx._id;
      ctx._type = '_doc';
    """
  }
}
----
// NOTCONSOLE

[float]
=== Typeless APIs in 7.0

In Elasticsearch 7.0, each API will support typeless requests,
and specifying a type will produce a deprecation warning.

NOTE: Typeless APIs work even if the target index contains a custom type.
For example, if an index has the the custom type name `my_type`, we can add
documents to it using typeless `index` calls, and load documents with typeless
`get` calls.

[float]
==== Indices APIs

Index creation, index template, and mapping APIs support a new `include_type_name`
URL parameter that specifies whether mapping definitions in requests and responses
should contain the type name. The parameter defaults to `true` in version 6.7 to
match the pre-7.0 behavior of using type names in mappings. It defaults to `false`
in version 7.0 and will be removed in version 8.0.

It should be set explicitly in 6.7 to prepare to upgrade to 7.0. To avoid deprecation
warnings in 6.7, the parameter can be set to either `true` or `false`. In 7.0, setting
`include_type_name` at all will result in a deprecation warning.

See some examples of interactions with Elasticsearch with this option set to `false`:

[source,js]
--------------------------------------------------
PUT index?include_type_name=false
{
  "mappings": {
    "properties": { <1>
      "foo": {
        "type": "keyword"
      }
    }
  }
}
--------------------------------------------------
// CONSOLE
<1> Mappings are included directly under the `mappings` key, without a type name.

[source,js]
--------------------------------------------------
PUT index/_mappings?include_type_name=false
{
  "properties": { <1>
    "bar": {
      "type": "text"
    }
  }
}
--------------------------------------------------
// CONSOLE
// TEST[continued]
<1> Mappings are included directly under the `mappings` key, without a type name.

[source,js]
--------------------------------------------------
GET index/_mappings?include_type_name=false
--------------------------------------------------
// CONSOLE
// TEST[continued]

The above call returns

[source,js]
--------------------------------------------------
{
  "index": {
    "mappings": {
      "properties": { <1>
        "foo": {
          "type": "keyword"
        },
        "bar": {
          "type": "text"
        }
      }
    }
  }
}
--------------------------------------------------
// TESTRESPONSE
<1> Mappings are included directly under the `mappings` key, without a type name.

[float]
==== Document APIs

In 7.0, index APIs must be called with the `{index}/_doc` path for automatic
generation of the `_id` and `{index}/_doc/{id}` with explicit ids.

[source,js]
--------------------------------------------------
PUT index/_doc/1
{
  "foo": "baz"
}
--------------------------------------------------
// CONSOLE

[source,js]
--------------------------------------------------
{
  "_index": "index",
  "_id": "1",
  "_type": "_doc",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}
--------------------------------------------------
// TESTRESPONSE

Similarly, the `get` and `delete` APIs use the path `{index}/_doc/{id}`:

[source,js]
--------------------------------------------------
GET index/_doc/1
--------------------------------------------------
// CONSOLE
// TEST[continued]

For API paths that contain both a type and endpoint name like `_update`,
in 7.0 the endpoint will immediately follow the index name:

[source,js]
--------------------------------------------------
POST index/_update/1
{
    "doc" : {
        "foo" : "qux"
    }
}

GET /index/_source/1
--------------------------------------------------
// CONSOLE
// TEST[continued]

Types should also no longer appear in the body of requests. The following
example of bulk indexing omits the type both in the URL, and in the individual
bulk commands:

[source,js]
--------------------------------------------------
POST _bulk
{ "index" : { "_index" : "index", "_id" : "3" } }
{ "foo" : "baz" }
{ "index" : { "_index" : "index", "_id" : "4" } }
{ "foo" : "qux" }
--------------------------------------------------
// CONSOLE

[float]
==== Search APIs

When calling a search API such `_search`, `_msearch`, or `_explain`, types
should not be included in the URL. Additionally, the `_type` field should not
be used in queries, aggregations, or scripts.

[float]
==== Types in responses

The document and search APIs will continue to return a `_type` key in
responses, to avoid breaks to response parsing. However, the key is
considered deprecated and should no longer be referenced. Types will
be completely removed from responses in 8.0.

Note that when a deprecated typed API is used, the index's mapping type will be
returned as normal, but that typeless APIs will return the dummy type `_doc`
in the response. For example, the following typeless `get` call will always
return `_doc` as the type, even if the mapping has a custom type name like
`my_type`:

[source,js]
--------------------------------------------------
PUT index/my_type/1
{
  "foo": "baz"
}

GET index/_doc/1
--------------------------------------------------
// CONSOLE

[source,js]
--------------------------------------------------
{
    "_index" : "index",
    "_type" : "_doc",
    "_id" : "1",
    "_version" : 1,
    "_seq_no" : 0,
    "_primary_term" : 1,
    "found": true,
    "_source" : {
        "foo" : "baz"
    }
}
--------------------------------------------------
// TESTRESPONSE

[float]
==== Index templates

It is recommended to make index templates typeless by re-adding them with
`include_type_name` set to `false`. Under the hood, typeless templates will use
the dummy type `_doc` when creating indices.

In case typeless templates are used with typed index creation calls or typed
templates are used with typeless index creation calls, the template will still
be applied but the index creation call decides whether there should be a type
or not. For instance in the below example, `index-1-01` will have a type in
spite of the fact that it matches a template that is typeless, and `index-2-01`
will be typeless in spite of the fact that it matches a template that defines
a type. Both `index-1-01` and `index-2-01` will inherit the `foo` field from
the template that they match.

[source,js]
--------------------------------------------------
PUT _template/template1
{
  "index_patterns":[ "index-1-*" ],
  "mappings": {
    "properties": {
      "foo": {
        "type": "keyword"
      }
    }
  }
}

PUT _template/template2?include_type_name=true
{
  "index_patterns":[ "index-2-*" ],
  "mappings": {
    "type": {
      "properties": {
        "foo": {
          "type": "keyword"
        }
      }
    }
  }
}

PUT index-1-01?include_type_name=true
{
  "mappings": {
    "type": {
      "properties": {
        "bar": {
          "type": "long"
        }
      }
    }
  }
}

PUT index-2-01
{
  "mappings": {
    "properties": {
      "bar": {
        "type": "long"
      }
    }
  }
}
--------------------------------------------------
// CONSOLE

In case of implicit index creation, because of documents that get indexed in
an index that doesn't exist yet, the template is always honored. This is
usually not a problem due to the fact that typeless index calls work on typed
indices.

[float]
==== Mixed-version clusters

In a cluster composed of both 6.7 and 7.0 nodes, the parameter
`include_type_name` should be specified in indices APIs like index
creation. This is because the parameter has a different default between
6.7 and 7.0, so the same mapping definition will not be valid for both
node versions.

Typeless document APIs such as `bulk` and `update` are only available as of
7.0, and will not work with 6.7 nodes. This also holds true for the typeless
versions of queries that perform document lookups, such as `terms`.

[[removal-of-types]]
== Removal of mapping types

IMPORTANT: Indices created in Elasticsearch 6.0.0 or later may only contain a
single <<mapping-type,mapping type>>.  Indices created in 5.x with multiple
mapping types will continue to function as before in Elasticsearch 6.x.
Types will be deprecated in APIs in Elasticsearch 7.0.0, and completely
removed in 8.0.0.

[float]
=== What are mapping types?

Since the first release of Elasticsearch, each document has been stored in a
single index and assigned a single mapping type.  A mapping type was used to
represent the type of document or entity being indexed, for instance a
`twitter` index might have a `user` type and a `tweet` type.

Each mapping type could have its own fields, so the `user` type might have a
`full_name` field, a `user_name` field, and an `email` field, while the
`tweet` type could have a `content` field, a `tweeted_at` field and, like the
`user` type, a `user_name` field.

Each document had a `_type` meta-field containing the type name, and searches
could be limited to one or more types by specifying the type name(s) in the
URL:

[source,js]
----
GET twitter/user,tweet/_search
{
  "query": {
    "match": {
      "user_name": "kimchy"
    }
  }
}
----
// NOTCONSOLE

The `_type` field was combined with the document's `_id` to generate a `_uid`
field, so documents of different types with the same `_id` could exist in a
single index.

Mapping types were also used to establish a
<<mapping-parent-field,parent-child relationship>>
between documents, so documents of type `question` could be parents to
documents of type `answer`.

[float]
=== Why are mapping types being removed?

Initially, we spoke about an ``index'' being similar to a ``database'' in an
SQL database, and a ``type'' being equivalent to a
``table''.

This was a bad analogy that led to incorrect assumptions. In an SQL database,
tables are independent of each other.  The columns in one table have no
bearing on columns with the same name in another table.  This is not the case
for fields in a mapping type.

In an Elasticsearch index, fields that have the same name in different mapping
types are backed by the same Lucene field internally.  In other words, using
the example above, the `user_name` field in the `user` type is stored in
exactly the same field as the `user_name` field in the `tweet` type, and both
`user_name` fields must have the same mapping (definition) in both types.

This can lead to frustration when, for example, you want `deleted` to be a
`date` field in one type and a `boolean` field in another type in the same
index.

On top of that, storing different entities that have few or no fields in
common in the same index leads to sparse data and interferes with Lucene's
ability to compress documents efficiently.

For these reasons, we have decided to remove the concept of mapping types from
Elasticsearch.

[float]
=== Alternatives to mapping types

[float]
==== Index per document type

The first alternative is to have an index per document type.  Instead of
storing tweets and users in a single `twitter` index, you could store tweets
in the `tweets` index and users in the `user` index. Indices are completely
independent of each other and so there will be no conflict of field types
between indices.

This approach has two benefits:

* Data is more likely to be dense and so benefit from compression techniques
  used in Lucene.

* The term statistics used for scoring in full text search are more likely to
  be accurate because all documents in the same index represent a single
  entity.

Each index can be sized appropriately for the number of documents it will
contain: you can use a smaller number of primary shards for `users` and a
larger number of primary shards for `tweets`.

[float]
==== Custom type field

Of course, there is a limit to how many primary shards can exist in a cluster
so you may not want to waste an entire shard for a collection of only a few
thousand documents.  In this case, you can implement your own custom `type`
field which will work in a similar way to the old `_type`.

Let's take the `user`/`tweet` example above.  Originally, the workflow would
have looked something like this:

[source,js]
----
PUT twitter
{
  "mappings": {
    "user": {
      "properties": {
        "name": { "type": "text" },
        "user_name": { "type": "keyword" },
        "email": { "type": "keyword" }
      }
    },
    "tweet": {
      "properties": {
        "content": { "type": "text" },
        "user_name": { "type": "keyword" },
        "tweeted_at": { "type": "date" }
      }
    }
  }
}

PUT twitter/user/kimchy
{
  "name": "Shay Banon",
  "user_name": "kimchy",
  "email": "shay@kimchy.com"
}

PUT twitter/tweet/1
{
  "user_name": "kimchy",
  "tweeted_at": "2017-10-24T09:00:00Z",
  "content": "Types are going away"
}

GET twitter/tweet/_search
{
  "query": {
    "match": {
      "user_name": "kimchy"
    }
  }
}
----
// NOTCONSOLE

You can achieve the same thing by adding a custom `type` field as follows:

[source,js]
----
PUT twitter
{
  "mappings": {
    "_doc": {
      "properties": {
        "type": { "type": "keyword" }, <1>
        "name": { "type": "text" },
        "user_name": { "type": "keyword" },
        "email": { "type": "keyword" },
        "content": { "type": "text" },
        "tweeted_at": { "type": "date" }
      }
    }
  }
}

PUT twitter/_doc/user-kimchy
{
  "type": "user", <1>
  "name": "Shay Banon",
  "user_name": "kimchy",
  "email": "shay@kimchy.com"
}

PUT twitter/_doc/tweet-1
{
  "type": "tweet", <1>
  "user_name": "kimchy",
  "tweeted_at": "2017-10-24T09:00:00Z",
  "content": "Types are going away"
}

GET twitter/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "user_name": "kimchy"
        }
      },
      "filter": {
        "match": {
          "type": "tweet" <1>
        }
      }
    }
  }
}
----
// NOTCONSOLE
<1> The explicit `type` field takes the place of the implicit `_type` field.

[float]
==== Parent/Child without mapping types

Previously, a parent-child relationship was represented by making one mapping
type the parent, and one or more other mapping types the children.  Without
types, we can no longer use this syntax.  The parent-child feature will
continue to function as before, except that the way of expressing the
relationship between documents has been changed to use the new
<<parent-join,`join` field>>.

[float]
=== Schedule for removal of mapping types

This is a big change for our users, so we have tried to make it as painless as
possible.  The change will roll out as follows:

Elasticsearch 5.6.0::

* Setting `index.mapping.single_type: true` on an index will enable the
  single-type-per-index behaviour which will be enforced in 6.0.

* The <<parent-join,`join` field>> replacement for parent-child is available
  on indices created in 5.6.

Elasticsearch 6.x::

* Indices created in 5.x will continue to function in 6.x as they did in 5.x.

* Indices created in 6.x only allow a single-type per index.  Any name
  can be used for the type, but there can be only one. The preferred type name
  is `_doc`, so that index APIs have the same path as they will have in 7.0:
  `PUT {index}/_doc/{id}` and `POST {index}/_doc`

* The `_type` name can no longer be combined with the `_id` to form the `_uid`
  field. The `_uid` field has become an alias for the `_id` field.

* New indices no longer support the old-style of parent/child and should
  use the <<parent-join,`join` field>> instead.

* The `_default_` mapping type is deprecated.

* In 6.7, the index creation, index template, and mapping APIs support a query
  string parameter (`include_type_name`) which indicates whether requests and
  responses should include a type name. It defaults to `true`, and should be set
  to an explicit value to prepare to upgrade to 7.0. Not setting `include_type_name`
  will result in a deprecation warning. Indices which don't have an explicit type will
  use the dummy type name `_doc`.

Elasticsearch 7.x::

* Specifying types in requests is deprecated. For instance, indexing a
  document no longer requires a document `type`.  The new index APIs
  are `PUT {index}/_doc/{id}` in case of explicit ids and `POST {index}/_doc`
  for auto-generated ids.

* The `include_type_name` parameter in the index creation, index template,
  and mapping APIs will default to `false`. Setting the parameter at all will
  result in a deprecation warning.

* The `_default_` mapping type is removed.

Elasticsearch 8.x::

* Specifying types in requests is no longer supported.

* The `include_type_name` parameter is removed.

[float]
=== Migrating multi-type indices to single-type

The <<docs-reindex,Reindex API>> can be used to convert multi-type indices to
single-type indices. The following examples can be used in Elasticsearch 5.6
or Elasticsearch 6.x.  In 6.x, there is no need to specify
`index.mapping.single_type` as that is the default.

[float]
==== Index per document type

This first example splits our `twitter` index into a `tweets` index and a
`users` index:

[source,js]
----
PUT users
{
  "settings": {
    "index.mapping.single_type": true
  },
  "mappings": {
    "_doc": {
      "properties": {
        "name": {
          "type": "text"
        },
        "user_name": {
          "type": "keyword"
        },
        "email": {
          "type": "keyword"
        }
      }
    }
  }
}

PUT tweets
{
  "settings": {
    "index.mapping.single_type": true
  },
  "mappings": {
    "_doc": {
      "properties": {
        "content": {
          "type": "text"
        },
        "user_name": {
          "type": "keyword"
        },
        "tweeted_at": {
          "type": "date"
        }
      }
    }
  }
}

POST _reindex
{
  "source": {
    "index": "twitter",
    "type": "user"
  },
  "dest": {
    "index": "users"
  }
}

POST _reindex
{
  "source": {
    "index": "twitter",
    "type": "tweet"
  },
  "dest": {
    "index": "tweets"
  }
}
----
// NOTCONSOLE

[float]
==== Custom type field

This next example adds a custom `type` field and sets it to the value of the
original `_type`.  It also adds the type to the `_id` in case there are any
documents of different types which have conflicting IDs:

[source,js]
----
PUT new_twitter
{
  "mappings": {
    "_doc": {
      "properties": {
        "type": {
          "type": "keyword"
        },
        "name": {
          "type": "text"
        },
        "user_name": {
          "type": "keyword"
        },
        "email": {
          "type": "keyword"
        },
        "content": {
          "type": "text"
        },
        "tweeted_at": {
          "type": "date"
        }
      }
    }
  }
}

POST _reindex
{
  "source": {
    "index": "twitter"
  },
  "dest": {
    "index": "new_twitter"
  },
  "script": {
    "source": """
      ctx._source.type = ctx._type;
      ctx._id = ctx._type + '-' + ctx._id;
      ctx._type = '_doc';
    """
  }
}
----
// NOTCONSOLE

[float]
=== Typeless APIs in 7.0

In Elasticsearch 7.0, each API will support typeless requests,
and specifying a type will produce a deprecation warning.

NOTE: Typeless APIs work even if the target index contains a custom type.
For example, if an index has the the custom type name `my_type`, we can add
documents to it using typeless `index` calls, and load documents with typeless
`get` calls.

[float]
==== Indices APIs

Index creation, index template, and mapping APIs support a new `include_type_name`
URL parameter that specifies whether mapping definitions in requests and responses
should contain the type name. The parameter defaults to `true` in version 6.7 to
match the pre-7.0 behavior of using type names in mappings. It defaults to `false`
in version 7.0 and will be removed in version 8.0.

It should be set explicitly in 6.7 to prepare to upgrade to 7.0. To avoid deprecation
warnings in 6.7, the parameter can be set to either `true` or `false`. In 7.0, setting
`include_type_name` at all will result in a deprecation warning.

See some examples of interactions with Elasticsearch with this option set to `false`:

[source,js]
--------------------------------------------------
PUT index?include_type_name=false
{
  "mappings": {
    "properties": { <1>
      "foo": {
        "type": "keyword"
      }
    }
  }
}
--------------------------------------------------
// CONSOLE
<1> Mappings are included directly under the `mappings` key, without a type name.

[source,js]
--------------------------------------------------
PUT index/_mappings?include_type_name=false
{
  "properties": { <1>
    "bar": {
      "type": "text"
    }
  }
}
--------------------------------------------------
// CONSOLE
// TEST[continued]
<1> Mappings are included directly under the `mappings` key, without a type name.

[source,js]
--------------------------------------------------
GET index/_mappings?include_type_name=false
--------------------------------------------------
// CONSOLE
// TEST[continued]

The above call returns

[source,js]
--------------------------------------------------
{
  "index": {
    "mappings": {
      "properties": { <1>
        "foo": {
          "type": "keyword"
        },
        "bar": {
          "type": "text"
        }
      }
    }
  }
}
--------------------------------------------------
// TESTRESPONSE
<1> Mappings are included directly under the `mappings` key, without a type name.

[float]
==== Document APIs

In 7.0, index APIs must be called with the `{index}/_doc` path for automatic
generation of the `_id` and `{index}/_doc/{id}` with explicit ids.

[source,js]
--------------------------------------------------
PUT index/_doc/1
{
  "foo": "baz"
}
--------------------------------------------------
// CONSOLE

[source,js]
--------------------------------------------------
{
  "_index": "index",
  "_id": "1",
  "_type": "_doc",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}
--------------------------------------------------
// TESTRESPONSE

Similarly, the `get` and `delete` APIs use the path `{index}/_doc/{id}`:

[source,js]
--------------------------------------------------
GET index/_doc/1
--------------------------------------------------
// CONSOLE
// TEST[continued]

For API paths that contain both a type and endpoint name like `_update`,
in 7.0 the endpoint will immediately follow the index name:

[source,js]
--------------------------------------------------
POST index/_update/1
{
    "doc" : {
        "foo" : "qux"
    }
}

GET /index/_source/1
--------------------------------------------------
// CONSOLE
// TEST[continued]

Types should also no longer appear in the body of requests. The following
example of bulk indexing omits the type both in the URL, and in the individual
bulk commands:

[source,js]
--------------------------------------------------
POST _bulk
{ "index" : { "_index" : "index", "_id" : "3" } }
{ "foo" : "baz" }
{ "index" : { "_index" : "index", "_id" : "4" } }
{ "foo" : "qux" }
--------------------------------------------------
// CONSOLE

[float]
==== Search APIs

When calling a search API such `_search`, `_msearch`, or `_explain`, types
should not be included in the URL. Additionally, the `_type` field should not
be used in queries, aggregations, or scripts.

[float]
==== Types in responses

The document and search APIs will continue to return a `_type` key in
responses, to avoid breaks to response parsing. However, the key is
considered deprecated and should no longer be referenced. Types will
be completely removed from responses in 8.0.

Note that when a deprecated typed API is used, the index's mapping type will be
returned as normal, but that typeless APIs will return the dummy type `_doc`
in the response. For example, the following typeless `get` call will always
return `_doc` as the type, even if the mapping has a custom type name like
`my_type`:

[source,js]
--------------------------------------------------
PUT index/my_type/1
{
  "foo": "baz"
}

GET index/_doc/1
--------------------------------------------------
// CONSOLE

[source,js]
--------------------------------------------------
{
    "_index" : "index",
    "_type" : "_doc",
    "_id" : "1",
    "_version" : 1,
    "_seq_no" : 0,
    "_primary_term" : 1,
    "found": true,
    "_source" : {
        "foo" : "baz"
    }
}
--------------------------------------------------
// TESTRESPONSE

[float]
==== Index templates

It is recommended to make index templates typeless by re-adding them with
`include_type_name` set to `false`. Under the hood, typeless templates will use
the dummy type `_doc` when creating indices.

In case typeless templates are used with typed index creation calls or typed
templates are used with typeless index creation calls, the template will still
be applied but the index creation call decides whether there should be a type
or not. For instance in the below example, `index-1-01` will have a type in
spite of the fact that it matches a template that is typeless, and `index-2-01`
will be typeless in spite of the fact that it matches a template that defines
a type. Both `index-1-01` and `index-2-01` will inherit the `foo` field from
the template that they match.

[source,js]
--------------------------------------------------
PUT _template/template1
{
  "index_patterns":[ "index-1-*" ],
  "mappings": {
    "properties": {
      "foo": {
        "type": "keyword"
      }
    }
  }
}

PUT _template/template2?include_type_name=true
{
  "index_patterns":[ "index-2-*" ],
  "mappings": {
    "type": {
      "properties": {
        "foo": {
          "type": "keyword"
        }
      }
    }
  }
}

PUT index-1-01?include_type_name=true
{
  "mappings": {
    "type": {
      "properties": {
        "bar": {
          "type": "long"
        }
      }
    }
  }
}

PUT index-2-01
{
  "mappings": {
    "properties": {
      "bar": {
        "type": "long"
      }
    }
  }
}
--------------------------------------------------
// CONSOLE

In case of implicit index creation, because of documents that get indexed in
an index that doesn't exist yet, the template is always honored. This is
usually not a problem due to the fact that typeless index calls work on typed
indices.

[float]
==== Mixed-version clusters

In a cluster composed of both 6.7 and 7.0 nodes, the parameter
`include_type_name` should be specified in indices APIs like index
creation. This is because the parameter has a different default between
6.7 and 7.0, so the same mapping definition will not be valid for both
node versions.

Typeless document APIs such as `bulk` and `update` are only available as of
7.0, and will not work with 6.7 nodes. This also holds true for the typeless
versions of queries that perform document lookups, such as `terms`.


fix tag

fix tag

:github-tag: 2.0.x
:github-repo: spring-cloud/spring-cloud-gateway
:github-raw: https://raw.githubusercontent.com/{github-repo}/{github-tag}
:github-code: https://github.com/{github-repo}/tree/{github-tag}
:all: {asterisk}{asterisk}
:nofooter:
:imagesdir: ./images
:imagesurl: {github-raw}/docs/src/main/asciidoc/images
= Spring Cloud Gateway

*{spring-cloud-version}*

include::intro.adoc[]

[[gateway-starter]]
== How to Include Spring Cloud Gateway

To include Spring Cloud Gateway in your project use the starter with group `org.springframework.cloud`
and artifact id `spring-cloud-starter-gateway`. See the http://projects.spring.io/spring-cloud/[Spring Cloud Project page]
for details on setting up your build system with the current Spring Cloud Release Train.

If you include the starter, but, for some reason, you do not want the gateway to be enabled, set `spring.cloud.gateway.enabled=false`.

== Glossary

* *Route*: Route the basic building block of the gateway. It is defined by an ID, a destination URI, a collection of predicates and a collection of filters. A route is matched if aggregate predicate is true.
* *Predicate*: This is a http://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html[Java 8 Function Predicate]. The input type is a http://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/server/ServerWebExchange.html[Spring Framework `ServerWebExchange`]. This allows developers to match on anything from the HTTP request, such as headers or parameters.
* *Filter*: These are instances http://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/server/WebFilter.html[Spring Framework `WebFilter`] constructed in with a specific factory. Here, requests and responses can be modified before or after sending the downstream request.

[[gateway-how-it-works]]
== How It Works

image::{imagesurl}/spring_cloud_gateway_diagram.png[Spring Cloud Gateway Diagram]

Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a Route, it is sent to the Gateway Web Handler. This handler runs sends the request through a filter chain that is specific to the request. The reason the filters are divided by the dotted line, is that filters may execute logic before the proxy request is sent or after. All "pre" filter logic is executed, then the proxy request is made. After the proxy request is made, the "post" filter logic is executed.

[[gateway-request-predicates-factories]]
== Route Predicate Factories

Spring Cloud Gateway matches routes as part of the Spring WebFlux `HandlerMapping` infrastructure. Spring Cloud Gateway includes many built-in Route Predicate Factorys. All of these predicates match on different attributes of the HTTP request. Multiple Route Predicate Factorys can be combined and are combined via logical `and`.

=== After Route Predicate Factory
The After Route Predicate Factory takes one parameter, a datetime. This predicate matches requests that happen after the current datetime.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: after_route
        uri: http://example.org
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
----

This route matches any request after Jan 20, 2017 17:42 Mountain Time (Denver).

=== Before Route Predicate Factory
The Before Route Predicate Factory takes one parameter, a datetime. This predicate matches requests that happen before the current datetime.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: before_route
        uri: http://example.org
        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]
----

This route matches any request before Jan 20, 2017 17:42 Mountain Time (Denver).

=== Between Route Predicate Factory
The Between Route Predicate Factory takes two parameters, datetime1 and datetime2. This predicate matches requests that happen after datetime1 and before datetime2. The datetime2 parameter must be after datetime1.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: between_route
        uri: http://example.org
        predicates:
        - Betweeen=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
----

This route matches any request after Jan 20, 2017 17:42 Mountain Time (Denver) and before Jan 21, 2017 17:42 Mountain Time (Denver). This could be useful for maintenance windows.

=== Cookie Route Predicate Factory
The Cookie Route Predicate Factory takes two parameters, the cookie name and a regular expression. This predicate matches cookies that have the given name and the value matches the regular expression.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: cookie_route
        uri: http://example.org
        predicates:
        - Cookie=chocolate, ch.p
----

This route matches the request has a cookie named `chocolate` who's value matches the `ch.p` regular expression.

=== Header Route Predicate Factory
The Header Route Predicate Factory takes two parameters, the header name and a regular expression. This predicate matches with a header that has the given name and the value matches the regular expression.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: header_route
        uri: http://example.org
        predicates:
        - Header=X-Request-Id, \d+
----

This route matches if the request has a header named `X-Request-Id` whos value matches the `\d+` regular expression (has a value of one or more digits).

=== Host Route Predicate Factory
The Host Route Predicate Factory takes one parameter: the host name pattern. The pattern is an Ant style pattern with `.` as the separator. This predicates matches the `Host` header that matches the pattern.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: host_route
        uri: http://example.org
        predicates:
        - Host=**.somehost.org
----

This route would match if the request has a `Host` header has the value `www.somehost.org` or `beta.somehost.org`.

=== Method Route Predicate Factory
The Method Route Predicate Factory takes one parameter: the HTTP method to match.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: method_route
        uri: http://example.org
        predicates:
        - Method=GET
----

This route would match if the request method was a `GET`.

=== Path Route Predicate Factory
The Path Route Predicate Factory takes one parameter: a Spring `PathMatcher` pattern.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: host_route
        uri: http://example.org
        predicates:
        - Path=/foo/{segment}
----

This route would match if the request path was, for example: `/foo/1` or `/foo/bar`.

This predicate extracts the URI template variables (like `segment` defined in the example above) as a map of names and values and places it in the `ServerWebExchange.getAttributes()` with a key defined in `PathRoutePredicate.URL_PREDICATE_VARS_ATTR`. Those values are then available for use by <<gateway-route-filters,WebFilter Factorys>>

=== Query Route Predicate Factory
The Query Route Predicate Factory takes two parameters: a required `param` and an optional `regexp`.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: query_route
        uri: http://example.org
        predicates:
        - Query=baz
----

This route would match if the request contained a `baz` query parameter.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: query_route
        uri: http://example.org
        predicates:
        - Query=foo, ba.
----

This route would match if the request contained a `foo` query parameter whose value matched the `ba.` regexp, so `bar` and `baz` would match.

=== RemoteAddr Route Predicate Factory
The RemoteAddr Route Predicate Factory takes a list (min size 1) of CIDR-notation strings, e.g. `192.168.0.1/16` (where `192.168.0.1` is an IP address and `16` is a subnet mask.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: remoteaddr_route
        uri: http://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24
----

This route would match if the remote address of the request was, for example, `192.168.1.10`.

[[gateway-route-filters]]
== WebFilter Factorys

Route filters allow the modification of the incoming HTTP request or outgoing HTTP response in some manner. Route filters are scoped to a particular route. Spring Cloud Gateway includes many built-in WebFilter Factories.

=== AddRequestHeader WebFilter Factory
The AddRequestHeader WebFilter Factory takes a name and value parameter.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: add_request_header_route
        uri: http://example.org
        filters:
        - AddRequestHeader=X-Request-Foo, Bar
----

This will add `X-Request-Foo:Bar` header to the downstream request's headers for all matching requests.

=== AddRequestParameter WebFilter Factory
The AddRequestParameter WebFilter Factory takes a name and value parameter.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: add_request_parameter_route
        uri: http://example.org
        filters:
        - AddRequestParameter=foo, bar
----

This will add `foo=bar` to the downstream request's query string for all matching requests.

=== AddResponseHeader WebFilter Factory
The AddResponseHeader WebFilter Factory takes a name and value parameter.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: add_request_header_route
        uri: http://example.org
        filters:
        - AddResponseHeader=X-Response-Foo, Bar
----

This will add `X-Response-Foo:Bar` header to the downstream response's headers for all matching requests.

=== Hystrix WebFilter Factory
The Hystrix WebFilter Factory takes a single `name` parameters, which is the name of the `HystrixCommand`. (More options might be added in future releases).

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: hytstrix_route
        uri: http://example.org
        filters:
        - Hystrix=myCommandName
----

This wraps the remaining filters in a `HystrixCommand` with command name `myCommandName`.

=== PrefixPath WebFilter Factory
The PrefixPath WebFilter Factory takes a single `prefix` parameter.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: prefixpath_route
        uri: http://example.org
        filters:
        - PrefixPath=/mypath
----

This will prefix `/mypath` to the path of all matching requests. So a request to `/hello`, would be sent to `/mypath/hello`.

=== RequestRateLimiter WebFilter Factory

The RequestRateLimiter WebFilter Factory takes three parameters: `replenishRate`, `burstCapacity` & `keyResolverName`.

`replenishRate` is how many requests per second do you want a user to be allowed to do.

`burstCapacity` TODO: document burst capacity

`keyResolverName` is the name of a bean that implements the `KeyResolver` interface.

.KeyResolver.java
[source,java]
----
public interface KeyResolver {
	Mono<String> resolve(ServerWebExchange exchange);
}
----

The `KeyResolver` interface allows pluggable strategies to derive the key for limiting requests. In future milestones, there will be some `KeyResolver` implementations.

The redis implementation is based off of work done at https://stripe.com/blog/rate-limiters[Stripe]. It requires the use of the `spring-boot-starter-data-redis-reactive` Spring Boot starter.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: requestratelimiter_route
        uri: http://example.org
        filters:
        - RequestRateLimiter=10, 20, userKeyResolver
----

.Config.java
[source,java]
----
@Bean
KeyResolver userKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}
----

This defines a request rate limit of 10 per user. The `KeyResolver` is a simple one that gets the `user` request parameter (note: this is not recommended for production).

=== RedirectTo WebFilter Factory
The RedirectTo WebFilter Factory takes a `status` and a `url` parameter. The status should be a 300 series redirect http code, such as 301. The url should be a valid url. This will be the value of the `Location` header.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: prefixpath_route
        uri: http://example.org
        filters:
        - RedirectTo=302, http://acme.org
----

This will send a status 302 with a `Location:http://acme.org` header to perform a redirect.

=== RemoveNonProxyHeaders WebFilter Factory
The RemoveNonProxyHeaders WebFilter Factory removes headers from forwarded requests. The default list of headers that is removed comes from the https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.1.3[IETF].

.The default removed headers are:
 *  Connection
 *  Keep-Alive
 *  Proxy-Authenticate
 *  Proxy-Authorization
 *  TE
 *  Trailer
 *  Transfer-Encoding
 *  Upgrade

To change this, set the `spring.cloud.gateway.filter.remove-non-proxy-headers.headers` property to the list of header names to remove.

=== RemoveRequestHeader WebFilter Factory
The RemoveRequestHeader WebFilter Factory takes a `name` parameter. It is the name of the header to be removed.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: removerequestheader_route
        uri: http://example.org
        filters:
        - RemoveRequestHeader=X-Request-Foo
----

This will remove the `X-Request-Foo` header before it is sent downstream.

=== RemoveResponseHeader WebFilter Factory
The RemoveResponseHeader WebFilter Factory takes a `name` parameter. It is the name of the header to be removed.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: removeresponseheader_route
        uri: http://example.org
        filters:
        - RemoveResponseHeader=X-Response-Foo
----

This will remove the `X-Response-Foo` header from the response before it is returned to the gateway client.

=== RewritePath WebFilter Factory
The RewritePath WebFilter Factory takes a path `regexp` parameter and a `replacement` parameter. This uses Java regular expressions for a flexible way to rewrite the request path.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: rewritepath_route
        uri: http://example.org
        - Path=/foo/**
        filters:
        - RewritePath=/foo/(?<segment>.*), /$\{segment}
----

For a request path of `/foo/bar`, this will set the path to `/bar` before making the downstream request. Notice the `$\` which is replaced with `$` because of the YAML spec.

=== SecureHeaders WebFilter Factory
The SecureHeaders WebFilter Factory adds a number of headers to the response at the reccomendation from https://blog.appcanary.com/2017/http-security-headers.html[this blog post].

.The following headers are added (allong with default values):
 * `X-Xss-Protection:1; mode=block`
 * `Strict-Transport-Security:max-age=631138519`
 * `X-Frame-Options:DENY`
 * `X-Content-Type-Options:nosniff`
 * `Referrer-Policy:no-referrer`
 * `Content-Security-Policy:default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'`
 * `X-Download-Options:noopen`
 * `X-Permitted-Cross-Domain-Policies:none`

To change the default values set the appropriate property in the `spring.cloud.gateway.filter.secure-headers` namespace:

.Property to change:
 * `xss-protection-header`
 * `strict-transport-security`
 * `frame-options`
 * `content-type-options`
 * `referrer-policy`
 * `content-security-policy`
 * `download-options`
 * `permitted-cross-domain-policies`

=== SetPath WebFilter Factory
The SetPath WebFilter Factory takes a path `template` parameter. It offers a simple way to manipulate the request path by allowing templated segments of the path. This uses the uri templates from Spring Framework. Multiple matching segments are allowed.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: setpath_route
        uri: http://example.org
        predicates:
        - Path=/foo/{segment}
        filters:
        - SetPath=/{segment}
----

For a request path of `/foo/bar`, this will set the path to `/bar` before making the downstream request.

=== SetResponseHeader WebFilter Factory
The SetResponseHeader WebFilter Factory takes `name` and `value` parameters.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: setresponseheader_route
        uri: http://example.org
        filters:
        - SetResponseHeader=X-Response-Foo, Bar
----

This WebFilter replaces all headers with the given name, rather than adding. So if the downstream server responded with a `X-Response-Foo:1234`, this would be replaced with `X-Response-Foo:Bar`, which is what the gateway client would receive.

=== SetStatus WebFilter Factory
The SetStatus WebFilter Factory takes a single `status` parameter. It must be a valid Spring `HttpStatus`. It may be the integer value `404` or the string representation of the enumeration `NOT_FOUND`.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: setstatusstring_route
        uri: http://example.org
        filters:
        - SetStatus=BAD_REQUEST
      - id: setstatusint_route
        uri: http://example.org
        filters:
        - SetStatus=401
----

In either case, the HTTP status of the response will be set to 401.

== Global Filters

The `GlobalFilter` interface has the same signature as `WebFilter`. These are special filters that are conditionally applied to all routes. (This interface and usage are subject to change in future milestones).

=== LoadBalancerClient Filter

The `LoadBalancerClientFilter` looks for a URI in the exchange attribute `ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR`. If the url has a `lb` scheme (ie `lb://myservice`), it will use the Spring Cloud `LoadBalancerClient` to resolve the name (`myservice` in the previous example) to an actual host and port and replace the URI in the same attribute. The unmodified original url is placed in the `ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR` attribute.

=== Netty Routing Filter

The Netty Routing Filter runs if the url located in the `ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR` exchange attribute has a `http` or `https` scheme. It uses the Netty `HttpClient` to make the downstream proxy request. The response is put in the `ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR` exchange attribute for use in a later filter. (There is an experimental `WebClientHttpRoutingFilter` that performs the same function, but does not require netty)

=== Netty Write Response Filter

The `NettyWriteResponseFilter` runs if there is a Netty `HttpClientResponse` in the `ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR` exchange attribute. It is run after all other filters have completed and writes the proxy response back to the gateway client response. (There is an experimental `WebClientWriteResponseFilter` that performs the same function, but does not require netty)

=== RouteToRequestUrl Filter

The `RouteToRequestUrlFilter` runs if there is a `Route` object in the `ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR` exchange attribute. It creates a new URI, based off of the request URI, but updated with the URI attribute of the `Route` object. The new URI is placed in the ``ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR` exchange attribute`.

=== Websocket Routing Filter

The Websocket Routing Filter runs if the url located in the `ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR` exchange attribute has a `ws` or `wss` scheme. It uses the Spring Web Socket infrastructure to forward the Websocket request downstream.

== Configuration

Configuration for Spring Cloud Gateway is driven by a collection of `RouteDefinitionLocator`s.

.RouteDefinitionLocator.java
[source,java]
----
public interface RouteDefinitionLocator {
	Flux<RouteDefinition> getRouteDefinitions();
}
----

By default, a `PropertiesRouteDefinitionLocator` loads properties using Spring Boot's `@ConfigurationProperties` mechanism.

The configuration examples above all use a shortcut notation that uses positional arguments rather than named ones. The two examples below are equivalent:

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: setstatus_route
        uri: http://example.org
        filters:
        - name: SetStatus
          args:
            status: 401
      - id: setstatusshortcut_route
        uri: http://example.org
        filters:
        - SetStatus=401
----

For some usages of the gateway, properties will be adequate, but some production use cases will benefit from loading configuration from an external source, such as a database. Future milestone versions will have `RouteDefinitionLocator` implementations based off of Spring Data Repositories such as: Redis, MongoDB and Cassandra.

=== Fluent Java Routes API
To allow for simple configuration in Java, there is a fluent API defined in the `Routes` class.

.Config.java
[source,java]
----
// static imports from WebFilterFactories and RoutePredicates
@Bean
public RouteLocator customRouteLocator(ThrottleWebFilterFactory throttle) {
    return Routes.locator()
            .route("test")
                .uri("http://httpbin.org:80")
                .predicate(host("**.abc.org").and(path("/image/png")))
                .addResponseHeader("X-TestHeader", "foobar")
                .and()
            .route("test2")
                .uri("http://httpbin.org:80")
                .predicate(path("/image/webp"))
                .add(addResponseHeader("X-AnotherHeader", "baz"))
                .and()
            .build();
}
----

This style also allows for more custom predicate assertions. The predicates defined by `RouteDefinitionLocator` beans are combined using logical `and`. By using the fluent Java API, you can use the `and()`, `or()` and `negate()` operators on the `Predicate` class.

== Actuator API

TODO: document the `/gateway` actuator endpoint

== Developer Guide

TODO: overview of writing custom integrations

=== Writing Custom Route Predicate Factorys

TODO: document writing Custom Route Predicate Factorys

=== Writing Custom WebFilter Factorys

TODO: document writing Custom WebFilter Factorys

=== Writing Custom Global Filters

TODO: document writing Custom Global Filters

=== Writing Custom Route Locators and Writers

TODO: document writing Custom Route Locators and Writers

== Building a Simple Gateway Using Spring MVC

Spring Cloud Gateway provides a utility object called `ProxyExchange` which you can use inside a regular Spring MVC handler as a method parameter. It supports basic downstream HTTP exchanges via methods that mirror the HTTP verbs, or forwarding to a local handler via the `forward()` method.

Example (proxying a request to "/test" downstream to a remote server):

```java
@RestController
@SpringBootApplication
public class GatewaySampleApplication {

	@Value("${remote.home}")
	private URI home;

	@GetMapping("/test")
	public ResponseEntity<?> proxy(ProxyExchange<Object> proxy) throws Exception {
		return proxy.uri(home.toString() + "/image/png").get();
	}

}
```

There are convenience methods on the `ProxyExchange` to enable the handler method to discover and enhance the URI path of the incoming request. For example you might want to extract the trailing elements of a path to pass them downstream:

```java
@GetMapping("/proxy/path/**")
public ResponseEntity<?> proxyPath(ProxyExchange<?> proxy) throws Exception {
  String path = proxy.path("/proxy/path/");
  return proxy.uri(home.toString() + "/foos/" + path).get();
}
```

All the features of Spring MVC are available to Gateway handler methods. So you can inject request headers and query parameters, for instance, and you can constrain the incoming requests with declarations in the mapping annotation. See the documentation for `@RequestMapping` in Spring MVC for more details of those features.

Headers can be added to the downstream response using the `header()` methods on `ProxyExchange`.

You can also manipulate response headers (and anything else you like in the response) by adding a mapper to the `get()` etc. method. The mapper is a `Function` that takes the incoming `ResponseEntity` and converts it to an outgoing one.

First class support is provided for "sensitive" headers ("cookie" and "authorization" by default) which are not passed downstream, and for "proxy" headers (`x-forwarded-*`).

:github-tag: master
:github-repo: spring-cloud/spring-cloud-gateway
:github-raw: https://raw.githubusercontent.com/{github-repo}/{github-tag}
:github-code: https://github.com/{github-repo}/tree/{github-tag}
:all: {asterisk}{asterisk}
:nofooter:
:imagesdir: ./images
:imagesurl: {github-raw}/docs/src/main/asciidoc/images
= Spring Cloud Gateway

*{spring-cloud-version}*

include::intro.adoc[]

[[gateway-starter]]
== How to Include Spring Cloud Gateway

To include Spring Cloud Gateway in your project use the starter with group `org.springframework.cloud`
and artifact id `spring-cloud-starter-gateway`. See the http://projects.spring.io/spring-cloud/[Spring Cloud Project page]
for details on setting up your build system with the current Spring Cloud Release Train.

If you include the starter, but, for some reason, you do not want the gateway to be enabled, set `spring.cloud.gateway.enabled=false`.

== Glossary

* *Route*: Route the basic building block of the gateway. It is defined by an ID, a destination URI, a collection of predicates and a collection of filters. A route is matched if aggregate predicate is true.
* *Predicate*: This is a http://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html[Java 8 Function Predicate]. The input type is a http://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/server/ServerWebExchange.html[Spring Framework `ServerWebExchange`]. This allows developers to match on anything from the HTTP request, such as headers or parameters.
* *Filter*: These are instances http://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/server/WebFilter.html[Spring Framework `WebFilter`] constructed in with a specific factory. Here, requests and responses can be modified before or after sending the downstream request.

[[gateway-how-it-works]]
== How It Works

image::{imagesurl}/spring_cloud_gateway_diagram.png[Spring Cloud Gateway Diagram]

Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a Route, it is sent to the Gateway Web Handler. This handler runs sends the request through a filter chain that is specific to the request. The reason the filters are divided by the dotted line, is that filters may execute logic before the proxy request is sent or after. All "pre" filter logic is executed, then the proxy request is made. After the proxy request is made, the "post" filter logic is executed.

[[gateway-request-predicates-factories]]
== Route Predicate Factories

Spring Cloud Gateway matches routes as part of the Spring WebFlux `HandlerMapping` infrastructure. Spring Cloud Gateway includes many built-in Route Predicate Factorys. All of these predicates match on different attributes of the HTTP request. Multiple Route Predicate Factorys can be combined and are combined via logical `and`.

=== After Route Predicate Factory
The After Route Predicate Factory takes one parameter, a datetime. This predicate matches requests that happen after the current datetime.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: after_route
        uri: http://example.org
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
----

This route matches any request after Jan 20, 2017 17:42 Mountain Time (Denver).

=== Before Route Predicate Factory
The Before Route Predicate Factory takes one parameter, a datetime. This predicate matches requests that happen before the current datetime.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: before_route
        uri: http://example.org
        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]
----

This route matches any request before Jan 20, 2017 17:42 Mountain Time (Denver).

=== Between Route Predicate Factory
The Between Route Predicate Factory takes two parameters, datetime1 and datetime2. This predicate matches requests that happen after datetime1 and before datetime2. The datetime2 parameter must be after datetime1.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: between_route
        uri: http://example.org
        predicates:
        - Betweeen=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
----

This route matches any request after Jan 20, 2017 17:42 Mountain Time (Denver) and before Jan 21, 2017 17:42 Mountain Time (Denver). This could be useful for maintenance windows.

=== Cookie Route Predicate Factory
The Cookie Route Predicate Factory takes two parameters, the cookie name and a regular expression. This predicate matches cookies that have the given name and the value matches the regular expression.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: cookie_route
        uri: http://example.org
        predicates:
        - Cookie=chocolate, ch.p
----

This route matches the request has a cookie named `chocolate` who's value matches the `ch.p` regular expression.

=== Header Route Predicate Factory
The Header Route Predicate Factory takes two parameters, the header name and a regular expression. This predicate matches with a header that has the given name and the value matches the regular expression.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: header_route
        uri: http://example.org
        predicates:
        - Header=X-Request-Id, \d+
----

This route matches if the request has a header named `X-Request-Id` whos value matches the `\d+` regular expression (has a value of one or more digits).

=== Host Route Predicate Factory
The Host Route Predicate Factory takes one parameter: the host name pattern. The pattern is an Ant style pattern with `.` as the separator. This predicates matches the `Host` header that matches the pattern.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: host_route
        uri: http://example.org
        predicates:
        - Host=**.somehost.org
----

This route would match if the request has a `Host` header has the value `www.somehost.org` or `beta.somehost.org`.

=== Method Route Predicate Factory
The Method Route Predicate Factory takes one parameter: the HTTP method to match.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: method_route
        uri: http://example.org
        predicates:
        - Method=GET
----

This route would match if the request method was a `GET`.

=== Path Route Predicate Factory
The Path Route Predicate Factory takes one parameter: a Spring `PathMatcher` pattern.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: host_route
        uri: http://example.org
        predicates:
        - Path=/foo/{segment}
----

This route would match if the request path was, for example: `/foo/1` or `/foo/bar`.

This predicate extracts the URI template variables (like `segment` defined in the example above) as a map of names and values and places it in the `ServerWebExchange.getAttributes()` with a key defined in `PathRoutePredicate.URL_PREDICATE_VARS_ATTR`. Those values are then available for use by <<gateway-route-filters,WebFilter Factorys>>

=== Query Route Predicate Factory
The Query Route Predicate Factory takes two parameters: a required `param` and an optional `regexp`.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: query_route
        uri: http://example.org
        predicates:
        - Query=baz
----

This route would match if the request contained a `baz` query parameter.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: query_route
        uri: http://example.org
        predicates:
        - Query=foo, ba.
----

This route would match if the request contained a `foo` query parameter whose value matched the `ba.` regexp, so `bar` and `baz` would match.

=== RemoteAddr Route Predicate Factory
The RemoteAddr Route Predicate Factory takes a list (min size 1) of CIDR-notation strings, e.g. `192.168.0.1/16` (where `192.168.0.1` is an IP address and `16` is a subnet mask.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: remoteaddr_route
        uri: http://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24
----

This route would match if the remote address of the request was, for example, `192.168.1.10`.

[[gateway-route-filters]]
== WebFilter Factorys

Route filters allow the modification of the incoming HTTP request or outgoing HTTP response in some manner. Route filters are scoped to a particular route. Spring Cloud Gateway includes many built-in WebFilter Factories.

=== AddRequestHeader WebFilter Factory
The AddRequestHeader WebFilter Factory takes a name and value parameter.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: add_request_header_route
        uri: http://example.org
        filters:
        - AddRequestHeader=X-Request-Foo, Bar
----

This will add `X-Request-Foo:Bar` header to the downstream request's headers for all matching requests.

=== AddRequestParameter WebFilter Factory
The AddRequestParameter WebFilter Factory takes a name and value parameter.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: add_request_parameter_route
        uri: http://example.org
        filters:
        - AddRequestParameter=foo, bar
----

This will add `foo=bar` to the downstream request's query string for all matching requests.

=== AddResponseHeader WebFilter Factory
The AddResponseHeader WebFilter Factory takes a name and value parameter.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: add_request_header_route
        uri: http://example.org
        filters:
        - AddResponseHeader=X-Response-Foo, Bar
----

This will add `X-Response-Foo:Bar` header to the downstream response's headers for all matching requests.

=== Hystrix WebFilter Factory
The Hystrix WebFilter Factory takes a single `name` parameters, which is the name of the `HystrixCommand`. (More options might be added in future releases).

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: hytstrix_route
        uri: http://example.org
        filters:
        - Hystrix=myCommandName
----

This wraps the remaining filters in a `HystrixCommand` with command name `myCommandName`.

=== PrefixPath WebFilter Factory
The PrefixPath WebFilter Factory takes a single `prefix` parameter.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: prefixpath_route
        uri: http://example.org
        filters:
        - PrefixPath=/mypath
----

This will prefix `/mypath` to the path of all matching requests. So a request to `/hello`, would be sent to `/mypath/hello`.

=== RequestRateLimiter WebFilter Factory

The RequestRateLimiter WebFilter Factory takes three parameters: `replenishRate`, `burstCapacity` & `keyResolverName`.

`replenishRate` is how many requests per second do you want a user to be allowed to do.

`burstCapacity` TODO: document burst capacity

`keyResolverName` is the name of a bean that implements the `KeyResolver` interface.

.KeyResolver.java
[source,java]
----
public interface KeyResolver {
	Mono<String> resolve(ServerWebExchange exchange);
}
----

The `KeyResolver` interface allows pluggable strategies to derive the key for limiting requests. In future milestones, there will be some `KeyResolver` implementations.

The redis implementation is based off of work done at https://stripe.com/blog/rate-limiters[Stripe]. It requires the use of the `spring-boot-starter-data-redis-reactive` Spring Boot starter.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: requestratelimiter_route
        uri: http://example.org
        filters:
        - RequestRateLimiter=10, 20, userKeyResolver
----

.Config.java
[source,java]
----
@Bean
KeyResolver userKeyResolver() {
    return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}
----

This defines a request rate limit of 10 per user. The `KeyResolver` is a simple one that gets the `user` request parameter (note: this is not recommended for production).

=== RedirectTo WebFilter Factory
The RedirectTo WebFilter Factory takes a `status` and a `url` parameter. The status should be a 300 series redirect http code, such as 301. The url should be a valid url. This will be the value of the `Location` header.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: prefixpath_route
        uri: http://example.org
        filters:
        - RedirectTo=302, http://acme.org
----

This will send a status 302 with a `Location:http://acme.org` header to perform a redirect.

=== RemoveNonProxyHeaders WebFilter Factory
The RemoveNonProxyHeaders WebFilter Factory removes headers from forwarded requests. The default list of headers that is removed comes from the https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.1.3[IETF].

.The default removed headers are:
 *  Connection
 *  Keep-Alive
 *  Proxy-Authenticate
 *  Proxy-Authorization
 *  TE
 *  Trailer
 *  Transfer-Encoding
 *  Upgrade

To change this, set the `spring.cloud.gateway.filter.remove-non-proxy-headers.headers` property to the list of header names to remove.

=== RemoveRequestHeader WebFilter Factory
The RemoveRequestHeader WebFilter Factory takes a `name` parameter. It is the name of the header to be removed.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: removerequestheader_route
        uri: http://example.org
        filters:
        - RemoveRequestHeader=X-Request-Foo
----

This will remove the `X-Request-Foo` header before it is sent downstream.

=== RemoveResponseHeader WebFilter Factory
The RemoveResponseHeader WebFilter Factory takes a `name` parameter. It is the name of the header to be removed.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: removeresponseheader_route
        uri: http://example.org
        filters:
        - RemoveResponseHeader=X-Response-Foo
----

This will remove the `X-Response-Foo` header from the response before it is returned to the gateway client.

=== RewritePath WebFilter Factory
The RewritePath WebFilter Factory takes a path `regexp` parameter and a `replacement` parameter. This uses Java regular expressions for a flexible way to rewrite the request path.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: rewritepath_route
        uri: http://example.org
        - Path=/foo/**
        filters:
        - RewritePath=/foo/(?<segment>.*), /$\{segment}
----

For a request path of `/foo/bar`, this will set the path to `/bar` before making the downstream request. Notice the `$\` which is replaced with `$` because of the YAML spec.

=== SecureHeaders WebFilter Factory
The SecureHeaders WebFilter Factory adds a number of headers to the response at the reccomendation from https://blog.appcanary.com/2017/http-security-headers.html[this blog post].

.The following headers are added (allong with default values):
 * `X-Xss-Protection:1; mode=block`
 * `Strict-Transport-Security:max-age=631138519`
 * `X-Frame-Options:DENY`
 * `X-Content-Type-Options:nosniff`
 * `Referrer-Policy:no-referrer`
 * `Content-Security-Policy:default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'`
 * `X-Download-Options:noopen`
 * `X-Permitted-Cross-Domain-Policies:none`

To change the default values set the appropriate property in the `spring.cloud.gateway.filter.secure-headers` namespace:

.Property to change:
 * `xss-protection-header`
 * `strict-transport-security`
 * `frame-options`
 * `content-type-options`
 * `referrer-policy`
 * `content-security-policy`
 * `download-options`
 * `permitted-cross-domain-policies`

=== SetPath WebFilter Factory
The SetPath WebFilter Factory takes a path `template` parameter. It offers a simple way to manipulate the request path by allowing templated segments of the path. This uses the uri templates from Spring Framework. Multiple matching segments are allowed.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: setpath_route
        uri: http://example.org
        predicates:
        - Path=/foo/{segment}
        filters:
        - SetPath=/{segment}
----

For a request path of `/foo/bar`, this will set the path to `/bar` before making the downstream request.

=== SetResponseHeader WebFilter Factory
The SetResponseHeader WebFilter Factory takes `name` and `value` parameters.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: setresponseheader_route
        uri: http://example.org
        filters:
        - SetResponseHeader=X-Response-Foo, Bar
----

This WebFilter replaces all headers with the given name, rather than adding. So if the downstream server responded with a `X-Response-Foo:1234`, this would be replaced with `X-Response-Foo:Bar`, which is what the gateway client would receive.

=== SetStatus WebFilter Factory
The SetStatus WebFilter Factory takes a single `status` parameter. It must be a valid Spring `HttpStatus`. It may be the integer value `404` or the string representation of the enumeration `NOT_FOUND`.

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: setstatusstring_route
        uri: http://example.org
        filters:
        - SetStatus=BAD_REQUEST
      - id: setstatusint_route
        uri: http://example.org
        filters:
        - SetStatus=401
----

In either case, the HTTP status of the response will be set to 401.

== Global Filters

The `GlobalFilter` interface has the same signature as `WebFilter`. These are special filters that are conditionally applied to all routes. (This interface and usage are subject to change in future milestones).

=== LoadBalancerClient Filter

The `LoadBalancerClientFilter` looks for a URI in the exchange attribute `ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR`. If the url has a `lb` scheme (ie `lb://myservice`), it will use the Spring Cloud `LoadBalancerClient` to resolve the name (`myservice` in the previous example) to an actual host and port and replace the URI in the same attribute. The unmodified original url is placed in the `ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR` attribute.

=== Netty Routing Filter

The Netty Routing Filter runs if the url located in the `ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR` exchange attribute has a `http` or `https` scheme. It uses the Netty `HttpClient` to make the downstream proxy request. The response is put in the `ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR` exchange attribute for use in a later filter. (There is an experimental `WebClientHttpRoutingFilter` that performs the same function, but does not require netty)

=== Netty Write Response Filter

The `NettyWriteResponseFilter` runs if there is a Netty `HttpClientResponse` in the `ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR` exchange attribute. It is run after all other filters have completed and writes the proxy response back to the gateway client response. (There is an experimental `WebClientWriteResponseFilter` that performs the same function, but does not require netty)

=== RouteToRequestUrl Filter

The `RouteToRequestUrlFilter` runs if there is a `Route` object in the `ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR` exchange attribute. It creates a new URI, based off of the request URI, but updated with the URI attribute of the `Route` object. The new URI is placed in the ``ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR` exchange attribute`.

=== Websocket Routing Filter

The Websocket Routing Filter runs if the url located in the `ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR` exchange attribute has a `ws` or `wss` scheme. It uses the Spring Web Socket infrastructure to forward the Websocket request downstream.

== Configuration

Configuration for Spring Cloud Gateway is driven by a collection of `RouteDefinitionLocator`s.

.RouteDefinitionLocator.java
[source,java]
----
public interface RouteDefinitionLocator {
	Flux<RouteDefinition> getRouteDefinitions();
}
----

By default, a `PropertiesRouteDefinitionLocator` loads properties using Spring Boot's `@ConfigurationProperties` mechanism.

The configuration examples above all use a shortcut notation that uses positional arguments rather than named ones. The two examples below are equivalent:

.application.yml
[source,yaml]
----
spring:
  cloud:
    gateway:
      routes:
      # =====================================
      - id: setstatus_route
        uri: http://example.org
        filters:
        - name: SetStatus
          args:
            status: 401
      - id: setstatusshortcut_route
        uri: http://example.org
        filters:
        - SetStatus=401
----

For some usages of the gateway, properties will be adequate, but some production use cases will benefit from loading configuration from an external source, such as a database. Future milestone versions will have `RouteDefinitionLocator` implementations based off of Spring Data Repositories such as: Redis, MongoDB and Cassandra.

=== Fluent Java Routes API
To allow for simple configuration in Java, there is a fluent API defined in the `Routes` class.

.Config.java
[source,java]
----
// static imports from WebFilterFactories and RoutePredicates
@Bean
public RouteLocator customRouteLocator(ThrottleWebFilterFactory throttle) {
    return Routes.locator()
            .route("test")
                .uri("http://httpbin.org:80")
                .predicate(host("**.abc.org").and(path("/image/png")))
                .addResponseHeader("X-TestHeader", "foobar")
                .and()
            .route("test2")
                .uri("http://httpbin.org:80")
                .predicate(path("/image/webp"))
                .add(addResponseHeader("X-AnotherHeader", "baz"))
                .and()
            .build();
}
----

This style also allows for more custom predicate assertions. The predicates defined by `RouteDefinitionLocator` beans are combined using logical `and`. By using the fluent Java API, you can use the `and()`, `or()` and `negate()` operators on the `Predicate` class.

== Actuator API

TODO: document the `/gateway` actuator endpoint

== Developer Guide

TODO: overview of writing custom integrations

=== Writing Custom Route Predicate Factorys

TODO: document writing Custom Route Predicate Factorys

=== Writing Custom WebFilter Factorys

TODO: document writing Custom WebFilter Factorys

=== Writing Custom Global Filters

TODO: document writing Custom Global Filters

=== Writing Custom Route Locators and Writers

TODO: document writing Custom Route Locators and Writers

== Building a Simple Gateway Using Spring MVC

Spring Cloud Gateway provides a utility object called `ProxyExchange` which you can use inside a regular Spring MVC handler as a method parameter. It supports basic downstream HTTP exchanges via methods that mirror the HTTP verbs, or forwarding to a local handler via the `forward()` method.

Example (proxying a request to "/test" downstream to a remote server):

```java
@RestController
@SpringBootApplication
public class GatewaySampleApplication {

	@Value("${remote.home}")
	private URI home;

	@GetMapping("/test")
	public ResponseEntity<?> proxy(ProxyExchange<Object> proxy) throws Exception {
		return proxy.uri(home.toString() + "/image/png").get();
	}

}
```

There are convenience methods on the `ProxyExchange` to enable the handler method to discover and enhance the URI path of the incoming request. For example you might want to extract the trailing elements of a path to pass them downstream:

```java
@GetMapping("/proxy/path/**")
public ResponseEntity<?> proxyPath(ProxyExchange<?> proxy) throws Exception {
  String path = proxy.path("/proxy/path/");
  return proxy.uri(home.toString() + "/foos/" + path).get();
}
```

All the features of Spring MVC are available to Gateway handler methods. So you can inject request headers and query parameters, for instance, and you can constrain the incoming requests with declarations in the mapping annotation. See the documentation for `@RequestMapping` in Spring MVC for more details of those features.

Headers can be added to the downstream response using the `header()` methods on `ProxyExchange`.

You can also manipulate response headers (and anything else you like in the response) by adding a mapper to the `get()` etc. method. The mapper is a `Function` that takes the incoming `ResponseEntity` and converts it to an outgoing one.

First class support is provided for "sensitive" headers ("cookie" and "authorization" by default) which are not passed downstream, and for "proxy" headers (`x-forwarded-*`).