How to combine multiple named matchers

Hi guys,

using Caddy v2.6.4. I wonder how I can use multiple named matchers with the same handler. Here is what I tried:

example.com {
  @api_access1 {
    method PATCH
    header X-API-Key test1
    path /api/v1/aaa
  }

  @api_access2 {
    method PATCH
    header X-API-Key test2
    path /api/v1/bbb
  }

  handle @api_access1 @api_access2 {
    reverse_proxy http://backend {
      header_up X-API-Key top-secret
    }
  }
}

Fails with: “Error: adapting config using caddyfile: parsing caddyfile tokens for ‘handle’: /etc/caddy/Caddyfile:14 - Error during parsing: Wrong argument count or unexpected line ending after ‘@api_access2’”

2,.

example.com {
  @api_access1 {
    method PATCH
    header X-API-Key test1
    path /api/v1/aaa
  }

  @api_access2 {
    method PATCH
    header X-API-Key test2
    path /api/v1/bbb
  }

  @api_access {
    expression @api_access1 or @api_access2
  }

  handle @api_access {
    reverse_proxy http://backend {
      header_up X-API-Key top-secret
    }
  }
}

Fails with: “Error: loading initial config: loading new config: loading http app module: provision http: server srv0: setting up route handlers: route 0: loading handler modules: position 0: loading module ‘subroute’: provision http.handlers.subroute: setting up subroutes: route 0: loading matcher modules: module name ‘expression’: provision http.matchers.expression: compiling CEL program: ERROR: :1:1: Syntax error: token recognition error at: ‘@’”

(bla) {
  handle {args[0]} {
    reverse_proxy http://backend {
      header_up X-API-Key top-secret
    }
  }
}

example.com {
  @api_access1 {
    method PATCH
    header X-API-Key test1
    path /api/v1/aaa
  }
  import bla @api_access1

  @api_access2 {
    method PATCH
    header X-API-Key test2
    path /api/v1/bbb
  }
  import bla @api_access2
}

Fails with: “Error: adapting config using caddyfile: parsing caddyfile tokens for ‘handle’: /etc/caddy/Caddyfile:2 - Error during parsing: Wrong argument count or unexpected line ending after ‘{args[0]}’”

Any idea how to get this working in a simple way without duplication? Thank you :slight_smile:

I got it working with:

(bla) {
  reverse_proxy http://backend {
    header_up X-API-Key top-secret
  }
}

example.com {
  @api_access1 {
    method PATCH
    header X-API-Key test1
    path /api/v1/aaa
  }
  handle @api_access1 {
    import bla 
  }

  @api_access2 {
    method PATCH
    header X-API-Key test2
    path /api/v1/bbb
  }
  handle @api_access2 {
    import bla 
  }
}

[/quote]

But isn’t there an easier/ shorter solution? :slight_smile:

No, there’s no way to combine named matchers. It’s much easier said than done. The tricky part is that matchers in the Caddyfile need to map to JSON config, and combining them is very complex in JSON.

You can use the expression matcher to make complex conditions with && and || etc.

@api `
	method('PATCH') &&
	(header({'X-Api-Key':'test1'}) && path('/api/v1/aaa*')) ||
	(header({'X-Api-Key':'test2'}) && path('/api/v1/bbb*'))
`
2 Likes

Thank you @francislavoie !

Is there a way to see what JSON Caddy generates for a given Caddyfile? I’d like to think about some nice JSON for combined matchers.

I also wonder why my 3. attempt “(bla) { …” doesn’t work. Isn’t this a bug?

BTW, looking at the docs again it seems instead of a snippet it should also work using a named route (I didn’t try this yet), right?

&(bla) {
  reverse_proxy http://backend {
    header_up X-API-Key top-secret
  }
}

example.com {
  @api_access1 {
    method PATCH
    header X-API-Key test1
    path /api/v1/aaa
  }
  invoke @api_access1 bla

  @api_access2 {
    method PATCH
    header X-API-Key test2
    path /api/v1/bbb
  }
  invoke @api_access2 bla
}

Yes, run caddy adapt --pretty

I’m not sure what you mean, but if you’re using a Caddyfile you don’t really need to worry about JSON. I was just mentioning that as an explanation of why it’s not as easy as you might think.

I don’t understand. Please be more specific. What’s not working?

You can yeah :+1: