Skip to content

Commit b8534de

Browse files
Merge pull request #204182 from adrianhall/apim/graphql-resolvers
Updates to graphql resolvers docs for galaxy release
2 parents 9aa09cd + 0474b54 commit b8534de

File tree

1 file changed

+169
-56
lines changed

1 file changed

+169
-56
lines changed

articles/api-management/graphql-policies.md

Lines changed: 169 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ services: api-management
55
author: dlepow
66
ms.service: api-management
77
ms.topic: reference
8-
ms.date: 05/17/2022
8+
ms.date: 07/08/2022
99
ms.author: danlep
10-
ms.custom: event-tier1-build-2022
1110
---
1211

1312
# API Management policies for GraphQL APIs
@@ -138,9 +137,6 @@ The `set-graphql-resolver` policy retrieves or sets data for a GraphQL field in
138137

139138
* This policy is invoked only when a matching GraphQL query is executed.
140139
* The policy resolves data for a single field. To resolve data for multiple fields, configure multiple occurrences of this policy in a policy definition.
141-
* The context for the HTTP request and HTTP response (if specified) differs from the context for the original gateway API request:
142-
* The HTTP request context contains arguments that are passed in the GraphQL query as its body.
143-
* The HTTP response context is the response from the independent HTTP call made by the resolver, not the context for the complete response for the gateway request.
144140

145141
[!INCLUDE [api-management-policy-generic-alert](../../includes/api-management-policy-generic-alert.md)]
146142

@@ -166,13 +162,160 @@ The `set-graphql-resolver` policy retrieves or sets data for a GraphQL field in
166162
</set-graphql-resolver>
167163
```
168164

169-
### Examples
165+
### Elements
166+
167+
| Name | Description | Required |
168+
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
169+
| `set-graphql-resolver` | Root element. | Yes |
170+
| `http-data-source` | Configures the HTTP request and optionally the HTTP response that are used to resolve data for the given `parent-type` and `field`. | Yes |
171+
| `http-request` | Specifies a URL and child policies to configure the resolver's HTTP request. Each child element can be specified at most once. | Yes |
172+
| `set-method`| Method of the resolver's HTTP request, configured using the [set-method](api-management-advanced-policies.md#SetRequestMethod) policy. | Yes |
173+
| `set-url` | URL of the resolver's HTTP request. | Yes |
174+
| `set-header` | Header set in the resolver's HTTP request, configured using the [set-header](api-management-transformation-policies.md#SetHTTPheader) policy. | No |
175+
| `set-body` | Body set in the resolver's HTTP request, configured using the [set-body](api-management-transformation-policies.md#SetBody) policy. | No |
176+
| `authentication-certificate` | Client certificate presented in the resolver's HTTP request, configured using the [authentication-certificate](api-management-authentication-policies.md#ClientCertificate) policy. | No |
177+
| `http-response` | Optionally specifies child policies to configure the resolver's HTTP response. If not specified, the response is returned as a raw string. Each child element can be specified at most once. |
178+
| `json-to-xml` | Transforms the resolver's HTTP response using the [json-to-xml](api-management-transformation-policies.md#ConvertJSONtoXML) policy. | No |
179+
| `xml-to-json` | Transforms the resolver's HTTP response using the [xml-to-json](api-management-transformation-policies.md#ConvertJSONtoXML) policy. | No |
180+
| `find-and-replace` | Transforms the resolver's HTTP response using the [find-and-replace](api-management-transformation-policies.md#Findandreplacestringinbody) policy. | No |
181+
182+
183+
### Attributes
184+
185+
| Name | Description | Required | Default |
186+
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- |
187+
| `parent-type`| An object type in the GraphQL schema. | Yes | N/A |
188+
| `field`| A field of the specified `parent-type` in the GraphQL schema. | Yes | N/A |
189+
190+
> [!NOTE]
191+
> Currently, the values of `parent-type` and `field` aren't validated by this policy. If they aren't valid, the policy is ignored, and the GraphQL query is forwarded to a GraphQL endpoint (if one is configured).
192+
193+
### Usage
194+
195+
This policy can be used in the following policy [sections](./api-management-howto-policies.md#sections) and [scopes](./api-management-howto-policies.md#scopes).
196+
197+
- **Policy sections:** backend
198+
- **Policy scopes:** all scopes
199+
200+
### GraphQL Context
201+
202+
* The context for the HTTP request and HTTP response (if specified) differs from the context for the original gateway API request:
203+
* `context.ParentResult` is set to the parent object for the current resolver execution.
204+
* The HTTP request context contains arguments that are passed in the GraphQL query as its body.
205+
* The HTTP response context is the response from the independent HTTP call made by the resolver, not the context for the complete response for the gateway request.
206+
The `context` variable that is passed through the request and response pipeline is augmented with the GraphQL context when used with `<set-graphql-resolver>` policies.
207+
208+
#### ParentResult
209+
210+
The `context.ParentResult` is set to the parent object for the current resolver execution. Consider the following partial schema:
211+
212+
``` graphql
213+
type Comment {
214+
id: ID!
215+
owner: string!
216+
content: string!
217+
}
218+
219+
type Blog {
220+
id: ID!
221+
title: string!
222+
content: string!
223+
comments: [Comment]!
224+
comment(id: ID!): Comment
225+
}
226+
227+
type Query {
228+
getBlog(): [Blog]!
229+
getBlog(id: ID!): Blog
230+
}
231+
```
232+
233+
Also, consider a GraphQL query for all the information for a specific blog:
234+
235+
``` graphql
236+
query {
237+
getBlog(id: 1) {
238+
title
239+
content
240+
comments {
241+
id
242+
owner
243+
content
244+
}
245+
}
246+
}
247+
```
248+
249+
If you set a resolver for `parent-type="Blog" field="comments"`, you will want to understand which blog ID to use. You can get the ID of the blog using `context.ParentResult.AsJObject()["id"].ToString()`. The policy for configuring this resolver would resemble:
250+
251+
``` xml
252+
<set-graphql-resolver parent-type="Blog" field="comments">
253+
<http-data-source>
254+
<http-request>
255+
<set-method>GET</set-method>
256+
<set-url>@{
257+
var blogId = context.ParentResult.AsJObject()["id"].ToString();
258+
return $"https://data.contoso.com/api/blog/{blogId}";
259+
}</set-url>
260+
</http-request>
261+
</http-data-source>
262+
</set-graphql-resolver>
263+
```
264+
265+
#### Arguments
170266

171-
### Resolver for GraphQL query
267+
The arguments for a parameterized GraphQL query are added to the body of the request. For example, consider the following two queries:
268+
269+
``` graphql
270+
query($id: Int) {
271+
getComment(id: $id) {
272+
content
273+
}
274+
}
275+
276+
query {
277+
getComment(id: 2) {
278+
content
279+
}
280+
}
281+
```
282+
283+
These queries are two ways of calling the `getComment` resolver. GraphQL sends the following JSON payload:
284+
285+
``` json
286+
{
287+
"query": "query($id: Int) { getComment(id: $id) { content } }",
288+
"variables": { "id": 2 }
289+
}
290+
291+
{
292+
"query": "query { getComment(id: 2) { content } }"
293+
}
294+
```
295+
296+
When the resolver is executed, the `arguments` property is added to the body. You can define the resolver as follows:
297+
298+
``` xml
299+
<set-graphql-resolver parent-type="Blog" field="comments">
300+
<http-data-source>
301+
<http-request>
302+
<set-method>GET</set-method>
303+
<set-url>@{
304+
var commentId = context.Request.Body.As<JObject>(true)["arguments"]["id"];
305+
return $"https://data.contoso.com/api/comment/{commentId}";
306+
}</set-url>
307+
</http-request>
308+
</http-data-source>
309+
</set-graphql-resolver>
310+
```
311+
312+
### More examples
313+
314+
#### Resolver for GraphQL query
172315

173316
The following example resolves a query by making an HTTP `GET` call to a backend data source.
174317

175-
#### Example schema
318+
##### Example schema
176319

177320
```
178321
type Query {
@@ -185,7 +328,7 @@ type User {
185328
}
186329
```
187330

188-
#### Example policy
331+
##### Example policy
189332

190333
```xml
191334
<set-graphql-resolver parent-type="Query" field="users">
@@ -198,11 +341,11 @@ type User {
198341
</set-graphql-resolver>
199342
```
200343

201-
### Resolver for a GraqhQL query that returns a list, using a liquid template
344+
#### Resolver for a GraqhQL query that returns a list, using a liquid template
202345

203-
The following example uses a liquid template, supported for use in the [set-body](api-management-transformation-policies.md#SetBody) policy, to return a list in the HTTP response to a query.
346+
The following example uses a liquid template, supported for use in the [set-body](api-management-transformation-policies.md#SetBody) policy, to return a list in the HTTP response to a query. It also renames the `username` field in the response from the REST API to `name` in the GraphQL response.
204347

205-
#### Example schema
348+
##### Example schema
206349

207350
```
208351
type Query {
@@ -215,7 +358,7 @@ type User {
215358
}
216359
```
217360

218-
#### Example policy
361+
##### Example policy
219362

220363
```xml
221364
<set-graphql-resolver parent-type="Query" field="users">
@@ -229,7 +372,7 @@ type User {
229372
[
230373
{% JSONArrayFor elem in body %}
231374
{
232-
"name": "{{elem.title}}"
375+
"name": "{{elem.username}}"
233376
}
234377
{% endJSONArrayFor %}
235378
]
@@ -239,11 +382,17 @@ type User {
239382
</set-graphql-resolver>
240383
```
241384

242-
### Resolver for GraphQL mutation
385+
#### Resolver for GraphQL mutation
243386

244-
The following example resolves a mutation that inserts data by making a `POST` request to an HTTP data source. The policy expression in the `set-body` policy of the HTTP request modifies a `name` argument that is passed in the GraphQL query as its body.
387+
The following example resolves a mutation that inserts data by making a `POST` request to an HTTP data source. The policy expression in the `set-body` policy of the HTTP request modifies a `name` argument that is passed in the GraphQL query as its body. The body that is sent will look like the following JSON:
245388

246-
#### Example schema
389+
``` json
390+
{
391+
"name": "the-provided-name"
392+
}
393+
```
394+
395+
##### Example schema
247396

248397
```
249398
type Query {
@@ -260,7 +409,7 @@ type User {
260409
}
261410
```
262411

263-
#### Example policy
412+
##### Example policy
264413

265414
```xml
266415
<set-graphql-resolver parent-type="Mutation" field="makeUser">
@@ -272,50 +421,14 @@ type User {
272421
<value>application/json</value>
273422
</set-header>
274423
<set-body>@{
275-
var body = context.Request.Body.As<JObject>(true);
424+
var args = context.Request.Body.As<JObject>(true)["arguments"];
276425
JObject jsonObject = new JObject();
277-
jsonObject.Add("name", body["name"])
426+
jsonObject.Add("name", args["name"])
278427
return jsonObject.ToString();
279428
}</set-body>
280429
</http-request>
281430
</http-data-source>
282431
</set-graphql-resolver>
283432
```
284433

285-
### Elements
286-
287-
| Name | Description | Required |
288-
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
289-
| `set-graphql-resolver` | Root element. | Yes |
290-
| `http-data-source` | Configures the HTTP request and optionally the HTTP response that are used to resolve data for the given `parent-type` and `field`. | Yes |
291-
| `http-request` | Specifies a URL and child policies to configure the resolver's HTTP request. Each child element can be specified at most once. | Yes |
292-
| `set-method`| Method of the resolver's HTTP request, configured using the [set-method](api-management-advanced-policies.md#SetRequestMethod) policy. | Yes |
293-
| `set-url` | URL of the resolver's HTTP request. | Yes |
294-
| `set-header` | Header set in the resolver's HTTP request, configured using the [set-header](api-management-transformation-policies.md#SetHTTPheader) policy. | No |
295-
| `set-body` | Body set in the resolver's HTTP request, configured using the [set-body](api-management-transformation-policies.md#SetBody) policy. | No |
296-
| `authentication-certificate` | Client certificate presented in the resolver's HTTP request, configured using the [authentication-certificate](api-management-authentication-policies.md#ClientCertificate) policy. | No |
297-
| `http-response` | Optionally specifies child policies to configure the resolver's HTTP response. If not specified, the response is returned as a raw string. Each child element can be specified at most once. |
298-
| `json-to-xml` | Transforms the resolver's HTTP response using the [json-to-xml](api-management-transformation-policies.md#ConvertJSONtoXML) policy. | No |
299-
| `xml-to-json` | Transforms the resolver's HTTP response using the [xml-to-json](api-management-transformation-policies.md#ConvertJSONtoXML) policy. | No |
300-
| `find-and-replace` | Transforms the resolver's HTTP response using the [find-and-replace](api-management-transformation-policies.md#Findandreplacestringinbody) policy. | No |
301-
302-
303-
### Attributes
304-
305-
| Name | Description | Required | Default |
306-
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- |
307-
| `parent-type`| An object type in the GraphQL schema. | Yes | N/A |
308-
| `field`| A field of the specified `parent-type` in the GraphQL schema. | Yes | N/A |
309-
310-
> [!NOTE]
311-
> Currently, the values of `parent-type` and `field` aren't validated by this policy. If they aren't valid, the policy is ignored, and the GraphQL query is forwarded to a GraphQL endpoint (if one is configured).
312-
313-
### Usage
314-
315-
This policy can be used in the following policy [sections](./api-management-howto-policies.md#sections) and [scopes](./api-management-howto-policies.md#scopes).
316-
317-
- **Policy sections:** backend
318-
319-
- **Policy scopes:** all scopes
320-
321434
[!INCLUDE [api-management-policy-ref-next-steps](../../includes/api-management-policy-ref-next-steps.md)]

0 commit comments

Comments
 (0)