Making HTTP Requests

Learn how to make HTTP requests with Apollo Connectors


Apollo Connectors provide a declarative way to integrate REST API calls into your graph using the @connect and @source directives in your schemas. In this guide, you'll learn the basics of making HTTP requests with Apollo Connectors. It includes examples specifying the HTTP method and URL, setting headers, and defining request bodies.

HTTP Methods

You specify the HTTP method for your request in the http argument of a @connect directive. You must specify one of the following HTTP methods: GET, POST, PUT, PATCH, or DELETE, followed by the URL.

Example GET request

GraphQL
Example Connector for GET HTTP method
1type Query {
2  products: [Product]
3    @connect(
4      http: { GET: "https://myapi.dev/products" }
5      selection: "id"
6    )
7}

Example POST request

GraphQL
Example Connector for POST HTTP method
1type Mutation {
2  createProduct(name: String!): Product
3    @connect(
4      http: {
5        POST: "https://myapi.dev/products"
6        body: "name: $args.name"
7      }
8      selection: "id"
9    )
10}

Example PUT request

GraphQL
Example Connector for PUT HTTP method
1type Mutation {
2  setProduct(id: ID!, name: String!): Product
3    @connect(
4      http: {
5        PUT: "https://myapi.dev/products/{$args.id}"
6        body: """
7        {
8          name: $args.name,
9          description: $args.description,
10          price: $args.price,
11          inventory: $args.inventory
12        }
13        """
14      }
15      selection: "id"
16    )
17}

Example PATCH request

GraphQL
Example Connector for PATCH HTTP method
1type Mutation {
2  updateProduct(id: ID!, name: String!): Product
3    @connect(
4      http: {
5        PATCH: "https://myapi.dev/products/{$args.id}?name={$args.name}"
6        body: "name: $args.name"
7      }
8      selection: "id"
9    )
10}

Example DELETE request

GraphQL
Example Connector for DELETE HTTP method
1type Mutation {
2  deleteProduct(id: ID!): Product
3    @connect(
4      http: {
5        DELETE: "https://myapi.dev/products/{$args.id}"
6      }
7      selection: "id"
8    )
9}

Dynamic URLs

URLs can be dynamic and use values from field arguments, sibling fields, and router configuration. The dynamic parts appear between curly braces ({}). For example, you can use field arguments as path segments.

The example below uses the productID argument in the path:

GraphQL
Example Connector with dynamic path segments
1type Query {
2  product(storeId: ID!, productId: ID!): Product
3    @connect(
4      http: {
5        GET: "https://myapi.dev/products/{$args.productId}"
6      }
7      selection: "id"
8    )
9}

Path segment values are URL-encoded. If the value contains a /, it is encoded as %2F. Learn more about using arguments in your URLs, including as query parameters and for pagination.

Headers

You add headers to your HTTP requests using the http.headers argument. Like with URIs, you can define header values using a combination of fixed values and dynamic mapping expressions in curly braces ({}).

The following example uses a static value for the x-api-version header and a dynamic value with the $config variable for the Authorization header:

GraphQL
Example Connector with headers
1type Query {
2  products: [Product]
3    @connect(
4      http: {
5        GET: "https://myapi.dev/products"
6        headers: [
7          { name: "x-api-version", value: "2024-01-01" }
8          { name: "Authorization", value: "Bearer {$config.token}" }
9        ]
10      }
11      selection: "id"
12    )
13}

You can also propagate headers from the incoming client request using the from argument:

GraphQL
Example Connector with client header propagation
1type Query {
2  products: [Product]
3    @connect(
4      http: { GET: "https://myapi.dev/products", headers: [{ name: "Authorization", from: "Authorization" }] }
5      selection: "id"
6    )
7}
note
The router's header propagation configuration doesn't affect Connector requests.

Sharing configuration with @source

You can use the @source directive to share a partial URL and headers with multiple Connectors.

Source definition

To define a @source:

GraphQL
Example @source creation
1extend schema
2  @link(
3    url: "https://specs.apollo.dev/connect/v0.1",
4    import: ["@connect", "@source"]
5  )
6  @source(
7    name: "myapi"
8    http: {
9      baseURL: "https://myapi.example.com/v1?client=router"
10      headers: [{ name: "X-API-Key", value: "{$config.api_key}" }]
11    }
12  )
  1. Import the @source directive from the Connectors @link. (line 4 above)

  2. Apply the @source directive to the schema. (lines 6-12 above)

    • Define a baseURL.

    • Optionally define headers, which can't contain $this or $args.

Source usage

To use a @source:

GraphQL
Example Connector with a related @source
1
2type Query {
3  products(first: Int = 10): [Product]
4    @connect(
5      source: "myapi"
6      http: {
7        GET: "/products?first={$args.first}",
8        headers: [{ name: "X-Product-Type", from: "Product-Type" }]
9      }
10      selection: "id"
11    )
12}
  1. Set the source field in each @connect directive that should use the shared configuration. Use the name defined in source definition.

  2. Use a partial URL in the @connect directive containing only the path and query parameters (no scheme, host, etc.).

  3. Define headers in @connect to override headers from the @source with the same name.

The Connector request above resolves to https://myapi.example.com/v1/products?client=router&first=10. It includes the X-API-Key header from the @source configuration and the X-Product-Type header from the @connect configuration.

Defining request bodies

The http.body field defines a JSON body to send with the request using the mapping language.

GraphQL
Example Connector with a request body
1type Mutation {
2  createProduct(input: CreateProductInput!): Product
3    @connect(
4      http: {
5        POST: "https://myapi.dev/products"
6        body: """
7        $args.input {
8          name
9          price
10        }
11        """
12      }
13      selection: "id"
14    )
15}

Form URL encoding

By adding a Content-Type header of exactly application/x-www-form-urlencoded, GraphOS Router encodes the request body as a form URL encoded string.

GraphQL
Form URL encoding
1type Mutation {
2  createPost(input: CreatePostInput!): Post
3    @connect(
4      http: {
5        POST: "https://api.example.com/posts"
6        headers: [{ name: "Content-Type", value: "application/x-www-form-urlencoded" }]
7      }
8      selection: """
9      $args.input {
10        title
11        content
12      }
13      """
14    )
15}

The router first maps the request body to a JSON object:

JSON
{
  "title": "Hello, world!",
  "content": "This is a post."
}

Then, it encodes the object as a x-www-form-urlencoded string:

plaintext
title=Hello%2C+world%21&content=This+is+a+post.
Form URL encoding details
  • List values are indexed starting from 0 using the list[0]=value syntax.
  • Nested objects use the parent[child]=value syntax.
  • Spaces are encoded as +.
GraphQL
Example: form URL encoding
1type Mutation {
2  example(input: ExampleInput!): Example
3    @connect(
4      http: { POST: "/example", headers: [{ name: "content-type", value: "application/x-www-form-urlencoded" }] }
5      selection: """
6      $args.input {
7        name
8        tags
9        addresses {
10          street
11          city
12          state
13          zip
14        }
15      }
16      """
17    )
18}
19
20input ExampleInput {
21  name: String!
22  tags: [String!]
23  addresses: [AddressInput!]
24}
25
26input AddressInput {
27  street: String!
28  city: String!
29  state: String!
30  zip: String!
31}
plaintext
Result (new lines added for readability)
1name=Example
2&tags[0]=tag1
3&tags[1]=tag2
4&addresses[0][street]=123+Main+St
5&addresses[0][city]=Anytown
6&addresses[0][state]=CA
7&addresses[0][zip]=12345
8&addresses[1][street]=456+Elm+St
9&addresses[1][city]=Othertown
10&addresses[1][state]=NY
11&addresses[1][zip]=54321

Error handling

Following the GraphQL specification, if a Connector returns an error, the corresponding field in the response's data is null, and the error is logged in the errors array. Connectors follow this convention for all non-20x responses.

See the common errors section on the troubleshooting page for information on composition errors.

Additional resources

Follow the guide on creating a Connector with arguments to see an example using the fictional ecommerce API used in the quickstart.

Feedback

Ask Community