k8s_gateway_api/
httproute.rs

1use crate::*;
2
3/// HTTPRoute provides a way to route HTTP requests. This includes the
4/// capability to match requests by hostname, path, header, or query param.
5/// Filters can be used to specify additional processing steps. Backends specify
6/// where matching requests should be routed.
7#[derive(
8    Clone,
9    Debug,
10    Default,
11    kube::CustomResource,
12    serde::Deserialize,
13    serde::Serialize,
14    schemars::JsonSchema,
15)]
16#[kube(
17    group = "gateway.networking.k8s.io",
18    version = "v1beta1",
19    kind = "HTTPRoute",
20    root = "HttpRoute",
21    status = "HttpRouteStatus",
22    namespaced
23)]
24pub struct HttpRouteSpec {
25    /// Common route information.
26    #[serde(flatten)]
27    pub inner: CommonRouteSpec,
28
29    /// Hostnames defines a set of hostname that should match against the HTTP
30    /// Host header to select a HTTPRoute to process the request. This matches
31    /// the RFC 1123 definition of a hostname with 2 notable exceptions:
32    ///
33    /// 1. IPs are not allowed.
34    /// 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard
35    ///    label must appear by itself as the first label.
36    ///
37    /// If a hostname is specified by both the Listener and HTTPRoute, there
38    /// must be at least one intersecting hostname for the HTTPRoute to be
39    /// attached to the Listener. For example:
40    ///
41    /// * A Listener with `test.example.com` as the hostname matches HTTPRoutes
42    ///   that have either not specified any hostnames, or have specified at
43    ///   least one of `test.example.com` or `*.example.com`.
44    /// * A Listener with `*.example.com` as the hostname matches HTTPRoutes
45    ///   that have either not specified any hostnames or have specified at least
46    ///   one hostname that matches the Listener hostname. For example,
47    ///   `test.example.com` and `*.example.com` would both match. On the other
48    ///   hand, `example.com` and `test.example.net` would not match.
49    ///
50    /// If both the Listener and HTTPRoute have specified hostnames, any
51    /// HTTPRoute hostnames that do not match the Listener hostname MUST be
52    /// ignored. For example, if a Listener specified `*.example.com`, and the
53    /// HTTPRoute specified `test.example.com` and `test.example.net`,
54    /// `test.example.net` must not be considered for a match.
55    ///
56    /// If both the Listener and HTTPRoute have specified hostnames, and none
57    /// match with the criteria above, then the HTTPRoute is not accepted. The
58    /// implementation must raise an 'Accepted' Condition with a status of
59    /// `False` in the corresponding RouteParentStatus.
60    ///
61    /// Support: Core
62    pub hostnames: Option<Vec<Hostname>>,
63
64    /// Rules are a list of HTTP matchers, filters and actions.
65    pub rules: Option<Vec<HttpRouteRule>>,
66}
67
68/// HTTPRouteRule defines semantics for matching an HTTP request based on
69/// conditions (matches), processing it (filters), and forwarding the request to
70/// an API object (backendRefs).
71#[derive(
72    Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
73)]
74#[serde(rename_all = "camelCase")]
75pub struct HttpRouteRule {
76    /// Matches define conditions used for matching the rule against incoming
77    /// HTTP requests. Each match is independent, i.e. this rule will be matched
78    /// if **any** one of the matches is satisfied.
79    ///
80    /// For example, take the following matches configuration:
81    ///
82    /// ```yaml
83    /// matches:
84    /// - path:
85    ///     value: "/foo"
86    ///   headers:
87    ///   - name: "version"
88    ///     value: "v2"
89    /// - path:
90    ///     value: "/v2/foo"
91    /// ```
92    ///
93    /// For a request to match against this rule, a request must satisfy
94    /// EITHER of the two conditions:
95    ///
96    /// - path prefixed with `/foo` AND contains the header `version: v2`
97    /// - path prefix of `/v2/foo`
98    ///
99    /// See the documentation for HTTPRouteMatch on how to specify multiple
100    /// match conditions that should be ANDed together.
101    ///
102    /// If no matches are specified, the default is a prefix
103    /// path match on "/", which has the effect of matching every
104    /// HTTP request.
105    ///
106    /// Proxy or Load Balancer routing configuration generated from HTTPRoutes
107    /// MUST prioritize rules based on the following criteria, continuing on
108    /// ties. Precedence must be given to the the Rule with the largest number
109    /// of:
110    ///
111    /// * Characters in a matching non-wildcard hostname.
112    /// * Characters in a matching hostname.
113    /// * Characters in a matching path.
114    /// * Header matches.
115    /// * Query param matches.
116    ///
117    /// If ties still exist across multiple Routes, matching precedence MUST be
118    /// determined in order of the following criteria, continuing on ties:
119    ///
120    /// * The oldest Route based on creation timestamp.
121    /// * The Route appearing first in alphabetical order by
122    ///   "{namespace}/{name}".
123    ///
124    /// If ties still exist within the Route that has been given precedence,
125    /// matching precedence MUST be granted to the first matching rule meeting
126    /// the above criteria.
127    ///
128    /// When no rules matching a request have been successfully attached to the
129    /// parent a request is coming from, a HTTP 404 status code MUST be returned.
130    pub matches: Option<Vec<HttpRouteMatch>>,
131
132    /// Filters define the filters that are applied to requests that match this
133    /// rule.
134    ///
135    /// The effects of ordering of multiple behaviors are currently unspecified.
136    /// This can change in the future based on feedback during the alpha stage.
137    ///
138    /// Conformance-levels at this level are defined based on the type of
139    /// filter:
140    ///
141    /// - ALL core filters MUST be supported by all implementations.
142    /// - Implementers are encouraged to support extended filters.
143    /// - Implementation-specific custom filters have no API guarantees across
144    ///   implementations.
145    ///
146    /// Specifying a core filter multiple times has unspecified or custom
147    /// conformance.
148    ///
149    /// Support: Core
150    pub filters: Option<Vec<HttpRouteFilter>>,
151
152    /// BackendRefs defines the backend(s) where matching requests should be
153    /// sent.
154    ///
155    /// A 500 status code MUST be returned if there are no BackendRefs or
156    /// filters specified that would result in a response being sent.
157    ///
158    /// A BackendRef is considered invalid when it refers to:
159    ///
160    /// * an unknown or unsupported kind of resource
161    /// * a resource that does not exist
162    /// * a resource in another namespace when the reference has not been
163    ///   explicitly allowed by a ReferencePolicy (or equivalent concept).
164    ///
165    /// When a BackendRef is invalid, 500 status codes MUST be returned for
166    /// requests that would have otherwise been routed to an invalid backend. If
167    /// multiple backends are specified, and some are invalid, the proportion of
168    /// requests that would otherwise have been routed to an invalid backend
169    /// MUST receive a 500 status code.
170    ///
171    /// When a BackendRef refers to a Service that has no ready endpoints, it is
172    /// recommended to return a 503 status code.
173    ///
174    /// Support: Core for Kubernetes Service
175    /// Support: Custom for any other resource
176    ///
177    /// Support for weight: Core
178    pub backend_refs: Option<Vec<HttpBackendRef>>,
179}
180
181/// HTTPRouteMatch defines the predicate used to match requests to a given
182/// action. Multiple match types are ANDed together, i.e. the match will
183/// evaluate to true only if all conditions are satisfied.
184///
185/// For example, the match below will match a HTTP request only if its path
186/// starts with `/foo` AND it contains the `version: v1` header:
187///
188/// ```yaml
189/// match:
190///   path:
191///     value: "/foo"
192///   headers:
193///   - name: "version"
194///     value "v1"
195/// ```
196#[derive(
197    Clone, Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
198)]
199#[serde(rename_all = "camelCase")]
200pub struct HttpRouteMatch {
201    /// Path specifies a HTTP request path matcher. If this field is not
202    /// specified, a default prefix match on the "/" path is provided.
203    pub path: Option<HttpPathMatch>,
204
205    /// Headers specifies HTTP request header matchers. Multiple match values
206    /// are ANDed together, meaning, a request must match all the specified
207    /// headers to select the route.
208    pub headers: Option<Vec<HttpHeaderMatch>>,
209
210    /// QueryParams specifies HTTP query parameter matchers. Multiple match
211    /// values are ANDed together, meaning, a request must match all the
212    /// specified query parameters to select the route.
213    pub query_params: Option<Vec<HttpQueryParamMatch>>,
214
215    /// Method specifies HTTP method matcher.
216    ///
217    /// When specified, this route will be matched only if the request has the
218    /// specified method.
219    ///
220    /// Support: Extended
221    pub method: Option<HttpMethod>,
222}
223
224/// HTTPPathMatch describes how to select a HTTP route by matching the HTTP request path.
225///
226/// The `type` specifies the semantics of how HTTP paths should be compared.
227/// Valid PathMatchType values are:
228///
229/// * "Exact"
230/// * "PathPrefix"
231/// * "RegularExpression"
232///
233/// PathPrefix and Exact paths must be syntactically valid:
234///
235/// - Must begin with the `/` character
236/// - Must not contain consecutive `/` characters (e.g. `/foo///`, `//`)
237#[derive(
238    Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
239)]
240#[serde(tag = "type", rename_all = "PascalCase")]
241pub enum HttpPathMatch {
242    Exact { value: String },
243    PathPrefix { value: String },
244    RegularExpression { value: String },
245}
246
247/// HTTPHeaderName is the name of an HTTP header.
248///
249/// Valid values include:
250///
251/// * "Authorization"
252/// * "Set-Cookie"
253///
254/// Invalid values include:
255///
256/// * ":method" - ":" is an invalid character. This means that HTTP/2 pseudo
257///   headers are not currently supported by this type.
258/// * "/invalid" - "/" is an invalid character
259pub type HttpHeaderName = String;
260
261/// HTTPHeaderMatch describes how to select a HTTP route by matching HTTP
262/// request headers.
263///
264/// `name` is the name of the HTTP Header to be matched. Name matching MUST be
265/// case insensitive. (See <https://tools.ietf.org/html/rfc7230#section-3.2>).
266///
267/// If multiple entries specify equivalent header names, only the first
268/// entry with an equivalent name MUST be considered for a match. Subsequent
269/// entries with an equivalent header name MUST be ignored. Due to the
270/// case-insensitivity of header names, "foo" and "Foo" are considered
271/// equivalent.
272///
273/// When a header is repeated in an HTTP request, it is
274/// implementation-specific behavior as to how this is represented.
275/// Generally, proxies should follow the guidance from the RFC:
276/// <https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2> regarding
277/// processing a repeated header, with special handling for "Set-Cookie".
278#[derive(
279    Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
280)]
281#[serde(tag = "type", rename_all = "PascalCase")]
282pub enum HttpHeaderMatch {
283    #[serde(rename_all = "camelCase")]
284    Exact { name: HttpHeaderName, value: String },
285
286    #[serde(rename_all = "camelCase")]
287    RegularExpression {
288        name: HttpHeaderName,
289
290        /// Since RegularExpression HeaderMatchType has custom conformance,
291        /// implementations can support POSIX, PCRE or any other dialects of regular
292        /// expressions. Please read the implementation's documentation to determine
293        /// the supported dialect.
294        value: String,
295    },
296}
297
298/// HTTPQueryParamMatch describes how to select a HTTP route by matching HTTP
299/// query parameters.
300#[derive(
301    Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
302)]
303#[serde(tag = "type", rename_all = "PascalCase")]
304pub enum HttpQueryParamMatch {
305    #[serde(rename_all = "camelCase")]
306    Exact { name: String, value: String },
307
308    #[serde(rename_all = "camelCase")]
309    RegularExpression { name: String, value: String },
310}
311
312/// HTTPMethod describes how to select a HTTP route by matching the HTTP
313/// method as defined by
314/// [RFC 7231](https://datatracker.ietf.org/doc/html/rfc7231#section-4) and
315/// [RFC 5789](https://datatracker.ietf.org/doc/html/rfc5789#section-2).
316/// The value is expected in upper case.
317pub type HttpMethod = String;
318
319/// HTTPRouteFilter defines processing steps that must be completed during the
320/// request or response lifecycle. HTTPRouteFilters are meant as an extension
321/// point to express processing that may be done in Gateway implementations.
322/// Some examples include request or response modification, implementing
323/// authentication strategies, rate-limiting, and traffic shaping. API
324/// guarantee/conformance is defined based on the type of the filter.
325///
326/// Type identifies the type of filter to apply. As with other API fields,
327/// types are classified into three conformance levels:
328///
329/// - Core: Filter types and their corresponding configuration defined by
330///   "Support: Core" in this package, e.g. "RequestHeaderModifier". All
331///   implementations must support core filters.
332///
333/// - Extended: Filter types and their corresponding configuration defined by
334///   "Support: Extended" in this package, e.g. "RequestMirror". Implementers
335///   are encouraged to support extended filters.
336///
337/// - Custom: Filters that are defined and supported by specific vendors.
338///   In the future, filters showing convergence in behavior across multiple
339///   implementations will be considered for inclusion in extended or core
340///   conformance levels. Filter-specific configuration for such filters
341///   is specified using the ExtensionRef field. `Type` should be set to
342///   "ExtensionRef" for custom filters.
343///
344/// Implementers are encouraged to define custom implementation types to
345/// extend the core API with implementation-specific behavior.
346///
347/// If a reference to a custom filter type cannot be resolved, the filter
348/// MUST NOT be skipped. Instead, requests that would have been processed by
349/// that filter MUST receive a HTTP error response.
350#[derive(
351    Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
352)]
353#[serde(tag = "type", rename_all = "PascalCase")]
354pub enum HttpRouteFilter {
355    /// RequestHeaderModifier defines a schema for a filter that modifies request
356    /// headers.
357    ///
358    /// Support: Core
359    #[serde(rename_all = "camelCase")]
360    RequestHeaderModifier {
361        request_header_modifier: HttpRequestHeaderFilter,
362    },
363
364    /// ResponseHeaderModifier defines a schema for a filter that modifies
365    /// response headers.
366    ///
367    /// Support: Extended
368    #[serde(rename_all = "camelCase")]
369    ResponseHeaderModifier {
370        response_header_modifier: HttpRequestHeaderFilter,
371    },
372
373    /// RequestMirror defines a schema for a filter that mirrors requests.
374    /// Requests are sent to the specified destination, but responses from
375    /// that destination are ignored.
376    ///
377    /// Support: Extended
378    #[serde(rename_all = "camelCase")]
379    RequestMirror {
380        request_mirror: HttpRequestMirrorFilter,
381    },
382
383    /// RequestRedirect defines a schema for a filter that responds to the
384    /// request with an HTTP redirection.
385    ///
386    /// Support: Core
387    #[serde(rename_all = "camelCase")]
388    RequestRedirect {
389        request_redirect: HttpRequestRedirectFilter,
390    },
391
392    /// URLRewrite defines a schema for a filter that modifies a request during forwarding.
393    ///
394    /// Support: Extended
395    #[serde(rename_all = "camelCase")]
396    URLRewrite { url_rewrite: HttpUrlRewriteFilter },
397
398    /// ExtensionRef is an optional, implementation-specific extension to the
399    /// "filter" behavior.  For example, resource "myroutefilter" in group
400    /// "networking.example.net"). ExtensionRef MUST NOT be used for core and
401    /// extended filters.
402    ///
403    /// Support: Implementation-specific
404    #[serde(rename_all = "camelCase")]
405    ExtensionRef { extension_ref: LocalObjectReference },
406}
407
408/// HTTPRequestHeaderFilter defines configuration for the RequestHeaderModifier
409/// filter.
410#[derive(
411    Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
412)]
413pub struct HttpRequestHeaderFilter {
414    /// Set overwrites the request with the given header (name, value)
415    /// before the action.
416    ///
417    /// Input:
418    ///   GET /foo HTTP/1.1
419    ///   my-header: foo
420    ///
421    /// Config:
422    ///   set:
423    ///   - name: "my-header"
424    ///     value: "bar"
425    ///
426    /// Output:
427    ///   GET /foo HTTP/1.1
428    ///   my-header: bar
429    pub set: Option<Vec<HttpHeader>>,
430
431    /// Add adds the given header(s) (name, value) to the request
432    /// before the action. It appends to any existing values associated
433    /// with the header name.
434    ///
435    /// Input:
436    ///   GET /foo HTTP/1.1
437    ///   my-header: foo
438    ///
439    /// Config:
440    ///   add:
441    ///   - name: "my-header"
442    ///     value: "bar"
443    ///
444    /// Output:
445    ///   GET /foo HTTP/1.1
446    ///   my-header: foo
447    ///   my-header: bar
448    pub add: Option<Vec<HttpHeader>>,
449
450    /// Remove the given header(s) from the HTTP request before the action. The
451    /// value of Remove is a list of HTTP header names. Note that the header
452    /// names are case-insensitive (see
453    /// <https://datatracker.ietf.org/doc/html/rfc2616#section-4.2>).
454    ///
455    /// Input:
456    ///   GET /foo HTTP/1.1
457    ///   my-header1: foo
458    ///   my-header2: bar
459    ///   my-header3: baz
460    ///
461    /// Config:
462    ///   remove: ["my-header1", "my-header3"]
463    ///
464    /// Output:
465    ///   GET /foo HTTP/1.1
466    ///   my-header2: bar
467    pub remove: Option<Vec<String>>,
468}
469
470/// HTTPHeader represents an HTTP Header name and value as defined by RFC 7230.
471#[derive(
472    Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
473)]
474pub struct HttpHeader {
475    /// Name is the name of the HTTP Header to be matched. Name matching MUST be
476    /// case insensitive. (See <https://tools.ietf.org/html/rfc7230#section-3.2>).
477    ///
478    /// If multiple entries specify equivalent header names, the first entry with
479    /// an equivalent name MUST be considered for a match. Subsequent entries
480    /// with an equivalent header name MUST be ignored. Due to the
481    /// case-insensitivity of header names, "foo" and "Foo" are considered
482    /// equivalent.
483    pub name: HttpHeaderName,
484
485    /// Value is the value of HTTP Header to be matched.
486    pub value: String,
487}
488
489/// HTTPPathModifier defines configuration for path modifiers.
490///
491// gateway:experimental
492#[derive(
493    Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
494)]
495#[serde(tag = "type", rename_all = "PascalCase")]
496pub enum HttpPathModifier {
497    /// ReplaceFullPath specifies the value with which to replace the full path
498    /// of a request during a rewrite or redirect.
499    #[serde(rename_all = "camelCase")]
500    ReplaceFullPath { replace_full_path: String },
501
502    /// ReplacePrefixMatch specifies the value with which to replace the prefix
503    /// match of a request during a rewrite or redirect. For example, a request
504    /// to "/foo/bar" with a prefix match of "/foo" would be modified to "/bar".
505    #[serde(rename_all = "camelCase")]
506    ReplacePrefixMatch { replace_prefix_match: String },
507}
508
509/// HTTPRequestRedirect defines a filter that redirects a request. This filter
510/// MUST not be used on the same Route rule as a HTTPURLRewrite filter.
511#[derive(
512    Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
513)]
514#[serde(rename_all = "camelCase")]
515pub struct HttpRequestRedirectFilter {
516    /// Scheme is the scheme to be used in the value of the `Location`
517    /// header in the response.
518    /// When empty, the scheme of the request is used.
519    ///
520    /// Support: Extended
521    pub scheme: Option<String>,
522
523    /// Hostname is the hostname to be used in the value of the `Location`
524    /// header in the response.
525    ///
526    /// When empty, the hostname of the request is used.
527    ///
528    /// Support: Core
529    pub hostname: Option<PreciseHostname>,
530
531    /// Path defines parameters used to modify the path of the incoming request.
532    /// The modified path is then used to construct the `Location` header. When
533    /// empty, the request path is used as-is.
534    ///
535    /// Support: Extended
536    pub path: Option<HttpPathModifier>,
537
538    /// Port is the port to be used in the value of the `Location`
539    /// header in the response.
540    /// When empty, port (if specified) of the request is used.
541    ///
542    /// Support: Extended
543    pub port: Option<PortNumber>,
544
545    /// StatusCode is the HTTP status code to be used in response.
546    ///
547    /// Support: Core
548    pub status_code: Option<u16>,
549}
550
551/// HTTPURLRewriteFilter defines a filter that modifies a request during
552/// forwarding. At most one of these filters may be used on a Route rule. This
553/// may not be used on the same Route rule as a HTTPRequestRedirect filter.
554///
555/// gateway:experimental
556/// Support: Extended
557#[derive(
558    Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
559)]
560pub struct HttpUrlRewriteFilter {
561    /// Hostname is the value to be used to replace the Host header value during
562    /// forwarding.
563    ///
564    /// Support: Extended
565    pub hostname: Option<PreciseHostname>,
566
567    /// Path defines a path rewrite.
568    ///
569    /// Support: Extended
570    pub path: Option<HttpPathModifier>,
571}
572
573/// HTTPRequestMirrorFilter defines configuration for the RequestMirror filter.
574#[derive(
575    Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
576)]
577#[serde(rename_all = "camelCase")]
578pub struct HttpRequestMirrorFilter {
579    /// BackendRef references a resource where mirrored requests are sent.
580    ///
581    /// If the referent cannot be found, this BackendRef is invalid and must be
582    /// dropped from the Gateway. The controller must ensure the "ResolvedRefs"
583    /// condition on the Route status is set to `status: False` and not configure
584    /// this backend in the underlying implementation.
585    ///
586    /// If there is a cross-namespace reference to an *existing* object
587    /// that is not allowed by a ReferencePolicy, the controller must ensure the
588    /// "ResolvedRefs"  condition on the Route is set to `status: False`,
589    /// with the "RefNotPermitted" reason and not configure this backend in the
590    /// underlying implementation.
591    ///
592    /// In either error case, the Message of the `ResolvedRefs` Condition
593    /// should be used to provide more detail about the problem.
594    ///
595    /// Support: Extended for Kubernetes Service
596    /// Support: Custom for any other resource
597    pub backend_ref: BackendObjectReference,
598}
599
600/// HTTPBackendRef defines how a HTTPRoute should forward an HTTP request.
601#[derive(
602    Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema,
603)]
604#[serde(rename_all = "camelCase")]
605pub struct HttpBackendRef {
606    /// BackendRef is a reference to a backend to forward matched requests to.
607    ///
608    /// If the referent cannot be found, this HTTPBackendRef is invalid and must
609    /// be dropped from the Gateway. The controller must ensure the
610    /// "ResolvedRefs" condition on the Route is set to `status: False` and not
611    /// configure this backend in the underlying implementation.
612    ///
613    /// If there is a cross-namespace reference to an *existing* object
614    /// that is not covered by a ReferencePolicy, the controller must ensure the
615    /// "ResolvedRefs"  condition on the Route is set to `status: False`,
616    /// with the "RefNotPermitted" reason and not configure this backend in the
617    /// underlying implementation.
618    ///
619    /// In either error case, the Message of the `ResolvedRefs` Condition
620    /// should be used to provide more detail about the problem.
621    ///
622    /// Support: Custom
623    #[serde(flatten)]
624    pub backend_ref: Option<BackendRef>,
625
626    /// Filters defined at this level should be executed if and only if the
627    /// request is being forwarded to the backend defined here.
628    ///
629    /// Support: Custom (For broader support of filters, use the Filters field
630    /// in HTTPRouteRule.)
631    pub filters: Option<Vec<HttpRouteFilter>>,
632}
633
634/// HTTPRouteStatus defines the observed state of HTTPRoute.
635#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
636pub struct HttpRouteStatus {
637    /// Common route status information.
638    #[serde(flatten)]
639    pub inner: RouteStatus,
640}
641
642#[cfg(test)]
643mod test {
644    use super::*;
645
646    #[test]
647    fn test_deserialize_http_route() {
648        // Test json with a URLRewrote
649        let test_json = r#"{
650            "apiVersion":"gateway.networking.k8s.io/v1beta1",
651            "kind":"HTTPRoute",
652            "metadata":{"name":"route_name"},
653            "spec":{
654                "parentRefs":null,
655                "hostnames":null,
656                "rules":[{
657                    "matches":null,
658                    "filters":[{
659                        "type":"URLRewrite",
660                        "urlRewrite":{
661                            "hostname":null,
662                            "path":{
663                                "type":"ReplacePrefixMatch",
664                                "replacePrefixMatch":"/"
665                            }
666                        }
667                    }],
668                    "backendRefs":null
669                }]}}"#;
670        let route: Result<HttpRoute, _> = serde_json::from_str(test_json);
671        assert!(route.is_ok());
672    }
673}