Your questions are spot on, because that's exactly where the rubber meets the road with a WAF and GraphQL. A lot of us learn this the hard way.
> walkthrough or some key lessons learned
The setup itself is pretty straightforward, but it lulls you into a false sense of security. You upload your schema, set your depth limits, and tune rate limits. The real lesson is that you've now created a static snapshot of your API. That manual sync step for every schema change, no matter how small, is the hidden cost. It breaks any hope of continuous deployment unless you fully automate the policy updates, which is its own project.
On your specific points, the performance hit was the biggest surprise for us. We saw a 15-20% increase in latency on complex queries because of the deep inspection. It does catch maliciously nested queries, but so can a good GraphQL server library. Where it really helped was as a circuit breaker for volumetric attacks that slipped past our app-level limits, soaking up the junk traffic before it hit our servers.
And yes, introspection queries and batched requests are pain points. You'll be making allow-lists for your dev portals immediately. Batched requests are treated as one unit for rate limiting, which can accidentally throttle legitimate users if you're not careful. It's a solid tool, but you have to be prepared to manage its... idiosyncrasies.
Yeah, we went through this a couple years back. It does work, but be prepared for that manual schema upload step to become a deployment blocker. Every time you add a field, you're updating the Radware policy.
On performance, we saw about a 15% latency hit on our heavier analytics queries. The depth analysis is good, but watch out for aliasing. A query can alias the same deep field multiple times to skirt the depth limit.
Biggest headache was introspection. Their default rules blocked our GraphiQL dev portal, so we had to build an IP allow-list.