Using Google Cloud Run to create mock targets for Apigee

Introduction

In this article, we present a no-code based solution to create a mock endpoint based on an OpenAPI spec (specification) and that can be used by an Apigee API proxy as a target endpoint during development phases.

Requirements

Considering a valid Open API spec (based on version v2 or v3.x), our requirements are:

  • Deploy a mock service on Google Cloud Platform (GCP), based on an OpenAPI spec
  • Deploy an API proxy on Apigee with target endpoint configured with the mock service deployed on GCP
  • Allow only authenticated access to the mock service: this means that the API proxy on Apigee has to generate and use a valid token (via Google authentication) when communicating with the mock service endpoint

In this article we use an API proxy example based on Apigee X/hybrid but the mocking solution does not depend on the Apigee runtime option that is used.

For Apigee Edge customers willing to implement the solution described in this article, it is important to consider authenticating Apigee via  Service Account Keys, as described in option-2 of the Apigee community article: “Hosted Targets vs. Google Cloud Run”.

The mock service on GCP will be deployed on Google Cloud Run

Here is an Apigee devrel reference implementation for how to front a Cloud Run service with Apigee X.

Solution Overview 

This section presents the proposed solution.

joel_gauci_0-1638551152702.png

The proposed solution consists in deploying the following components, in order:

  1. A Cloud Run service, based on a stoplight/prism Docker image using an OpenAPI spec in order to create a mock API, which can generate dynamic random examples based on the API description
  2. A service account for Apigee to call Cloud Run securely using Google authentication
  3. An API proxy on Apigee. The proxy’s target endpoint is the target URL exposed by the Cloud Run service. 

Prism is an open-source HTTP mock server that can mimic your API’s behavior as if you already built it. Mock HTTP servers are generated from your OpenAPI v2/v3 (formerly known as Swagger) documents.

The main advantage of using prism is that you do not have to write any code to implement the mock APIs on Cloud Run.

Solution Deployment

In this section, we describe the different steps to deploy the solution.

In our example, we use the petstore OpenAPI Specification that is publicly available, but you can choose another document of your convenience.

We also consider that the following tools are set on the local machine used for the deployment:

  • gcloud
  • jq
  • docker
  • sackmesser 
  • xmllint

The Apigee Sackmesser tool lets you deploy API proxies, shared flows and configuration to Apigee Edge as well as Apigee hybrid/X, without writing any additional manifest files.

Environment Variables

In the coming sections, we use the following environment variables:

  • GCP_PROJECT: your current GCP project identifier
  • GCP_REGION: your current GCP region
  • OPEN_API_SPEC_MOCK: the relative path of the OpenAPI spec you want to use
  • APIGEE_X_ORG, APIGEE_X_ENV, APIGEE_X_HOSTNAME: name of your Apigee X/hybrid organization, environment and the hostname used to reach deployed APIs

Dockerfile

In the current directory, we create a specs sub directory in which we download the petstore.yaml file, using the following command:

mkdir ./specs
curl -L0 https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.yaml > ./specs/petstore.yaml 

export OPEN_API_SPEC_MOCK=./specs/petstore.yaml

Let’s go on with the creation of the Dockerfile, based on the stoplight/prism (version 4) image:

cat > Dockerfile <<EOF
FROM stoplight/prism:4
ADD $OPEN_API_SPEC_MOCK /usr/src/prism/openapi.yaml
EXPOSE 4010
CMD ["mock","-d","-h","'0.0.0.0'","/usr/src/prism/openapi.yaml"]
EOF

docker build -t gcr.io/"$GCP_PROJECT"/apigee-mock-target:latest .
docker push gcr.io/"$GCP_PROJECT"/apigee-mock-target:latest

We use the prism mock command to start a server, which exposes the petstore API.

The -d option is used to generate dynamic random examples based on the API description, so the examples are always valid.

Once created, the Docker image is built and pushed to a container registry in your current GCP project. For a detail of the different possible options available with stoplight/prism, please refer to the online Stoplight Prism doc

Cloud Run Service

We can now deploy a Cloud Run service using the following command:

gcloud run deploy apigee-mock-target \
--image=gcr.io/"$GCP_PROJECT"/apigee-mock-target \
--platform=managed \
--port 4010 \
--region="$GCP_REGION" \
--no-allow-unauthenticated

TARGET_URL=$(gcloud run services describe apigee-mock-target --platform managed --region "$GCP_REGION" --format json | jq -r '.status.url')

We define the TARGET_URL variable that contains the value of the Cloud Run service’s target URL, once this service has been deployed. We use this variable to configure the target endpoint of the Apigee API proxy.

Service Account

The Apigee API proxy (that is created later) needs a service account with the role “roles/run.invoker” as access to the Cloud Run service is authenticated.

gcloud iam service-accounts create oas-mock-target-sa \
--project "$GCP_PROJECT" || true

gcloud run services add-iam-policy-binding apigee-mock-target \
--region "$GCP_REGION" \
--member serviceAccount:oas-mock-target-sa@"$GCP_PROJECT".iam.gserviceaccount.com \
--role roles/run.invoker \
--platform managed

Apigee API proxy

We use a simple pass-through API proxy. The only configuration aspect that requires your attention is the target endpoint. 

Here is an example of the target endpoint configuration that you can use in order to use Google authentication to connect with the Cloud Run service that has been created before:

<TargetEndpoint name="default">
  <HTTPTargetConnection>
    <URL>@TargetURL@</URL>
    <Authentication>
      <GoogleIDToken>
          <Audience>@TargetURL@</Audience>
      </GoogleIDToken>
  </Authentication>
  </HTTPTargetConnection>
</TargetEndpoint>

You must now replace the @TargetURL@ tag with the value of the TARGET_URL variable, as shown with the following sed command:

sed -i.bak "s|@TargetURL@|$TARGET_URL|" ./api-proxy-v1/apiproxy/targets/default.xml

rm ./api-proxy-v1/apiproxy/targets/default.xml.bak

We consider here that the target endpoint configuration is contained in the default.xml file, that is part of the /api-proxy-v1/apiproxy/targets/ directory.

Here is an overview of the api-proxy-v1 directory structure:

api-proxy-v1/
└── apiproxy
    ├── apigee-v1.xml
    ├── policies
    │   └── SpikeArrest.xml
    ├── proxies
    │   └── default.xml
    └── targets
        └── default.xml

4 directories, 4 files

The only policy we have defined is a SpikeArrest policy to protect the mock service. This policy is not mandatory if you want to start with a (very) simple API proxy.

Now we can deploy the API proxy using the sackmesser command. In our example, the configuration of the API proxy that is deployed is defined in the api-proxy-v1 directory:

sackmesser deploy --googleapi \
-o "$APIGEE_X_ORG" \
-e "$APIGEE_X_ENV" \
-t "$APIGEE_TOKEN" \
-h "$APIGEE_X_HOSTNAME" \
-d "./api-proxy-v1" \
--deployment-sa oas-mock-target-sa@"$GCP_PROJECT".iam.gserviceaccount.com

The APIGEE_TOKEN environment variable is generated using the  following gcloud command:

APIGEE_TOKEN=$(gcloud auth print-access-token)

The service account that is configured at the API proxy level and that is used to generate a valid access token to connect with the Cloud Run service is defined with the --deployment-sa option.

Testing the Solution

Once deployed, the solution can be tested using any HTTP client (here we are using curl):

curl https://"$APIGEE_X_HOSTNAME"/api/v1/pets | jq

The response is an array, including at least one pet in the form of:

{
    "id": 5712447680535704000,
    "name": "velit",
    "tag": "ullamco minim"
}

The id, name and tag are dynamically generated by the stoplight/prism mocker.

The debug traces on Apigee (X or hybrid) provide the following information, like the mock service’s response:

joel_gauci_0-1638552199134.png

Metrics related to the Cloud Run mock service can be retrieved from the GCP console:

joel_gauci_1-1638552199133.png

Clean Up Process

In order to clean up what has been previously deployed, you can use the following commands:

rm -r ./api-proxy-v1

rm Dockerfile

# delete the API proxy proxy from Apigee X or hybrid
APIGEE_TOKEN=$(gcloud auth print-access-token);
sackmesser clean --googleapi -t "$APIGEE_TOKEN" proxy <API-PROXY-NAME>

# Cleanup  GCP Assets
gcloud run services delete apigee-mock-target \
--region "$GCP_REGION" -q

gcloud iam service-accounts delete oas-mock-target-sa@"$GCP_PROJECT".iam.gserviceaccount.com \
--project "$GCP_PROJECT" -q

Thanks to Omid Tahouri and Daniel Strebel for their feedback on drafts of this article!

Contributors
Version history
Last update:
‎12-03-2021 10:57 PM
Updated by: