GSP363

Overview
In a challenge lab you’re given a scenario and a set of tasks. Instead of following step-by-step instructions, you will use the skills learned from the labs in the course to figure out how to complete the tasks on your own! An automated scoring system (shown on this page) will provide feedback on whether you have completed your tasks correctly.
When you take a challenge lab, you will not be taught new Google Cloud concepts. You are expected to extend your learned skills, like changing default values and reading and researching error messages to fix your own mistakes.
To score 100% you must successfully complete all tasks within the time period!
This lab is recommended for students who have completed the labs in the Develop and Secure APIs with Apigee X course. Are you ready for the challenge?
Setup
Before you click the Start Lab button
Read these instructions. Labs are timed and you cannot pause them. The timer, which starts when you click Start Lab, shows how long Google Cloud resources are made available to you.
This hands-on lab lets you do the lab activities in a real cloud environment, not in a simulation or demo environment. It does so by giving you new, temporary credentials you use to sign in and access Google Cloud for the duration of the lab.
To complete this lab, you need:
- Access to a standard internet browser (Chrome browser recommended).
Note: Use an Incognito (recommended) or private browser window to run this lab. This prevents conflicts between your personal account and the student account, which may cause extra charges incurred to your personal account.
- Time to complete the lab—remember, once you start, you cannot pause a lab.
Note: Use only the student account for this lab. If you use a different Google Cloud account, you may incur charges to that account.
Challenge scenario
You are a Cloud Engineer for Cymbal Shops, a national retailer. Cymbal Shop is focused on global sales, and translation services have been identified as a key tool to help expand the global business. You are responsible for creating the first version of a translation API.
You are expected to have the skills and knowledge for these tasks, so step-by-step guides are not provided.
Your challenge
You will create a new Apigee API proxy and other resources in the project's Apigee organization. Read through each task description, and create the required functionality.
Save errors
When you save changes to your API proxy, you might encounter a Could not save new revision
error. If you use the Save dropdown button (
), and then select Save as new revision, you should see an error message that tells you what is invalid.
Task 1. Proxy the Cloud Translation API
Cymbal Shops has decided to use Google Cloud's Translation API as the backend service for the API proxy.
Requirements:
- In the Google Cloud Console, confirm that the Cloud Translation API is enabled in the API Library.
- Create a service account for the API proxy named
apigee-proxy
, and grant it the role Logging > Logs Writer.
- In the Google Cloud Console,from the Navigation menu, select Apigee to open the Apigee UI and create your API proxy.
- The API proxy should be a reverse proxy named translate-v1, with a base path of /translate/v1.
- The API proxy's target is the HTTP URL for the basic version of the Cloud Translation API (
https://translation.googleapis.com/language/translate/v2
).
- Do not add authorization, CORS, or a quota using the Common Policies page of the proxy wizard.
- On the summary page, create the API proxy by leaving the settings at their defaults.
- Add an Authentication section to the default TargetEndpoint, causing an access token to be sent with every backend request. Use a GoogleAccessToken element with a Scope of
https://www.googleapis.com/auth/cloud-translation
.
Note:
Edit the proxy and in the Develop tab, under Target endpoints section, edit the default.xml file.
- Use the following Cloud Shell script to confirm that the Apigee runtime is completely installed:
export INSTANCE_NAME=eval-instance; export ENV_NAME=eval; export PREV_INSTANCE_STATE=; echo "waiting for runtime instance ${INSTANCE_NAME} to be active"; while : ; do export INSTANCE_STATE=$(curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" -X GET "https://apigee.googleapis.com/v1/organizations/${GOOGLE_CLOUD_PROJECT}/instances/${INSTANCE_NAME}" | jq "select(.state != null) | .state" --raw-output); [[ "${INSTANCE_STATE}" == "${PREV_INSTANCE_STATE}" ]] || (echo; echo "INSTANCE_STATE=${INSTANCE_STATE}"); export PREV_INSTANCE_STATE=${INSTANCE_STATE}; [[ "${INSTANCE_STATE}" != "ACTIVE" ]] || break; echo -n "."; sleep 5; done; echo; echo "instance created, waiting for environment ${ENV_NAME} to be attached to instance"; while : ; do export ATTACHMENT_DONE=$(curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" -X GET "https://apigee.googleapis.com/v1/organizations/${GOOGLE_CLOUD_PROJECT}/instances/${INSTANCE_NAME}/attachments" | jq "select(.attachments != null) | .attachments[] | select(.environment == \"${ENV_NAME}\") | .environment" --join-output); [[ "${ATTACHMENT_DONE}" != "${ENV_NAME}" ]] || break; echo -n "."; sleep 5; done; echo "***ORG IS READY TO USE***";
When the script returns ORG IS READY TO USE
, you can proceed to next steps.
Note:
If you are waiting for the runtime to install, you may read ahead and plan your development for Task 2.
- Save and deploy the translate-v1 proxy to the eval environment using the following service account:
apigee-proxy@{{{ project_0.project_id | PROJECT }}}.iam.gserviceaccount.com
- Test the API proxy.
The eval environment in the Apigee organization can be called using the hostname eval.example.com. This DNS entry is only available in the internal network, so you must use a VM that has been created for you.
- In Cloud Shell, open an SSH connection to apigeex-test-vm:
TEST_VM_ZONE=$(gcloud compute instances list --filter="name=('apigeex-test-vm')" --format "value(zone)")
gcloud compute ssh apigeex-test-vm --zone=${TEST_VM_ZONE} --force-key-file-overwrite
-
If asked to authorize, click Authorize. For each question asked in the gcloud command, click Enter or Return to specify the default input.
-
Once you have successfully completed Task 1, the following curl command should translate the text:
curl -i -k -X POST "https://eval.example.com/translate/v1" -H "Content-Type: application/json" -d '{ "q": "Translate this text!", "target": "es" }'
The response should look similar to this:
{
"data": {
"translations": [
{
"translatedText": "¡Traduce este texto!",
"detectedSourceLanguage": "en"
}
]
}
}
Note:
For a few minutes, you may receive a 502 error response until your API proxy is fully deployed.
Click Check my progress to verify the objective.
Proxy the Cloud Translation API
Note:
If a green check mark isn't displayed, click the score fly-out on the upper-right, and then click Check my progress on the relevant step. A pop-up box will give you advice.
Task 2. Change the API request and response
Cymbal Shops wants to create an API that is different from the interface provided by the Translation API. There are two Translation API calls that should be modified.
The first call retrieves a list of valid languages.
Cloud Translation API request:
REQUEST:
POST https://translation.googleapis.com/language/translate/v2/languages
Authorization: Bearer ACCESSTOKEN
Content-Type: application/json
{
"target": "en"
}
Cloud Translation API response:
Content-Type: application/json
{
"data": {
"languages": [
{
"language": "af",
"name": "Afrikaans"
},
{
"language": "sq",
"name": "Albanian"
},
...
]
}
}
translate-v1 request:
GET https://eval.example.com/translate/v1/languages
translate-v1 response:
Content-Type: application/json
[{"language":"af","name":"Afrikaans"},{"language":"sq","name":"Albanian"}, ... ]
The API proxy must replace the GET with a POST, remove the data and languages response fields, and get the target language code from a property set. The access token was added automatically by the Authentication section in Task 1.
The second call translates text to a specified language.
Cloud Translate API request:
POST https://translation.googleapis.com/language/translate/v2
Authorization: Bearer ACCESSTOKEN
Content-Type: application/json
{
"q": "Hello world!",
"target": "de"
}
Cloud Translate API response:
Content-Type: application/json
{
"data": {
"translations": [
{
"translatedText": "Hallo Welt!",
"detectedSourceLanguage": "en"
}
]
}
}
translate-v1 request:
POST https://eval.example.com/translate/v1?lang=de
Content-Type: application/json
{
"text": "Hello world!"
}
translate-v1 response:
Content-Type: application/json
{
"translated": "Hallo Welt!"
}
The API proxy must take the target language from the lang query parameter, and change the field names for the incoming and translated text. The lang query parameter may optionally be omitted from the translate-v1 request, in which case the target language will be taken from a property in the property set.
Note:
The Translation API accepts either a single string or an array of strings for the 'q' field. Your API should only support a single string.
Requirements:
-
Within the API proxy, create a property set named language.properties. The property set should have two properties: output with a value of es
, and caller with a value of en
. The caller property will be used to specify the target language when listing languages (the language used for the name field). output will specify the default target language to be used if the lang query parameter is not provided.
-
In the proxy endpoint, create a path and verb conditional flow for the POST /
resource. Name it translate
.
-
In the proxy endpoint, create a path (no verb) conditional flow for the /languages
resource. Name it getLanguages
. (Do not include a verb. You will be modifying the request's verb from GET
(for the input to the proxy) to POST
(required by the backend). If you include a verb in the condition, response policies in the flow would not execute because request.verb
is no longer equal to GET
.)
-
Create an AssignMessage policy named AM-BuildTranslateRequest
to create the backend request used in the translate conditional flow.
The policy should include:
-
An AssignVariable with a template to create variables which will be used later in a logged message. The variable named text
should use the jsonPath message template function to extract the text
field from the request.
-
The variable named language
should be created by using the firstnonnull message template function. This variable should contain the lang query parameter value if it exists, and the language property set's output property for the target language if the lang query parameter has not been specified.
-
A Set section should be used to set the JSON payload required by the backend service. Both variables you have created will be used in the payload.
-
The [AssignTo] element should use the existing request message.
The AssignVariable sections in the AssignMessage policy should look similar to this:
<AssignVariable>
<Name>...</Name>
<Template>...</Template>
<AssignVariable>
- Create an AssignMessage policy named
AM-BuildTranslateResponse
under translate conditional flow to create the response for the caller using the Translation API response.
The policy should include:
-
An AssignVariable with a jsonPath template to create a variable named translated
, extracting the translatedText field from the Translation API response. Hint: the JSONPath expression to extract this field is $.data.translations[0].translatedText
.
-
Set createNew to true.
-
The new JSON payload will use the translated variable.
The AssignVariable sections in the AssignMessage policy should look similar to this:
<AssignVariable>
<Name>...</Name>
<Template>...</Template>
<AssignVariable>
- Create an AssignMessage policy named
AM-BuildLanguagesRequest
to create the backend request used in the getLanguages conditional flow.
The policy should include:
-
Use Set to set the correct verb and payload for the backend request.
-
The caller property in the language property set should be used for the target field in the backend payload.
-
Set createNew to true.
-
Set the backend request payload to have a content type of application/json.
The AssignVariable sections in the AssignMessage policy should look similar to this:
<AssignVariable>
<Name>...</Name>
<Set>
...
</Set>
</AssignVariable>
- Create a JavaScript policy named
JS-BuildLanguagesResponse
under getLanguages conditional flow to create the response for the caller. The JavaScript code should use these steps:
Your JavaScript code should look similar to this:
var payload = ...;
var payloadObj = JSON.parse(...);
var newPayload = JSON.stringify(...);
context.setVariable(...);
Note:
Make sure to create the desired policies under their correct conditional flows and edit the desired policy configurations in respective .xml files.
- Test the API. From the apigeex-test-vm virtual machine, use the following curl commands to test the examples shown above:
Click Check my progress to verify the objective.
Change the API request and response
Note:
If a green check mark isn't displayed, click the score fly-out on the upper-right, and then click Check my progress on the relevant step. A pop-up box will give you advice.
Task 3. Add API key verification and quota enforcement
Access to this API should be limited to approved applications, so you will add a VerifyAPI key policy, as well as a Quota policy to limit the number of requests.
Requirements:
-
Create an API product with a name and display name of translate-product
. This API product should have public access, automatically approve access requests, and be available in the eval environment.
-
Add an operation to the translate-product
API product. The operation should allow access to the translate-v1 proxy and use a path of /
, which allows access to any request, including /. Allowed methods are GET and POST. Add an operation quota setting of 10 requests per 1 minute.
-
Create a developer with the email joe@example.com
. Choose your own first name, last name, and username.
-
Create an app called translate-app
, and enable the translate-product
API product for it. You will need to associate it with your joe@example.com
developer.
-
Add a VerifyAPIKey policy named VA-VerifyKey
to the proxy endpoint preflow. The API key should be required for every request, and should be sent in using the Key header.
-
Add a Quota policy named Q-EnforceQuota
to the proxy endpoint preflow.
The policy should include the steps:
- Use a type of
calendar
. The calendar type requires a StartTime
element.
- Specify
UseQuotaConfigInAPIProduct
to use the quota from the API product, with a default quota of 5 requests every one hour if the API product does not specify quota settings.
- Set Distributed and Synchronous to true, and remove the AsynchronousConfiguration element.
Once these changes have been made, the request should return an error if a valid API key is not specified in the Key header.
- From the apigeex-test-vm virtual machine, use the following curl commands to test the API key functionality:
Click Check my progress to verify the objective.
Add API key verification and quota enforcement
Note:
If a green check mark isn't displayed, click the score fly-out on the upper-right, and then click Check my progress on the relevant step. A pop-up box will give you advice.
Task 4. Add message logging
To understand how the translation service is being used, a MessageLogging policy will log each translated message.
Requirements:
- Add a MessageLogging policy named
ML-LogTranslation
to the translate
conditional flow. The policy must execute after the AM-BuildTranslateResponse
step.
Note:
Don't add it to the PostClientFlow because logs are only created for the translation operation.
- The policy should log to Cloud Logging. Use this policy documentation.
-
The LogName
value should be:
projects/{organization.name}/logs/translate
-
The logged message should have a contentType of text/plain
, and the message contents should be:
{language}|{text}|{translated}
This message requires the language, text, and translated variables that were created in the AM-BuildTranslateRequest
and AM-BuildTranslateResponse
policies.
-
Validate the logged messages in the Logging page of the Google Cloud Console. Use the query logName : "translate"
to see only the translated logs.
-
Once the MessageLogging policy has been successfully added, use the following curl command:
curl -i -k -X POST "https://eval.example.com/translate/v1?lang=de" -H "Content-Type:application/json" -H "Key: $KEY" -d '{ "text": "Hello world!" }'
Note:
There is a short delay before a logged message appears in the logs.
Click Check my progress to verify the objective.
Add message logging
Note:
If a green check mark isn't displayed, click the score fly-out on the upper-right, and then click Check my progress on the relevant step. A pop-up box will give you advice.
Task 5. Rewrite a backend error message
When the target parameter sent to the Translation API is invalid, a 400 Bad Request error message is returned:
{
"error": {
"code": 400,
"message": "Invalid Value",
"errors": [
{
"message": "Invalid Value",
"domain": "global",
"reason": "invalid"
}
]
}
}
This error message would be confusing to the caller, so you will rewrite the error message.
Requirements:
- Add a FaultRules section to the default target endpoint. When the backend returns a 400 response, it will automatically evaluate any matching fault rules in the target endpoint.
Note:
The UI Navigator menu on the left cannot be used to add a FaultRules section. You must add it in the target endpoint's XML configuration.
-
Add a FaultRule to the FaultRules section. The Condition of this FaultRule should be set so that it executes if fault.name
is ErrorResponseCode
.
-
Create an AssignMessage policy named AM-BuildErrorResponse
and attach it to the FaultRule. Use the following policy configuration:
<AssignMessage name="AM-BuildErrorResponse">
<Set>
<Payload contentType="application/json">{ "error": "Invalid request. Verify the lang query parameter." }</Payload>
</Set>
</AssignMessage>
Once the policy is attached, your FaultRules section in the target endpoint should look similar to this:
<FaultRules>
<FaultRule name="...">
<Step>
<Name>...</Name>
</Step>
<Condition>...</Condition>
</FaultRule>
</FaultRules>
Note:
You need to manually edit the Target Endpoint XML (make sure it is the TargetEndpoint, not the ProxyEndpoint).
- Test the API.
Click Check my progress to verify the objective.
Rewrite a backend error message
Note:
If a green check mark isn't displayed, click the score fly-out on the upper-right, and then click Check my progress on the relevant step. A pop-up box will give you advice.
Congratulations!
Over the course of this challenge lab you have demonstrated your knowledge of Apigee X API development and security.

Earn your next skill badge
This self-paced lab is part of the Develop and Secure APIs with Apigee X quest. Completing this skill badge quest earns you the badge above, to recognize your achievement. Share your badge on your resume and social platforms, and announce your accomplishment using #GoogleCloudBadge.
This skill badge quest is part of Google Cloud’s API Developer learning path. Continue your learning journey by enrolling in the Deploy and Manage Apigee X quest.
Google Cloud training and certification
...helps you make the most of Google Cloud technologies. Our classes include technical skills and best practices to help you get up to speed quickly and continue your learning journey. We offer fundamental to advanced level training, with on-demand, live, and virtual options to suit your busy schedule. Certifications help you validate and prove your skill and expertise in Google Cloud technologies.
Manual Last Updated July 10, 2024
Lab Last Tested July 10, 2024
Copyright 2025 Google LLC. All rights reserved. Google and the Google logo are trademarks of Google LLC. All other company and product names may be trademarks of the respective companies with which they are associated.