|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "metadata": {}, |
| 6 | + "source": [ |
| 7 | + "### 🛠️ 1. Initialize notebook variables\n", |
| 8 | + "\n", |
| 9 | + "Configures everything that's needed for deployment. \n", |
| 10 | + "\n", |
| 11 | + "**Modify entries under _1) User-defined parameters_ and _3) Define the APIs and their operations and policies_**." |
| 12 | + ] |
| 13 | + }, |
| 14 | + { |
| 15 | + "cell_type": "code", |
| 16 | + "execution_count": null, |
| 17 | + "metadata": {}, |
| 18 | + "outputs": [], |
| 19 | + "source": [ |
| 20 | + "import utils\n", |
| 21 | + "from apimtypes import *\n", |
| 22 | + "\n", |
| 23 | + "# 1) User-defined parameters (change these as needed)\n", |
| 24 | + "rg_location = 'eastus2'\n", |
| 25 | + "index = 1\n", |
| 26 | + "deployment = INFRASTRUCTURE.SIMPLE_APIM\n", |
| 27 | + "tags = ['azure-maps'] # ENTER DESCRIPTIVE TAG(S)\n", |
| 28 | + "api_prefix = 'am-' # OPTIONAL: ENTER A PREFIX FOR THE APIS TO REDUCE COLLISION POTENTIAL WITH OTHER SAMPLES\n", |
| 29 | + "azure_maps_url = 'https://atlas.microsoft.com' # OPTIONAL: ENTER THE AZURE MAPS URL IF DIFFERENT FROM DEFAULT\n", |
| 30 | + "\n", |
| 31 | + "# 2) Service-defined parameters (please do not change these)\n", |
| 32 | + "rg_name = utils.get_infra_rg_name(deployment, index)\n", |
| 33 | + "sample_folder = \"azure-maps\"\n", |
| 34 | + "nb_helper = utils.NotebookHelper(sample_folder, rg_name, rg_location, deployment, [INFRASTRUCTURE.AFD_APIM_PE, INFRASTRUCTURE.APIM_ACA, INFRASTRUCTURE.SIMPLE_APIM])\n", |
| 35 | + "\n", |
| 36 | + "# 3) Define the APIs and their operations and policies\n", |
| 37 | + "\n", |
| 38 | + "# Policies\n", |
| 39 | + "# Named values must be set up a bit differently as they need to have two surrounding curly braces\n", |
| 40 | + "map_async_geocode_batch_v1_keyauth_post_xml = utils.read_policy_xml('map_async_geocode_batch_v1_keyauth_post.xml', sample_name=sample_folder)\n", |
| 41 | + "map_default_route_v2_aad_get_xml = utils.read_policy_xml('map_default_route_v2_aad_get.xml', sample_name=sample_folder)\n", |
| 42 | + "map_geocode_v2_aad_get_xml = utils.read_policy_xml('map_geocode_v2_aad_get.xml', sample_name=sample_folder)\n", |
| 43 | + "\n", |
| 44 | + "# Map API \n", |
| 45 | + "mapApi_v2_default_get = GET_APIOperation2('get-default-route','Get default route','/default/*','This is the default route that will allow all requests to go through to the backend api',map_default_route_v2_aad_get_xml)\n", |
| 46 | + "mapApi_v1_async_post = APIOperation('async-geocode-batch','Async Geocode Batch','/geocode/batch/async',HTTP_VERB.POST, 'Post geocode batch async endpoint',map_async_geocode_batch_v1_keyauth_post_xml)\n", |
| 47 | + "mapApi_v2_geocode_get = GET_APIOperation2('get-geocode','Get Geocode','/geocode','Get geocode endpoint',map_geocode_v2_aad_get_xml)\n", |
| 48 | + "api1 = API('map-api', 'Map API', '/map', 'This is the proxy for Azure Maps', operations=[mapApi_v2_default_get, mapApi_v1_async_post,mapApi_v2_geocode_get], tags = tags, serviceUrl=azure_maps_url)\n", |
| 49 | + "\n", |
| 50 | + "# APIs Array\n", |
| 51 | + "apis: List[API] = [api1]\n", |
| 52 | + "\n", |
| 53 | + "# 4) Set up the named values, for this specific sample, we are using some of the named values in the API policies defined above that can't be known at this point in the process. For those named values, we are setting them in the main.bicep file.\n", |
| 54 | + "nvs: List[NamedValue] = [\n", |
| 55 | + " NamedValue('azure-maps-arm-api-version','2023-06-01')\n", |
| 56 | + "]\n", |
| 57 | + "\n", |
| 58 | + "utils.print_ok('Notebook initialized')" |
| 59 | + ] |
| 60 | + }, |
| 61 | + { |
| 62 | + "cell_type": "markdown", |
| 63 | + "metadata": {}, |
| 64 | + "source": [ |
| 65 | + "### 🚀 2. Create deployment using Bicep\n", |
| 66 | + "\n", |
| 67 | + "Creates the bicep deployment into the previously-specified resource group. A bicep parameters file will be created prior to execution." |
| 68 | + ] |
| 69 | + }, |
| 70 | + { |
| 71 | + "cell_type": "code", |
| 72 | + "execution_count": null, |
| 73 | + "metadata": {}, |
| 74 | + "outputs": [], |
| 75 | + "source": [ |
| 76 | + "import utils\n", |
| 77 | + "\n", |
| 78 | + "# 1) Define the Bicep parameters with serialized APIs\n", |
| 79 | + "bicep_parameters = {\n", |
| 80 | + " 'apis': {'value': [api.to_dict() for api in apis]},\n", |
| 81 | + " 'namedValues': {'value': [nv.to_dict() for nv in nvs]}\n", |
| 82 | + "}\n", |
| 83 | + "\n", |
| 84 | + "# 2) Deploy the bicep template\n", |
| 85 | + "output = nb_helper.deploy_bicep(bicep_parameters)\n", |
| 86 | + "\n", |
| 87 | + "if output.json_data:\n", |
| 88 | + " apim_name = output.get('apimServiceName', 'APIM Service Name')\n", |
| 89 | + " apim_gateway_url = output.get('apimResourceGatewayURL', 'APIM API Gateway URL')\n", |
| 90 | + "\n", |
| 91 | + "utils.print_ok('Deployment completed')" |
| 92 | + ] |
| 93 | + }, |
| 94 | + { |
| 95 | + "cell_type": "markdown", |
| 96 | + "metadata": {}, |
| 97 | + "source": [ |
| 98 | + "### ✅ 3. Verify API Request Success\n", |
| 99 | + "\n", |
| 100 | + "Assert that the deployment was successful by making simple calls to APIM. \n", |
| 101 | + "\n", |
| 102 | + "❗️ If the infrastructure shields APIM and requires a different ingress (e.g. Azure Front Door), the request to the APIM gateway URl will fail by design. Obtain the Front Door endpoint hostname and try that instead." |
| 103 | + ] |
| 104 | + }, |
| 105 | + { |
| 106 | + "cell_type": "code", |
| 107 | + "execution_count": null, |
| 108 | + "metadata": {}, |
| 109 | + "outputs": [], |
| 110 | + "source": [ |
| 111 | + "import utils\n", |
| 112 | + "from apimtesting import ApimTesting\n", |
| 113 | + "from apimrequests import ApimRequests\n", |
| 114 | + "import json\n", |
| 115 | + "\n", |
| 116 | + "tests = ApimTesting(\"Azure Maps Sample Tests\", sample_folder, deployment)\n", |
| 117 | + "\n", |
| 118 | + "# Preflight: Check if the infrastructure architecture deployment uses Azure Front Door. If so, assume that APIM is not directly accessible and use the Front Door URL instead.\n", |
| 119 | + "endpoint_url = utils.test_url_preflight_check(deployment, rg_name, apim_gateway_url)\n", |
| 120 | + "\n", |
| 121 | + "reqs = ApimRequests(endpoint_url)\n", |
| 122 | + "\n", |
| 123 | + "# 1) Issue a direct request to API Management\n", |
| 124 | + "output = reqs.singleGet('/', msg = 'Calling Hello World (Root) API. Expect 200.')\n", |
| 125 | + "tests.verify(output, 'Hello World from API Management!')\n", |
| 126 | + "\n", |
| 127 | + "# 2) Issue requests to API Management with Azure Maps APIs\n", |
| 128 | + "output = reqs.singleGet('/map/default/geocode?query=15127%20NE%2024th%20Street%20Redmond%20WA', msg = 'Calling Default Route API with SAS Token Auth. Expect 200.')\n", |
| 129 | + "tests.verify('address' in output, True)\n", |
| 130 | + "\n", |
| 131 | + "output = reqs.singleGet('/map/geocode?query=15127%20NE%2024th%20Street%20Redmond%20WA', msg = 'Calling Geocode v2 API with AAD Auth. Expect 200.')\n", |
| 132 | + "tests.verify('address' in output, True)\n", |
| 133 | + "\n", |
| 134 | + "output = reqs.singlePostAsync('/map/geocode/batch/async', data={\n", |
| 135 | + " \"batchItems\": [\n", |
| 136 | + " {\"query\": \"?query=400 Broad St, Seattle, WA 98109&limit=3\"},\n", |
| 137 | + " {\"query\": \"?query=One, Microsoft Way, Redmond, WA 98052&limit=3\"},\n", |
| 138 | + " {\"query\": \"?query=350 5th Ave, New York, NY 10118&limit=1\"},\n", |
| 139 | + " {\"query\": \"?query=Pike Pl, Seattle, WA 98101&lat=47.610970&lon=-122.342469&radius=1000\"},\n", |
| 140 | + " {\"query\": \"?query=Champ de Mars, 5 Avenue Anatole France, 75007 Paris, France&limit=1\"}\n", |
| 141 | + " ]\n", |
| 142 | + "}, msg = 'Calling Async Geocode Batch v1 API with Share Key Auth. Expect initial 202, then a 200 on the polling response', timeout=120, poll_interval=3)\n", |
| 143 | + "\n", |
| 144 | + "# confirm the response contains \"summary\": { \"successfulRequests\": 5, \"totalRequests\": 5}\n", |
| 145 | + "tests.verify('summary' in output and 'successfulRequests' in output and json.loads(output)['summary']['successfulRequests'] == 5, True)\n", |
| 146 | + "\n", |
| 147 | + "tests.print_summary()\n", |
| 148 | + "\n", |
| 149 | + "utils.print_ok('All done!')" |
| 150 | + ] |
| 151 | + } |
| 152 | + ], |
| 153 | + "metadata": { |
| 154 | + "kernelspec": { |
| 155 | + "display_name": "APIM Samples Python 3.12", |
| 156 | + "language": "python", |
| 157 | + "name": "apim-samples" |
| 158 | + }, |
| 159 | + "language_info": { |
| 160 | + "codemirror_mode": { |
| 161 | + "name": "ipython", |
| 162 | + "version": 3 |
| 163 | + }, |
| 164 | + "file_extension": ".py", |
| 165 | + "mimetype": "text/x-python", |
| 166 | + "name": "python", |
| 167 | + "nbconvert_exporter": "python", |
| 168 | + "pygments_lexer": "ipython3", |
| 169 | + "version": "3.12.10" |
| 170 | + } |
| 171 | + }, |
| 172 | + "nbformat": 4, |
| 173 | + "nbformat_minor": 2 |
| 174 | +} |
0 commit comments