Make an HTTP request

You can define a workflow step that makes an HTTP call and assign the response from the call to a variable. For example, you can invoke a Google Cloud service such as Cloud Run functions or Cloud Run through an HTTP request.

Invoke an HTTP endpoint

This type of step allows you to make an HTTP request. Both HTTP and HTTPS requests are supported. The most common HTTP request methods have a call shortcut (such as http.get and http.post), but you can make any type of HTTP request by setting the call field to http.request and specifying the type of request using the method field.

YAML

  - STEP_NAME:
      call: HTTP_REQUEST
      args:
          url: URL_VALUE
          method: REQUEST_METHOD
          private_service_name: "REGISTERED_SERVICE"
          headers:
              HEADER_KEY:HEADER_VALUE
              ...
          body:
              BODY_KEY:BODY_VALUE
              ...
          query:
              QUERY_KEY:QUERY_VALUE
              ...
          auth:
              type: AUTH_TYPE
              scope: AUTH_SCOPE
              scopes: AUTH_SCOPE
              audience: AUDIENCE
          timeout: TIMEOUT_IN_SECONDS
      result: RESULT_VALUE
    

JSON

  [
    {
      "STEP_NAME": {
        "call": "HTTP_REQUEST",
        "args": {
          "url": "URL_VALUE",
          "method": "REQUEST_METHOD",
          "private_service_name": "REGISTERED_SERVICE",
          "headers": {"HEADER_KEY":"HEADER_VALUE",
          ...
          },
          "body": {"BODY_KEY":"BODY_VALUE",
          ...
          },
          "query": {"QUERY_KEY":"QUERY_VALUE",
          ...
          },
          "auth": {
            "type":"AUTH_TYPE",
            "scope":"AUTH_SCOPE",
            "scopes":"AUTH_SCOPE",
            "audience":"AUDIENCE"
          },
          "timeout": "TIMEOUT_IN_SECONDS"
        },
        "result": "RESULT_VALUE"
      }
    }
  ]
    

Replace the following:

  • HTTP_REQUEST: required. Use one of the following for HTTP requests:
    • http.delete
    • http.get
    • http.patch
    • http.post
    • http.put
    • http.request
  • URL_VALUE: required. URL where the request is sent.
  • REQUEST_METHOD: required if using call type http.request. The type of HTTP request method to use. For example:
    • GET
    • POST
    • PATCH
    • DELETE
  • REGISTERED_SERVICE: optional. A registered Service Directory service name in the format projects/PROJECT_ID/locations/LOCATION/namespaces/NAMESPACE_NAME/services/SERVICE_NAME. For more information, see Invoke a VPC Service Controls-compliant private endpoint.
  • HEADER_KEY:HEADER_VALUE: optional. Header fields to supply input to the API.

    If using a Content-Type header to specify the media type of the request body, only the following types are supported:

    • application/json or application/type+json—must be a map
    • application/x-www-form-urlencoded—must be an unencoded string
    • text/type—must be a string

    If a Content-Type header is specified, the body is encoded as prescribed. For example, it might be JSON or URL-encoded.

    If using a User-Agent header to identify the requesting user agent, the following applies:

    • The default is GoogleCloudWorkflows; (+https://cloud.google.com/workflows/docs)
    • If a value is specified, GoogleCloudWorkflows; (+https://cloud.google.com/workflows/docs) is appended to that value

      For example, if User-Agent: "MY_USER_AGENT_VALUE" is specified, the HTTP request header would be as follows (with a space between the specified value and the appended default):

      MY_USER_AGENT_VALUE GoogleCloudWorkflows; (+https://cloud.google.com/workflows/docs)
  • BODY_KEY:BODY_VALUE: optional. Body fields to supply input to the API.

    If a Content-Type header is not specified, and if a request body is present, the following applies:

    • If the body value is bytes, the header is set to Content-Type: application/octet-stream.
    • Otherwise, the body is JSON-encoded and the header is set to Content-Type: application/json; charset=utf-8.
    The following example is of a body structure equivalent to a JSON payload:

    YAML

    body:
      requests:
      - image:
          source:
            gcsImageUri: ${gsUri}
        features:
        - type: LABEL_DETECTION
        - type: SAFE_SEARCH_DETECTION
        - type: IMAGE_PROPERTIES
    result: imageAnalysisResponse

    JSON

    {
      "requests":[
        {
          "image": {
            "source": {
                "gcsUri": "img.png"
            }
          },
          "features": [
            { "type":"LABEL_DETECTION" },
            { "type":"SAFE_SEARCH_DETECTION" },
            { "type":"IMAGE_PROPERTIES" },
          ]
        }
      ]
    }
  • QUERY_KEY:QUERY_VALUE: optional. Query fields to supply input to the API.
  • AUTH_TYPE: optional. Required if the API being called requires authentication. Use either OIDC or OAuth2. For more information, see Make authenticated requests from a workflow.
    • AUTH_SCOPE: optional. Limits an application's access to a user's account. Use either the scope or scopes key.

      The scope key supports either a string or list of strings. For example:

      "https://www.googleapis.com/auth/cloud-platform"

      or

      ["https://www.googleapis.com/auth/cloud-platform", "scope2", "scope3"]

      The scopes key, in addition to supporting a string or list of strings, supports space and comma-separated strings. For example:

      "https://www.googleapis.com/auth/cloud-platform scope2 scope3"

      or

      "https://www.googleapis.com/auth/cloud-platform,scope2,scope3"

      For more information, see OAuth 2.0 Scopes for Google APIs.

    • AUDIENCE: optional. Specifies the audience for the OIDC token. By default, it's set to the same value as url; however, it should be set to your service's root URL. For example: https://region-project.cloudfunctions.net/hello_world.
  • TIMEOUT_IN_SECONDS: optional. How long in seconds a request is allowed to run before throwing an exception. The maximum is 1800 seconds.
  • RESULT_VALUE: optional. Variable name where the result of an HTTP invocation step is stored.

Access HTTP response data saved in a variable

If the Content-Type header for the response specifies an application/json media type, the JSON response that is stored in a variable is automatically converted to a map that can be accessed.

If necessary, modify the API that is being called to specify an application/json media type for the Content-Type response header. Otherwise, you can use the json.decode and text.encode functions to convert the response body into a map. For example:

json.decode(text.encode(RESPONSE_FROM_API))

Workflows includes a built-in parser for accessing this data. To access the fields from the HTTP response, use the following syntax:

${VARIABLE_NAME.body|code|headers.PATH_TO_FIELD}

Replace the following:

  • VARIABLE_NAME: the name of the workflow variable where you saved a JSON response.
  • body: use the body field to access the body of the HTTP response.
  • code: use the code field to access the HTTP response code.
  • headers: use the headers field to access the HTTP response headers by name.
  • PATH_TO_FIELD: the path to the field in the JSON response that you want to access. May be simply the name of the field, or if the field is nested inside an object, it may take the form of object1.object2.field.

For example, if an API returns {"age":50} and a workflow stores that response in a variable called age_response, the following example returns the value of the age field; in this case, 50:

age_response.body.age

Samples

These samples demonstrate the syntax.

Assign the response from an API call

Unless you input your own search term, this sample uses your Google Cloud location to construct a search term, which it passes to the Wikipedia API. A list of related Wikipedia articles is returned.

YAML

main:
  params: [input]
  steps:
    - checkSearchTermInInput:
        switch:
          - condition: '${"searchTerm" in input}'
            assign:
              - searchTerm: '${input.searchTerm}'
            next: readWikipedia
    - getLocation:
        call: sys.get_env
        args:
          name: GOOGLE_CLOUD_LOCATION
        result: location
    - setFromCallResult:
        assign:
          - searchTerm: '${text.split(location, "-")[0]}'
    - readWikipedia:
        call: http.get
        args:
          url: 'https://en.wikipedia.org/w/api.php'
          query:
            action: opensearch
            search: '${searchTerm}'
        result: wikiResult
    - returnOutput:
        return: '${wikiResult.body[1]}'

JSON

{
  "main": {
    "params": [
      "input"
    ],
    "steps": [
      {
        "checkSearchTermInInput": {
          "switch": [
            {
              "condition": "${\"searchTerm\" in input}",
              "assign": [
                {
                  "searchTerm": "${input.searchTerm}"
                }
              ],
              "next": "readWikipedia"
            }
          ]
        }
      },
      {
        "getLocation": {
          "call": "sys.get_env",
          "args": {
            "name": "GOOGLE_CLOUD_LOCATION"
          },
          "result": "location"
        }
      },
      {
        "setFromCallResult": {
          "assign": [
            {
              "searchTerm": "${text.split(location, \"-\")[0]}"
            }
          ]
        }
      },
      {
        "readWikipedia": {
          "call": "http.get",
          "args": {
            "url": "https://en.wikipedia.org/w/api.php",
            "query": {
              "action": "opensearch",
              "search": "${searchTerm}"
            }
          },
          "result": "wikiResult"
        }
      },
      {
        "returnOutput": {
          "return": "${wikiResult.body[1]}"
        }
      }
    ]
  }
}

Make an external HTTP POST request

This sample makes a POST request to an external HTTP endpoint.

YAML

- send_message:
    call: http.post
    args:
      url: https://www.example.com/endpoint
      body:
        some_val: "Hello World"
        another_val: 123
    result: the_message
- return_value:
    return: ${the_message.body}

JSON

[
  {
    "send_message": {
      "call": "http.post",
      "args": {
        "url": "https://www.example.com/endpoint",
        "body": {
          "some_val": "Hello World",
          "another_val": 123
        }
      },
      "result": "the_message"
    }
  },
  {
    "return_value": {
      "return": "${the_message.body}"
    }
  }
]

Make an external HTTP GET request with headers

This sample makes an HTTP GET request with a custom header. You can also supply custom header definitions when making other types of HTTP requests.

YAML

- get_message:
    call: http.get
    args:
      url: https://www.example.com/endpoint
      headers:
        Content-Type: "text/plain"
      query:
        some_val: "Hello World"
        another_val: 123
    result: the_message
- return_value:
    return: ${the_message.body}

JSON

[
  {
    "get_message": {
      "call": "http.get",
      "args": {
        "url": "https://www.example.com/endpoint",
        "headers": {
          "Content-Type": "text/plain"
        },
        "query": {
          "some_val": "Hello World",
          "another_val": 123
        }
      },
      "result": "the_message"
    }
  },
  {
    "return_value": {
      "return": "${the_message.body}"
    }
  }
]

Use OIDC to authenticate when making a request to Cloud Run functions

This sample makes an HTTP request using OIDC by adding an auth section to the args section of the workflow's definition, after specifying the URL.

YAML

- call_my_function:
    call: http.post
    args:
      url: https://us-central1-myproject123.cloudfunctions.net/myfunc1
      auth:
        type: OIDC
      body:
        some_val: "Hello World"
        another_val: 123
    result: the_message
- return_value:
    return: ${the_message.body}

JSON

[
  {
    "call_my_function": {
      "call": "http.post",
      "args": {
        "url": "https://us-central1-myproject123.cloudfunctions.net/myfunc1",
        "auth": {
          "type": "OIDC"
        },
        "body": {
          "some_val": "Hello World",
          "another_val": 123
        }
      },
      "result": "the_message"
    }
  },
  {
    "return_value": {
      "return": "${the_message.body}"
    }
  }
]

Catch and handle HTTP request errors

This sample implements a custom exception handler based on the HTTP status code returned by the GET request. The workflow catches a potential exception and returns a predefined error message. If an exception is not recognized, the workflow execution fails and throws the exception as returned by the GET request. For other error tags, see Workflow errors.

YAML

# Use a custom exception handler to catch exceptions and return predefined
# error messages; if the exception isn't recognized, the workflow
# execution fails and throws the exception returned by the GET request
- read_item:
    try:
      call: http.get
      args:
        url: https://example.com/someapi
        auth:
          type: OIDC
      result: API_response
    except:
      as: e
      steps:
        - known_errors:
            switch:
              - condition: ${not("HttpError" in e.tags)}
                next: connection_problem
              - condition: ${e.code == 404}
                next: url_not_found
              - condition: ${e.code == 403}
                next: auth_problem
        - unhandled_exception:
            raise: ${e}
- url_found:
    return: ${API_response.body}
- connection_problem:
    return: "Connection problem; check URL"
- url_not_found:
    return: "Sorry, URL wasn't found"
- auth_problem:
    return: "Authentication error"

JSON

[
  {
    "read_item": {
      "try": {
        "call": "http.get",
        "args": {
          "url": "https://example.com/someapi",
          "auth": {
            "type": "OIDC"
          }
        },
        "result": "API_response"
      },
      "except": {
        "as": "e",
        "steps": [
          {
            "known_errors": {
              "switch": [
                {
                  "condition": "${not(\"HttpError\" in e.tags)}",
                  "next": "connection_problem"
                },
                {
                  "condition": "${e.code == 404}",
                  "next": "url_not_found"
                },
                {
                  "condition": "${e.code == 403}",
                  "next": "auth_problem"
                }
              ]
            }
          },
          {
            "unhandled_exception": {
              "raise": "${e}"
            }
          }
        ]
      }
    }
  },
  {
    "url_found": {
      "return": "${API_response.body}"
    }
  },
  {
    "connection_problem": {
      "return": "Connection problem; check URL"
    }
  },
  {
    "url_not_found": {
      "return": "Sorry, URL wasn't found"
    }
  },
  {
    "auth_problem": {
      "return": "Authentication error"
    }
  }
]

What's next