* feat: Update prerequisites and APIM creation

* feat: Update screenshots and styles

* feat: Update API creation

* feat: Start updating policies

* feat: Finalize policies

* feat: Update monitoring

* feat: Add monitoring with Event Hub

* feat: Update event hub part and fix url link

* feat: Start updating security section

* feat: Update all auth flow for Auth2

* feat: Update devops

* feat: Update security / Key Vault section

* feat: Update additional topics

* feat: Remove unused images

* feat: Update missing title

* feat: Update PR feedbacks

* feat: Update typo

* feat: Update naming

* feat: Update missing typo

---------

Co-authored-by: Damien Aicheh <damienaicheh@microsoft.com>
This commit is contained in:
Damien Aicheh 2023-04-13 16:10:25 +02:00 коммит произвёл GitHub
Родитель a92387d1cd
Коммит fbdf8c2d3c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
222 изменённых файлов: 579 добавлений и 476 удалений

16
.vscode/tasks.json поставляемый
Просмотреть файл

@ -16,7 +16,17 @@
{
"label": "build and run local",
"type": "shell",
"command": "bundle install && bundle exec jekyll build ",
"command": "bundle install && bundle exec jekyll build",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": false
}
},
{
"label": "run locally and watch",
"type": "shell",
"command": "bundle exec jekyll serve",
"problemMatcher": [],
"group": {
"kind": "build",
@ -24,6 +34,4 @@
}
}
]
}
}

Просмотреть файл

@ -1,23 +0,0 @@
---
title: Prerequisites
has_children: false
nav_order: 1
---
## Check that you have everything ready to do the workshop
Please check that you have the following requirements to complete the hands-on lab:
- Azure requirements
- Access to the [Azure Portal](https://www.portal.azure.com)
- Access to an active [Azure subscription](https://portal.azure.com/#blade/Microsoft_Azure_Billing/SubscriptionsBlade)
- Contributor role in a resource group to be able to deploy an API Management instance
- During part 3 of this lab, we will add existing APIs to our API Management instance. The following APIs/websites should be available:
- [Colors API](https://colors-api.azurewebsites.net/swagger/v1/swagger.json), in case this website is down you can deploy your own API using the following [instructions](../10-additionalTopics/apimanagement-10-2-containerinstance.md)
- [Colors website](https://colors-web.azurewebsites.net), in case this website is down you can deploy your own website using the following [instructions](../10-additionalTopics/apimanagement-10-2-containerinstance.md)
- [Star Wars API](https://swapi.dev/)
- [Calculator API](http://calcapi.cloudapp.net/calcapi.json)
- For part 8 you need to have access to a valid [Azure DevOps](https://dev.azure.com) organization.
**An API Management instance can take some time to provision.** Please follow the steps outlined in APIM Creation prior to the workshop.

Просмотреть файл

@ -0,0 +1,9 @@
---
title: Prerequisites
has_children: true
nav_order: 1
---
## Prerequisites
Check that you have everything ready to do this workshop, and read the naming conventions.

Просмотреть файл

@ -0,0 +1,20 @@
---
title: Technical requirements
parent: Prerequisites
has_children: false
nav_order: 1
---
## Technical requirements
- Azure requirements
- Access to the [Azure Portal](https://www.portal.azure.com)
- Access to an active [Azure subscription](https://portal.azure.com/#blade/Microsoft_Azure_Billing/SubscriptionsBlade)
- **Contributor** role in a resource group to be able to deploy an API Management instance
- During this lab, we will add existing APIs to our API Management instance. The following APIs/websites should be available:
- [Colors API](https://colors-api.azurewebsites.net/swagger/v1/swagger.json), in case this website is down you can deploy your own API using the following [instructions](../10-additional-topics/additional-topics-10-2-container-instance.md)
- [Colors website](https://colors-web.azurewebsites.net), in case this website is down you can deploy your own website using the following [instructions](../10-additional-topics/additional-topics-10-2-container-instance.md)
- [Star Wars API](https://swapi.dev/)
- [Calculator API](http://calcapi.cloudapp.net/calcapi.json)
- For the DevOps part, you need to have access to a valid [Azure DevOps](https://dev.azure.com) organization.

Просмотреть файл

@ -0,0 +1,39 @@
---
title: Naming conventions
parent: Prerequisites
has_children: false
nav_order: 2
---
## Naming conventions
Before starting to deploy any Azure services, it's important to follow a naming convention. Based on the official [documentation][az-naming-convention] we need to define a few things:
- The application name
- The environment
- The region
- The instance number
We will also add an owner property, so for the purpose of this lab the values will be:
- The application name: `hol` (for Hands On Lab)
- The environment: `dev`
- The region: `we`
- The instance: `01`
- The owner: `ms`
So we will use this convention:
```xml
<!--If the resource prefix has a dash: -->
<service-prefix>-<environment>-<region>-<application-name>-<owner>-<instance>
<!--If the resource does not allow any special caracters: -->
<service-prefix><environment><region><application-name><owner><instance>
```
For instance, for a resouce group you will name it `rg-dev-we-hol-ms-01` and for a storage account you will have: `stdevweholms01`.
> Be sure to use your own value to have unique names or use your own convention based on the [official resource abbreviations][az-abrevation]
[az-naming-convention]: https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming
[az-abrevation]: https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations

Просмотреть файл

@ -0,0 +1,10 @@
---
title: APIM instantiation
parent: Prerequisites
has_children: false
nav_order: 3
---
## APIM creation
>> **An API Management instance can take some time to provision.** Please follow the steps outlined in the APIM Creation prior to the workshop.

Просмотреть файл

@ -0,0 +1,33 @@
---
title: Instantiation
parent: Azure Apim Creation
has_children: false
nav_order: 1
---
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.ApiManagement)
Using the naming convention defined [previously](../0-prerequisites/prerequisite-0-2-naming.md), fill in each required field and press *Review + Create*, followed by *Create* to provision the service.
> Please bear in mind that this APIM instance is entirely intended for the purposes of the lab, and the approach is simplified to provide every lab participant a common starting point. To that end, **please do not modify any settings beyond the ones we ask** for here as it may result in having to recreate the APIM instance later, which is costly with respect to time.
Please note that the **service name must be unique**, this is where the owner value of your naming convention will be useful.
The naming conventions here are:
- Resource group: `rg-<environment>-<region>-<application-name>-<owner>-<instance>`
- APIM: `apim-<environment>-<region>-<application-name>-<owner>-<instance>`.
> Take note of APIM service name as you will need it for forming URLs in this lab.
Please use the **Developer** tier, which provides [all relevant features at the lowest cost](https://azure.microsoft.com/en-us/pricing/details/api-management/#pricing).
![APIM deploy blade](../../assets/images/apim-deploy-blade.png)
Please do not modify other settings. Specifically, the *Virtual network* tab should remain as **None**. We will allude to best practices for securing access to APIM later on in this workshop.
![APIM deploy blade Virtual Network tab](../../assets/images/apim-deploy-blade-vnet.png)
Once started, it is not necessary to remain on this page or in the Azure Portal. If you entered a valid email address, you will receive a provisioning completion email:
![APIM creation email](../../assets/images/apim-creation-email.png)

Просмотреть файл

@ -0,0 +1,46 @@
---
title: Verification
parent: Azure Apim Creation
has_children: false
nav_order: 2
---
## Verifying the API Management instance
Once the APIM instance has been created, please verify that it functions correctly by following these steps:
1) Navigate to the newly-created APIM instance in the Azure Portal.
2) Select the **APIs** blade, then select the *Echo API*.
3) Press the **Test** tab, then select the **GET Retrieve resource** operation.
4) Press **Send** to issue a simple request.
![APIM Echo API Test Send](../../assets/images/apim-echo-api-test-1.png)
5) Observe the `200` Success response.
![APIM Echo API Test Success](../../assets/images/apim-echo-api-test-2.png)
At this time you have successfully verified that APIM is set up!
### Verification Failure (and Path to Success)
You may have noticed the *Request URL* and may be tempted to put it in your browser, issue a CURL statement, etc. If you do, you may see a `401` error and wonder what's happening.
![APIM Echo API Test 401](../../assets/images/apim-echo-api-test-3.png)
The reason for this the unauthorized access status code is that the *Echo API* requires a subscription key to be set. Whereas tests originating in APIM account for this automatically, external callers cannot (and, naturally, should not).
Back in APIM, switch to the **Settings** tab and uncheck **Subscription required** and press **Save** at the bottom of the page.
> Subscriptions are important and useful, but in this case, we just want to quickly verify the APIM instance is working as intended.
![APIM Echo API Disable Required Subscription](../../assets/images/apim-echo-api-test-4.png)
Accessing the link in your browser should now show you no error message. In fact, in order to verify the 200, it's easiest to open your Developer Tools (F12), navigate to the **Network** tab, and look at **All** requests to see the 200.
![APIM Echo API Browser Success](../../assets/images/apim-echo-api-test-5.png)
Alternatively, you can issue a verbose (`-v`) CURL command against the **Echo API** and observe the `200` Success:
`curl -v https://<your apim instance>.azure-api.net/echo/resource?param1=sample`
![APIM Echo API Curl Success](../../assets/images/apim-echo-api-test-6.png)

Просмотреть файл

@ -0,0 +1,10 @@
---
title: Azure Apim Creation
has_children: true
nav_order: 1
---
## Create an API Management instance
Due to the substantial infrastructure, an API Management instance can take some time to provision. Expect ~45-75 minutes. Therefore, **please create an instance in advance.**

Просмотреть файл

@ -1,69 +0,0 @@
---
title: Azure Apim Creation
has_children: false
nav_order: 2
---
## Create an API Management instance
Due to the substantial infrastructure, an API Management instance can take some time to provision. Expect ~45-75 minutes. Therefore, **please create an instance prior to any demo.**
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.ApiManagement)
Using either your own or [Azure's common naming convention](https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming), fill in each required field and press *Review + Create*, followed by *Create* to provision the service.
> Please bear in mind that this APIM instance is entirely intended for the purposes of the lab, and the approach is simplified to provide every lab participant a common starting point. To that end, please do not modify any settings beyond the ones we ask for here as it may result in having to recreate the APIM instance later, which is costly with respect to time.
Once started, it is not necessary to remain on this page or in the Azure Portal. If you entered a valid email address, you will receive a provisioning completion email.
Please note that the **service name must be unique**. We recommend to include your initials and numeric date.
> Take note of APIM service name as you will need it for forming URLs in this lab.
Please use the **Developer** tier, which provides [all relevant features at the lowest cost](https://azure.microsoft.com/en-us/pricing/details/api-management/#pricing).
![APIM deploy blade](../../assets/images/apim-deploy-blade.png)
Please do not modify other settings. Specifically, the *Virtual network* tab should remain as **None**. We will allude to best practices for securing access to APIM later on in this workshop.
![APIM deploy blade Virtual Network tab](../../assets/images/apim-deploy-blade-vnet.png)
## Verifying the API Management instance
Once the APIM instance has been created, please verify that it functions correctly by following these steps:
1) Navigate to the newly-created APIM instance in the Azure Portal.
2) Select the *APIs* blade, then select the *Echo API*.
3) Press the *Test* tab, then select the *GET Retrieve resource* operation.
4) Press *Send* to issue a simple request.
![APIM Echo API Test Send](../../assets/images/apim-echo-api-test-1.png)
5) Observe the `200` Success response.
![APIM Echo API Test Success](../../assets/images/apim-echo-api-test-2.png)
At this time you have successfully verified that APIM is set up!
### Verification Failure (and Path to Success)
You may have noticed the *Request URL* and may be tempted to put it in your browser, issue a CURL statement, etc. If you do, you may see a `401` error and wonder what's happening.
![APIM Echo API Test 401](../../assets/images/apim-echo-api-test-3.png)
The reason for this the unauthorized access status code is that the *Echo API* requires a subscription key to be set. Whereas tests originating in APIM account for this automatically, external callers cannot (and, naturally, should not).
Back in APIM, switch to the *Settings* tab and uncheck *Subscription required* and press *Save* at the bottom of the page.
> Subscriptions are important and useful, but in this case, we just want to quickly verify the APIM instance is working as intended.
![APIM Echo API Disable Required Subscription](../../assets/images/apim-echo-api-test-4.png)
Accessing the link in your browser should now show you no error message. In fact, in order to verify the 200, it's easiest to open your Developer Tools (F12), navigate to the *Network* tab, and look at *All* requests to see the 200.
![APIM Echo API Browser Success](../../assets/images/apim-echo-api-test-5.png)
Alternatively, you can issue a verbose (`-v`) CURL command against the *Echo API* and observe the `200` Success: `curl -v https://<your apim instance>.azure-api.net/echo/resource?param1=sample`
![APIM Echo API Curl Success](../../assets/images/apim-echo-api-test-6.png)

Просмотреть файл

@ -6,16 +6,16 @@ nav_order: 1
---
## Additional Topics - Architecture Design Session
## Architecture Design Session
In this section we provide you with a template architecture diagram for your apim baseline architecture. We recommend you take the time and answer the following questions:
In this section we provide you with a template architecture diagram for your APIM baseline architecture. We recommend you take the time and answer the following questions:
- What type of apis are you onboarding to Azure Apim?
- What deployment model works for you(no vnet, internal, external)?
- What tier of apim is the right for you?
- What security will you add to your apis?
- What type of APIs are you onboarding to Azure APIM?
- What deployment model works for you (no vnet, internal, external)?
- What tier of APIM is the right for you?
- What security will you add to your APIs?
- What products are we going to define?
- What teams and processess need to be in place to manage the Azure Apim?
- What teams and processes need to be in place to manage the Azure APIM?
![](../../assets/images/apim-architecture-design-session-v2.png)
| <a href="https://app.diagrams.net/#Uhttps%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fapim-lab%2Fmain%2Fassets%2Fdiagrams%2FapimADSv2.drawio" target="_blank">Edit As New</a>

Просмотреть файл

@ -6,31 +6,33 @@ nav_order: 2
---
## Additional Topics - Provision your own instance of ColoursWeb/ColoursAPI
## Provision your own instance of ColoursWeb/ColoursAPI
Some of the demos use the ColourWeb web application and the ColourAPI API application. In this lab we will show you how to deploy your own instances of the Colours Web and Colours API. Note - ColoursWeb / ColoursAPI is new version of ColorsWeb/ColorsAPI ... do not mix the web client and API versions.
Some of the demos use the ColoursWeb web application and the ColoursAPI API application. In this lab we will show you how to deploy your own instances of the Colours Web and Colours API. Note - ColoursWeb / ColoursAPI is new version of ColorsWeb/ColorsAPI ... do not mix the web client and API versions.
The code for the ColourWeb / ColourAPI applications is available here:
The code for the ColoursWeb / ColoursAPI applications is available here:
- [ColourWeb](https://github.com/markharrison/ColoursWeb)
- [ColourApi](https://github.com/markharrison/ColoursAPI)
- [ColoursWeb](https://github.com/markharrison/ColoursWeb)
- [ColoursAPI](https://github.com/markharrison/ColoursAPI)
Docker Containers exist for these applications and so provides an easy deployment option ( IMPORTANT : due to the new pull restrictions on Docker Hub images, in this lab we will be using the GitHub registry):
Docker Containers exist for these applications and so provides an easy deployment option.
> IMPORTANT : due to the new pull restrictions on Docker Hub images, in this lab we will be using the GitHub registry
- Github (Colours)
- docker pull ghcr.io/markharrison/coloursapi:latest
- docker pull ghcr.io/markharrison/coloursweb:latest
- `docker pull ghcr.io/markharrison/coloursapi:latest`
- `docker pull ghcr.io/markharrison/coloursweb:latest`
- DockerHub (Colors)
- docker pull markharrison/colorweb:latest
- docker pull markharrison/colorapi:latest
- `docker pull markharrison/colorweb:latest`
- `docker pull markharrison/colorapi:latest`
With the container we can deploy to multiple hosting options : VM's, App Services, ACI and also AKS. In this lab we are going to show you how to do it with [Azure Container Instances](https://docs.microsoft.com/en-us/azure/container-instances/).
# Deploying Web and API containers with Azure Container Instances
1. Login to Azure Portal at http://portal.azure.com.
2. Open the Azure Cloud Shell and choose Bash Shell (do not choose Powershell)
1. Login to [Azure Portal](https://portal.azure.com)
2. Open the **Azure Cloud Shell** and choose **Bash Shell** (do not choose Powershell)
![Azure Cloud Shell](../../assets/images/azure-cloud-shell.png "Azure Cloud Shell")

Просмотреть файл

@ -5,7 +5,7 @@ has_children: false
nav_order: 3
---
## Additional Topics - API Proxy to Serverless
## API Proxy to Serverless
Azure Serverless (Functions and Logic Apps) can be configured to benefit from the advantages of API Management.

Просмотреть файл

@ -5,7 +5,7 @@ has_children: false
nav_order: 4
---
## Additional Topics - Self-hosted Gateway
## Self-hosted Gateway
With the API Management self-hosted gateway, organisations have the ability to deploy an instance of the APIM gateway component to the environments where they host their applications and/or APIs - for example, in an on-premise data center.

Просмотреть файл

@ -3,3 +3,5 @@ title: Additional Topics
has_children: true
nav_order: 11
---
## Additional Topics

Просмотреть файл

@ -13,7 +13,11 @@ If you'd like to contribute to this workshop, please read the following guidelin
- [Minor update or fix to an existing challenge and adding a new challenge](3-minor-update-fix.md)
- [Run the github page locally with Github Codespaces](4-github-codespaces.md)
# Keep things consistent
- Follow the naming convention for each component
- Hide specific subscription name or personal information
- Keep the screenshots and images updated and generic
# Contributing

Просмотреть файл

@ -2,4 +2,6 @@
title: Contributing
has_children: true
nav_order: 12
---
---
## Contributing

Просмотреть файл

@ -10,13 +10,13 @@ nav_order: 1
The APIM Developer Portal uses role-based access control (RBAC). After creating the APIM instance, you need to first **access the Developer Portal using the admin role**, which will trigger its activation.
- Click the *Developer portal* link in the *Overview* blade of the APIM instance:
- Click the **Developer portal** link in the **Overview** blade of the APIM instance:
![APIM Developer Portal](../../assets/images/apim-developer-portal.png)
![APIM Developer Portal Admin Launch](../../assets/images/apim-developer-portal-admin-launch.png)
- You can now proceed with publishing the Developer Portal to allow anonymous and authenticated roles. Back in the Azure Portal, locate _Developer Portal_ in the left-hand resource menu, then click on *Portal overview*. Press the *Publish* button and confirm with *Yes* in the popup. The portal will then be available for users to access.
- You can now proceed with publishing the Developer Portal to allow anonymous and authenticated roles. Back in the Azure Portal, locate **Developer Portal** in the left-hand resource menu, then click on **Portal overview**. Press the **Publish** button and confirm with **Yes** in the popup. The portal will then be available for users to access.
![APIM Developer Portal Publish](../../assets/images/apim-developer-portal-publish.png)
@ -30,7 +30,7 @@ The APIM Developer Portal uses role-based access control (RBAC). After creating
Cross-origin resource sharing (CORS) is a mechanism that allows resources on a web page to be requested from another domain, outside the domain from which the first resource was served. CORS is required to let portal visitors use the interactive console in the API reference pages and should be enabled for domains, including custom domains.
- CORS is enabled by using policies. We will go deeper on this topic in part 4. For now we will enable this using a built-in UI by pressing the *Enable CORS* button.
- CORS is enabled by using policies. We will go deeper on this topic in part 4. For now we will enable this using a built-in UI by pressing the **Enable CORS** button.
![APIM Developer Portal Enable CORS](../../assets/images/apim-developer-portal-CORS.png)
@ -62,7 +62,7 @@ Let's experience how your users will navigate through your portal. In order to d
### Register for an account
- Let's sign up for an account by pressing the *Sign up* link in the upper right-hand corner. The email can be your personal or a work email for this lab, but please be sure to use an email other than the one associated with your Azure subscription.
- Let's sign up for an account by pressing the **Sign up** link in the upper right-hand corner. The email can be your personal or a work email for this lab, but please be sure to use an email other than the one associated with your Azure subscription.
![APIM Developer Portal Sign-up](../../assets/images/apim-developer-portal-signup.png)
@ -76,27 +76,27 @@ Let's experience how your users will navigate through your portal. In order to d
![APIM Developer Portal Sign-in](../../assets/images/apim-developer-portal-sign-in.png)
- Click on *Products*, then *Starter*.
- Enter `Starter` as the subscription name, then press *Subscribe*. You should receive a confirmation email shortly.
- Click on **Products**, then **Starter**.
- Enter `Starter` as the subscription name, then press **Subscribe**. You should receive a confirmation email shortly.
![APIM Developer Portal Product Subscribe](../../assets/images/apim-developer-portal-product-subscribe.png)
- Next, click back on *Products*, then *Unlimited*.
- Enter `Unlimited` as the subscription name, then press *Subscribe*.
- Next, click back on **Products**, then **Unlimited**.
- Enter `Unlimited` as the subscription name, then press **Subscribe**.
> Note that the `Unlimited` subscription requires admin approval.
- You should receive an email confirming your subscription request.
### Approving Subscriptions
- Back in the Azure Portal, navigate to the *Subscriptions* blade to see the two new subscriptions that were just added.
- Back in the Azure Portal, navigate to the **Subscriptions** blade to see the two new subscriptions that were just added.
![APIM Subscriptions](../../assets/images/apim-subscriptions.png)
- Enter the menu for the submitted *Unlimited* subscription, then press *Activate subscription*. - Provide additional comments, if you like, then confirm the activation. By default, this will send an activation confirmation email to the user.
- Enter the menu for the submitted **Unlimited** subscription, then press **Activate subscription**. - Provide additional comments, if you like, then confirm the activation. By default, this will send an activation confirmation email to the user.
![APIM Activate Subscription](../../assets/images/apim-activate-subscription.png)
- Back in the private browser, refresh the profile page to see the activated *Unlimited* subscription.
- Back in the private browser, refresh the profile page to see the activated **Unlimited** subscription.
![APIM Subscription Activated](../../assets/images/apim-subscriptions-activated.png)
@ -104,9 +104,9 @@ Let's experience how your users will navigate through your portal. In order to d
It's now time to test one of the published APIs.
- Open the *APIs* page and look at the *Echo API*:
- Open the **APIs** page and look at the **Echo API**:
- Notice the developer information
- Test the Echo API using the POST verb by pressing *Try it*, using the defaults, then pressing *Send* at the bottom. You should see a successful `200` response.
- Test the Echo API using the POST verb by pressing **Try it**, using the defaults, then pressing **Send** at the bottom. You should see a successful `200` response.
![APIM Developer Portal Try API](../../assets/images/apim-developer-portal-try-api-1.png)

Просмотреть файл

@ -22,14 +22,14 @@ A product contains one or more APIs as well as a usage quota and the terms of us
![APIM Add Product](../../assets/images/apim-add-product-2.png)
- Next, we'll change the access control by clicking on *Gold Tier* and selecting *Access control* in the left pane.
- Next, we'll change the access control by clicking on **Gold Tier** and selecting **Access control** in the left pane.
![APIM Add Product Access](../../assets/images/apim-add-product-access-1.png)
Press *Add group*, check *Developers* and *Guests*, then press *Select*. The two added roles are shown now.
Press **Add group**, check **Developers** and **Guests**, then press **Select**. The two added roles are shown now.
![APIM Add Product Access](../../assets/images/apim-add-product-access-2.png)
Back in the private browsing session, browse to *Products* and observe the new *Gold Tier*.
Back in the private browsing session, browse to **Products** and observe the new **Gold Tier**.
![APIM Developer Portal Added Product](../../assets/images/apim-developer-portal-added-product.png)

Просмотреть файл

@ -16,14 +16,14 @@ nav_order: 1
Instead of developing an API, for this lab you will use the existing [*Star Wars* API](https://swapi.dev):
1) Click on *Add API*.
2) Click on *HTTP - Manually define an HTTP API*.
3) Select the *Full* option in the *Create an HTTP API* dialog.
4) Enter *Display name* `Star Wars`, *Name* `star-wars`, and, optionally, *Description*.
5) Assign `https://swapi.dev/api` to the *Web service URL*.
6) Keep the *URL scheme* at `HTTPS` as we strive to enforce HTTPS only.
7) Set the *API URL suffix* to `sw`. This allows us to compartmentalize the APIM URLs for distinct APIs.
8) Assign *Starter* and *Unlimited* products.
1) Click on **Add API**.
2) Click on **HTTP - Manually define an HTTP API**.
3) Select the **Full** option in the **Create an HTTP API** dialog.
4) Enter **Display name** `Star Wars`, **Name** `star-wars`, and, optionally, **Description**.
5) Assign `https://swapi.dev/api` to the **Web service URL**.
6) Keep the **URL scheme** at `HTTPS` as we strive to enforce HTTPS only.
7) Set the **API URL suffix** to `sw`. This allows us to compartmentalize the APIM URLs for distinct APIs.
8) Assign **Starter** and **Unlimited** products.
9) Press **Create**.
> While it is conventionally a good idea to version APIs from the onset, we are omitting this step here for brevity of the labs.
@ -32,14 +32,14 @@ Instead of developing an API, for this lab you will use the existing [*Star Wars
- Once created, inside the *Star Wars* API press **+ Add operation** to declare two new operations:
1) **GetPeople**
- Display name: **GetPeople**
- Name: **getpeople**
1) **Get People**
- Display name: **Get People**
- Name will be populate with: **get-people**
- URL: **GET /people/**
2) **GetPeopleById**
- Display name: **GetPeopleById**
- Name: **getpeoplebyid**
2) **Get People By Id**
- Display name: **Get People By Id**
- Name will be populate with: **get-people-by-id**
- URL: **GET /people/{id}/**
![APIM Star Wars API Add Operation](../../assets/images/apim-star-wars-api-add-operation.png)
@ -47,15 +47,15 @@ Instead of developing an API, for this lab you will use the existing [*Star Wars
### Access Star Wars API from Developer Portal
- Switch now to the Developer Portal and sign in as a developer with a subscription.
- Select *Explore APIs*. You should see both *Echo API* and *Star Wars*.
- Select **Explore APIs**. You should see both **Echo API** and **Star Wars**.
![APIM Developer Portal Echo & Star Wars APIs](../../assets/images/apim-developer-portal-apis-echo-star-wars.png)
- Click on *Star Wars*. Try the *GetPeople* operation. Observe a successful `200` response.
- Click on **Star Wars**. Try the **Get People** operation. Observe a successful `200` response.
![APIM Developer Portal Star Wars Try It](../../assets/images/apim-developer-portal-star-wars-try-it-1.png)
- Now try the *GetPeopleById* operation with `id = 2`
- Now try the **Get People By Id** operation with `id = 2`
![APIM Developer Portal Star Wars Try It](../../assets/images/apim-developer-portal-star-wars-try-it-2.png)

Просмотреть файл

@ -16,26 +16,29 @@ As a demo we will use an API that offers a simple calculator service : [Calc API
![APIM Calculator API](../../assets/images/apim-calc-api.png)
1) On the left menu, open the *APIs* blade.
2) Click on *Add API*.
3) Under *Create from definition* select *OpenAPI*.
4) Select the *Full* option in the *Create from OpenAPI specification* dialog.
5) Enter `http://calcapi.cloudapp.net/calcapi.json` as the *OpenAPI specification* value. You should subsequently see *Display name*, *Name*, and *Description* populate.
> **Note the intentional use of `http` instead of `https` as this backend does not presently support `https`.**
1) On the left menu, open the **APIs** blade.
2) Click on **Add API**.
3) Under **Create from definition** select **OpenAPI**.
4) Select the **Full** option in the **Create from OpenAPI specification** dialog.
5) Enter `http://calcapi.cloudapp.net/calcapi.json` as the **OpenAPI specification** value. You should subsequently see **Display name**, **Name**, and **Description** populate.
> **Note the intentional use of `http` instead of `https` as this backend does not presently support `https`.**
6) While the backend service only runs on `HTTP`, we need to **set URL scheme to `Both`** to allow for APIM ingress to occur on HTTPS for callers such as the Developer Portal.
7) Set the *API URL suffix* to `calc`.
8) Assign *Starter* and *Unlimited* products.
7) Set the **API URL suffix** to `calc`.
8) Assign **Starter** and **Unlimited** products.
9) Press **Create**.
![APIM Add Calculator API](../../assets/images/apim-add-calc-api-1.png)
- Once the API is created, it will show in the list of APIs along with all of its operations.
> Ensure that the backend shows as `HTTP`. If that is not the case, navigate to the *Settings* tab and update the *Web service URL* accordingly.
> Ensure that the backend shows as `HTTP`. If that is not the case, navigate to the **Settings** tab and update the **Web service URL** accordingly.
![APIM Add Calculator API](../../assets/images/apim-add-calc-api-2.png)
- Back in the Developer Portal, try out the Calculator API via the *Add two integers* GET method, then examine the response.
- Back in the Developer Portal, try out the Calculator API via the **Add two integers** GET method, then examine the response.
> Accepting the defaults of `49` and `51` suffices. There's presently an issue where defaults are shown in a dropdown. If you wanted to change the values, add new `a` and `b` parameters and values, then remove the dropdown values.
![APIM Developer Portal Calculator API Try It](../../assets/images/apim-developer-portal-calc-api-try-it-1.png)

Просмотреть файл

@ -19,16 +19,16 @@ Let's add another API, the [Colors API](https://colors-api.azurewebsites.net/swa
![APIM Add Colors API](../../assets/images/apim-add-color-api-2.png)
- We can test the newly-added API from the *Test* tab. Note the successful **200** response.
- We can test the newly-added API from the **Test** tab. Note the successful `200` response.
![APIM Test Colors API](../../assets/images/apim-test-color-api.png)
- Products can be configured after the API is initially created as well. On the *Settings* tab, set *Products* to include *Starter* and *Unlimited*, then press *Save*.
- Products can be configured after the API is initially created as well. On the **Settings** tab, set **Products** to include **Starter** and **Unlimited**, then press **Save**.
![APIM Colors API Add Products](../../assets/images/apim-color-api-add-products.png)
- Switch to the Developer portal and look at the *Colors* API.
- Try the *Get random color* operation.
- Switch to the Developer portal and look at the **Colors API**.
- Try the **Get random color** operation.
- Notice the successful `200` response and the returned random color.
![APIM Developer Portal Colors API Try It](../../assets/images/apim-developer-portal-color-api-try-it-1.png)
@ -47,46 +47,48 @@ First, we need to enable CORS for the domain name of the frontend. To achieve th
- On the sidemenu, click on `APIs`, then select the `All APIs` option.
- Inside the `Inbound processing` area you will see the `cors` policy, which we added in part 2 by pressing the `Enable Cors` button.
- Click on the pencil icon next to that policy to edit it.
- Click on the **pencil icon** next to that policy to edit it.
![APIM Policy CORS All APIs](../../assets/images/apim-policy-cors-all-apis-1.png)
- Here we will see this form where we can add the domain name of our frontend `https://colors-web.azurewebsites.net` or the `*` for all domains. Press *Add allowed origin*, enter the URL, then press *Save*.
- Here we will see this form where we can add the domain name of our frontend `https://colors-web.azurewebsites.net` or the `*` for all domains. Press **Add allowed origin**, enter the URL, then press **Save**.
![APIM Policy CORS All APIs](../../assets/images/apim-policy-cors-all-apis-2.png)
- After enabling CORS in APIM lets go back to our frontend <https://colors-web.azurewebsites.net> and follow these steps:
- After enabling CORS in APIM let's go back to our frontend <https://colors-web.azurewebsites.net> and follow these steps:
- Click on the hamburger menu next to *Colors* in the top left corner.
- Click on *Config*.
- Replace the *API URL* according to this format: <https://YOURAPIM.azure-api.net/colors/random> (e.g. https://apim-lab-pk.azure-api.net/colors/random).
- After setting the API URL correctly, press the hamburger menu again and go to *Home*.
- Press *Start* to see how the frontend is calling the api. You should see a *401* response, indicating an auth error. This happens as our API requires a subscription, but we have not yet entered a subscription key.
- Click on **Config**.
- Replace the **API URL** according to this format: https://YOUR_APIM.azure-api.net/colors/random (e.g. https://apim-dev-we-hol-ms-01.azure-api.net/colors/random).
- After setting the API URL correctly, press the hamburger menu again and go to **Home**.
- Press **Start** to see how the frontend is calling the api. You should see a **401** response, indicating an auth error. This happens as our API requires a subscription, but we have not yet entered a subscription key.
![Colors Website APIM 401](../../assets/images/color-website-apim-401.png)
- The subscription keys can be fetched from the Developer Portal. Open the main Developer Portal page, then click on *Profile* in the top menu.
- Copy the following URL into Notepad, modify your APIM instance, then copy the URL, so that you have two of the same URLs. We will use them for the *Starter* and *Unlimited* pathways into APIM.
- `https://YOURAPIM.azure-api.net/colors/random?key=`
- Append the primary keys for both subscriptions - one key per URL - to get unique URLs for *Starter* and *Unlimited*.
![Notepad Colors API Subscription Keys](../../assets/images/notepad-color-api-subscription-keys.png)
- The subscription keys can be fetched from the Developer Portal. Open the main Developer Portal page, then click on **Profile** in the top menu.
- To see that *Unlimited* product has no rate limits:
- Prepare the url in a text editor:
Concat the base url and the subscription key for the **Starter** and **Unlimited**, and update modify the url with your APIM instance:
```
https://YOUR_APIM.azure-api.net/colors/random?key=STARTER_PRIMARY_KEY_HERE
https://YOUR_APIM.azure-api.net/colors/random?key=UNLIMITED_PRIMARY__KEY_HERE
```
- To see that **Unlimited** product has no rate limits:
- Configure the Colors website to use the Unlimited URL.
- Select [Start].
- Select **Start**.
- Notice there is no rate limit - every light is randomly and continuously updated.
![Colors Website APIM Unlimited Product](../../assets/images/color-website-apim-unlimited-product.png)
- To see that *Starter* product is limited to 5 calls per minute:
- To see that **Starter** product is limited to 5 calls per minute:
- Configure the Colors website to use the Starter URL.
- Select [Start].
- Select **Start**.
- Notice that only 5 lights get colored.
![Colors Website APIM Starter Product](../../assets/images/color-website-apim-starter-product.png)
- Try the same *Starter* URL directly in your web browser:
- Notice the error status / message returned. For example: `{ "statusCode": 429, "message": "Rate limit is exceeded. Try again in 53 seconds." }`
- Try the same **Starter** URL directly in your web browser and notice the error status / message returned:
![APIM Colors API URL in Browser for Starter Product 429 ](../../assets/images/apim-color-api-url-in-browser-starter-product-429.png)

Просмотреть файл

Просмотреть файл

@ -7,7 +7,7 @@ nav_order: 5
## Policy Expressions
Policy Expressions are used to control traffic to and modify the behavior of the Backend API. At the time of this writing, [APIM policy expressions support C# 7](https://docs.microsoft.com/en-us/azure/api-management/api-management-policy-expressions). Please note that a specific subset of .NET Framework types, not the entire Framework, are made available. This is to cover the most frequently-needed types and operations without introducing bloat into APIM.
Policy Expressions are used to control traffic to and modify the behavior of the Backend API. At the time of this writing, [APIM Policy Expressions support C# 7](https://docs.microsoft.com/en-us/azure/api-management/api-management-policy-expressions). Please note that a specific subset of .NET Framework types, not the entire Framework, are made available. This is to cover the most frequently-needed types and operations without introducing bloat into APIM.
Using C# statements and an ability to access the API context, as well as your API Management service configuration, Policy Expressions are a powerful way to modify the behavior of the API at runtime.
@ -17,42 +17,42 @@ We had a brief look earlier at setting CORS policies. Lets dive in a bit deeper:
Policies can be applied at multiple scopes and follow this hierarchy. It is important to understand at what level to apply policy to appropriately yield security, robustness, and flexibility.
![APIM Policy Scopes](../../assets/images/apim-policy-scopes.png)
![APIM Policies Scopes](../../assets/images/apim-policy-scopes.png)
### APIM Portal Oddities
### APIM Portal oddities
> The APIM Portal is good, but it's not perfect.
There are two things to pay particular attention to:
- When switching away from the *Test* tab, all values and settings you made for the previous test will be reset. You will need to set every test up from scratch, unfortunately.
- When switching away from the **Test** tab, all values and settings you made for the previous test will be reset. You will need to set every test up from scratch, unfortunately.
- When switching to the *Design* tab to make API operation changes, note that *All operations* is always selected regardless of whether you were testing a specific operation prior. This can cause confusion when adding policies in our labs to specific operations as they can erroneously be added to *All operations*.
- When switching to the **Design** tab to make API operation changes, note that **All operations** is always selected regardless of whether you were testing a specific operation prior. This can cause confusion when adding policies in our labs to specific operations as they can erroneously be added to **All operations**.
### Getting Started - Frontend/Inbound/Outbound/Backend
Select an API (e.g. *Colors*). Policy can be configured for *Inbound processing*, *Backend*, and *Outbound processing*. Most commonly, policies are applied in the *Inbound processing* section. Select the pencil icon to visually edit any section or the `</>` code brackets to edit the underlying XML. The configuration can be scoped to the API (All operations) or to an individual operation.
Select an API (e.g. **Colors**). Policy can be configured for **Inbound processing**, **Backend**, and **Outbound processing**. Most commonly, policies are applied in the **Inbound processing** section. Select the pencil icon to visually edit any section or the `</>` code brackets to edit the underlying XML. The configuration can be scoped to the API (All operations) or to an individual operation.
The *Frontend* section allows for editing of the OpenAPI / Swagger definition.
The **Frontend** section allows for editing of the OpenAPI / Swagger definition.
![APIM Policy Editor](../../assets/images/apim-policy-editor.png)
Editing the Frontend:
- If editing an operation, there is a choice of the *Code View* or *Forms-based* editor.
- If editing an API, the only option is the *Code View* editor.
- The *Code View* editor allows amendments to the OpenAPI / Swagger definition.
- If editing an operation, there is a choice of the **Code View** or **Forms-based** editor.
- If editing an API, the only option is the **Code View** editor.
- The **Code View** editor allows amendments to the OpenAPI / Swagger definition.
![APIM Frontend Code Editor](../../assets/images/apim-frontend-code-editor.png)
![APIM Frontend Form Editor](../../assets/images/apim-frontend-form-editor.png)
Editing *Inbound processing / Outbound processing / Backend*:
Editing **Inbound processing / Outbound processing / Backend**:
- Using the *Code Editor*:
- Using the **Code Editor**:
![APIM Inbound Code Editor](../../assets/images/apim-inbound-code-editor.png)
- Using the *Form Editor*:
- Using the **Form Editor**:
![APIM Inbound Processing](../../assets/images/apim-inbound-processing.png)

Просмотреть файл

@ -6,11 +6,11 @@ nav_order: 1
---
### Cross-origin resource sharing (CORS)
### Cross-origin resource sharing (CORS) policy
The [cors policy](<https://docs.microsoft.com/en-us/azure/api-management/api-management-cross-domain-policies#CORS>) adds cross-origin resource sharing (CORS) support to an operation or an API to allow cross-domain calls from browser-based clients.
We have already configured the *cors* policy for our APIs in labs 2 & 3. Below is the resulting XML:
We have already configured the **CORS** policy for our APIs in labs 2 & 3. Below is the resulting XML:
![APIM Policy CORS All APIs](../../assets/images/apim-policy-cors-all-apis-1.png)

Просмотреть файл

@ -6,16 +6,16 @@ nav_order: 2
---
### Caching
### Caching policy
API Management can be configured for response caching which can significantly reduce API latency, bandwidth consumption, and web service load for data that does not change frequently.
Using the Azure Management portal, navigate to the *Colors* API and set a set a caching policy for the `Get random color` GET:
- Press *Add policy*.
Using the Azure Management portal, navigate to the **Colors** API and set a caching policy for the `Get random color` call:
- Press **Add policy**.
![APIM Adding Enable Caching](../../assets/images/apim-enable-caching-1.png)
- Select *Cache responses*.
- Select **Cache responses**.
![APIM Enable Caching](../../assets/images/apim-enable-caching-2.png)
@ -25,12 +25,12 @@ Using the Azure Management portal, navigate to the *Colors* API and set a set a
![APIM Cache Duration](../../assets/images/apim-enable-caching-3.png)
- Configure the Colors website from lab 3 to use the Unlimited subscription URL.
- Select *Start*.
- Select **Start**.
- Notice that for each 15 second period the same color is set.
![Colors Website Caching](../../assets/images/color-website-caching.png)
- Looking at the *Get Random color* GET API policies in the *Code View*, you'll see the caching policy defined:
- Looking at the **Get Random color** GET API policies in the **Code View**, you'll see the caching policy defined:
```xml
<policies>

Просмотреть файл

@ -5,29 +5,28 @@ has_children: false
nav_order: 3
---
## Colors API
## Transformation policies
### Transformation - replace string
The *find-and-replace* policy finds a substring in a request or response and replaces it with a different string.
The **find-and-replace** policy finds a substring in a request or response and replaces it with a different string.
- Open the *Colors* API, then open the `Get random color` operation.
- Enter the *Policy code editor* in the *Outbound processing* section.
- Open the **Colors** API, then open the `Get random color` operation.
- Enter the **Policy code editor** in the **Outbound processing** section.
- Place the cursor after the `<base />` element in the `<outbound>` section.
- Press *Show snippets*, then select the *Find and replace string in body* transformation policy.
- Press **Show snippets**, then select the **Find and replace string in body** transformation policy.
![APIM Policy Find & Replace](../../assets/images/apim-policy-find-and-replace-1.png)
- Fill in the `from` and `to` values accordingly:
```xml
<outbound>
<base />
<find-and-replace from="blue" to="yellow" />
<cache-store duration="15" />
</outbound>
```
```xml
<outbound>
<base />
<find-and-replace from="blue" to="yellow" />
<cache-store duration="15" />
</outbound>
```
![APIM Policy Find & Replace](../../assets/images/apim-policy-find-and-replace-2.png)
@ -37,16 +36,14 @@ The *find-and-replace* policy finds a substring in a request or response and rep
---
## Star Wars API
### Transformation - conditional
Policies can be applied very granularly. In this example, you are modifying the *Star Wars* API to return a limited set of information if the caller is using the *Starter* subscription. Other products, such as the *Unlimited* subscription, will receive the full response.
Policies can be applied very granularly. In this example, you are modifying the **Star Wars** API to return a limited set of information if the caller is using the **Starter** subscription. Other products, such as the **Unlimited** subscription, will receive the full response.
The [context variable](https://docs.microsoft.com/en-us/azure/api-management/api-management-policy-expressions#ContextVariables) that is implicitly available in every policy expression provides access to the `Response` and `Product` below.
- Open the *Star Wars* API, then open the *GetPeopleById* operation.
- Similarly to the *Colors* API, we will add the outbound policy to conditionally change the response body. Replace the existing entries in the operation with the entire `<policies>` code below.
- Open the **Star Wars** API, then open the **Get People By Id** operation.
- Similarly to the **Colors** API, we will add the outbound policy to conditionally change the response body. Replace the existing entries in the operation with the entire `<policies>` code below.
Note that the inbound `Accept-Encoding` header is set to `deflate` to ensure that the response body is not encoded as that causes the JSON parsing to fail.
```xml
@ -83,25 +80,23 @@ Note that the inbound `Accept-Encoding` header is set to `deflate` to ensure tha
</policies>
```
- Test the API on the *Test* tab with *id* 1 and apply the appropriate *Starter* or *Unlimited* product scope. Examine the different responses.
- Test the API on the **Test** tab with **id** 1 and apply the appropriate **Starter** or **Unlimited** product scope. Examine the different responses.
- With *Starter* or *None* product scope:
- With **Starter** or **None** product scope:
![APIM Policy Transform Starter Product](../../assets/images/apim-policy-transform-starter-product.png)
- With *Unlimited* product scope. Notice the four properties in red that are not included in the *Starter* scope response.
- With **Unlimited** product scope. Notice the four properties in red that are not included in the **Starter** scope response.
![APIM Policy Transform Unlimited Product](../../assets/images/apim-policy-transform-unlimited-product.png)
---
## Calculator API
### Transformation - XML to JSON
A frequent requirement is to transform content, especially to maintain compatibility with legacy APIs. For this lab we are going back to the *Calculator* API that returned an XML response.
A frequent requirement is to transform content, especially to maintain compatibility with legacy APIs. For this lab we are going back to the **Calculator** API that returned an XML response.
- Add an outbound policy to the *Add two integers* operation on the *Calculator* API to transform the response body to JSON.
- Add an outbound policy to the **Add two integers** operation on the **Calculator** API to transform the response body to JSON.
```xml
<outbound>
@ -114,11 +109,11 @@ A frequent requirement is to transform content, especially to maintain compatibi
![APIM Policy Transform XML to JSON](../../assets/images/apim-policy-transform-xml-to-json.png)
### Delete response headers
### Transformation - Delete response headers
A frequent requirement is to remove headers, especially ones that return security-related or superfluous information.
- Add an outbound policy to the same *Calculator* API operation to remove specific response headers.
- Add an outbound policy to the same **Calculator** API operation to remove specific response headers.
```xml
<outbound>
@ -133,11 +128,11 @@ A frequent requirement is to remove headers, especially ones that return securit
![APIM Policy Delete Response Header](../../assets/images/apim-policy-delete-response-header.png)
### Amend what's passed to the backend
### Transformation - Amend what's passed to the backend
Query string parameters and headers can be easily modified prior to sending the request on to the backend.
- Back in the same *Calculator* API operation, add inbound policies to modify the query string and headers.
- Back in the same **Calculator** API operation, add inbound policies to modify the query string and headers.
```xml
<inbound>
@ -151,7 +146,7 @@ Query string parameters and headers can be easily modified prior to sending the
</inbound>
```
- Test the call by using either the *Starter* or *Unlimited* product, click on Trace button and then inspect the result on the *Trace* tab. If Tracing is not enabled, press *Enable Tracing*.
- Test the call by using either the **Starter** or **Unlimited** product, click on Trace button and then inspect the result on the **Trace** tab. If Tracing is not enabled, press **Enable Tracing**.
![APIM Policy Amend Backend Call](../../assets/images/apim-trace-amend-backend-1.png)

Просмотреть файл

@ -6,11 +6,9 @@ nav_order: 4
---
## Calculator API
## Named Values
### Named Values collection
*Named Values* (aka *Properties*) are a collection of key/value pairs that are global to the service instance. These properties can be used to manage `string` constants across all API configurations and policies. Values can be expressions, secrets (encrypted by APIM), or Key Vault, which links to a corresponding secret in Azure Key Vault.
**Named Values** (aka **Properties**) are a collection of key/value pairs that are global to the service instance. These properties can be used to manage `string` constants across all API configurations and policies. Values can be expressions, secrets (encrypted by APIM), or Key Vault, which links to a corresponding secret in Azure Key Vault.
- Open the `Named values` blade in the resource menu and press **+ Add**.
- Create the new property:
@ -21,7 +19,7 @@ nav_order: 4
![APIM Named Values](../../assets/images/apim-named-values.png)
- Back in the *APIs* blade, open the *Add two integers* operation in the Calculator API.
- Back in the **APIs** blade, open the **Add two integers** operation in the Calculator API.
- Amend the inbound `set-header` policy by clicking on the pencil icon.
- Create a new header by pressing **+ Add header**:
- Name: **x-request-received-time**
@ -44,7 +42,7 @@ nav_order: 4
</inbound>
```
- Test the operation by selecting the *Starter* or *Unlimited* product scope.
- Test the operation by selecting the **Starter** or **Unlimited** product scope.
- Examine the backend trace to find the added header with the evaluated named value:
```json

Просмотреть файл

@ -6,16 +6,16 @@ nav_order: 5
---
## Star Wars API
## Mock policy
### Mock responses
Mocking in APIM is a useful mechanism for API consumers to interact with APIs without waiting for the backend to be ready.
- Open the Star Wars API and select **+ Add Operation**
- Open the **Star Wars** API and select **+ Add Operation**
- Create a new GET operation:
- Display name: **GetFilm**
- Name: **getfilm**
- Display name: **Get Film**
- Name: **get-film**
- URL: **/film**
- In the *Responses* configuration tab, press **+ Add response**, return `200 OK` with a representation with content type `application/json` and this sample data:
@ -29,8 +29,8 @@ Mocking in APIM is a useful mechanism for API consumers to interact with APIs wi
![APIM Policy Mock Frontend](../../assets/images/apim-policy-mock-frontend.png)
- Press **Save**.
- Open the Inbound processing 'Code View'
- Add *Mock Response* under *Other policies* after the `<base /> tag.
- Open the Inbound processing **Code View**
- Add **Mock Response** under **Other policies** after the `<base />` tag.
```xml
<inbound>

Просмотреть файл

@ -6,19 +6,19 @@ nav_order: 6
---
## Calculator API
## Send One Way policy
APIM integrates well with [external services](https://docs.microsoft.com/en-us/azure/api-management/api-management-sample-send-request) via HTTP-based interaction.
This example shows a fire-and-forget [send-one-way-request](https://docs.microsoft.com/en-us/azure/api-management/api-management-sample-send-request#send-one-way-request) policy, which does not await a response. Alternatively, you can use a [send-request](https://docs.microsoft.com/en-us/azure/api-management/api-management-sample-send-request#send-request) policy to send a request and await a return. Some complex in-flight processing logic may also be better handled by using Logic Apps.
### Send-One-Way-Request Setup
### Setup the Send-One-Way-Request policy
The following policy and payload applies for both examples in this lab. **Please ensure that you replace the value in `<set-url>` with your webhook target URL.** You will identify the URL in either example below.
The following policy and payload applies for both examples in this section (webhook and teams). **Please ensure that you replace the value in `<set-url>` with your webhook target URL.** You will identify the URL in either example below.
- Open the *Add two integers* operation in the Calculator API.
- Open the 'Code View'.
- Add the `send-one-way-request` policy to *Outbound processing* and replace the webhook and payload as required. For demo purposes we are going to use the payload for a Teams message (even for Webhook.site) and also send the message on every successful request.
- Open the **Add two integers** operation in the Calculator API.
- Open the **Code View**.
- Add the `send-one-way-request` policy to **Outbound processing** and replace the webhook and payload as required. For demo purposes we are going to use the payload for a Teams message (even for Webhook.site) and also send the message on every successful request.
```xml
<outbound>
@ -60,11 +60,11 @@ The following policy and payload applies for both examples in this lab. **Please
![Webhook Site Setup](../../assets/images/webhook-site-1.png)
- Use this URL as the value in the `<set-url>` property in the `send-one-way-request` policy.
- Use this URL as the value in the `<set-url>` property in the `send-one-way-request` policy previously defined.
- Invoke the API from the APIM _Test_ tab and observe the `200` success response.
- Invoke the API from the APIM **Test** tab by clicking the **Trace** button and observe the `200` success response.
- Check the _Trace_ for the _Outbound_ one-way message.
- Check the **Trace** for the **Outbound** one-way message.
![Webhook Site APIM Trace](../../assets/images/webhook-site-apim-send-one-way-request-1.png)
@ -74,22 +74,13 @@ The following policy and payload applies for both examples in this lab. **Please
### Send a message to Microsoft Teams channel
An optional lab, for Microsoft Teams, please review [Create an Incoming Webhook](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook#create-an-incoming-webhook-1).
An optional lab to connect to Microsoft Teams:
- First, open Teams and enable a Webhook connector for your team.
- Get the URL of the webhook.
- Follow the official steps from the [documentation to create an Incoming Webhook](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook#create-an-incoming-webhook-1) and when you have your rwebhook URL ready, update the previous `send-one-way-request` policy.
![Teams Webhook](../../assets/images/teams-webhook-1.png)
- If you want, you can format the required payload. The payload sent to a Teams channel uses the [MessageCard](https://docs.microsoft.com/en-us/microsoftteams/platform/task-modules-and-cards/cards/cards-reference) JSON schema. You can experiment with different cards in the [MessageCard Playground](https://messagecardplayground.azurewebsites.net/).
![Teams Webhook](../../assets/images/teams-webhook-2.png)
![Teams Webhook](../../assets/images/teams-webhook-3.png)
![Teams Webhook](../../assets/images/teams-webhook-4.png)
- Format the required payload. The payload sent to a Teams channel uses the [MessageCard](https://docs.microsoft.com/en-us/microsoftteams/platform/task-modules-and-cards/cards/cards-reference) JSON schema. You can experiment with different cards in the [MessageCard Playground](https://messagecardplayground.azurewebsites.net/).
- Invoke the API from the _Test_ tab and observe the `200` success response.
- When you are ready, invoke the API from the **Test** tab and observe the `200` success response.
- Look for a received message in your Teams channel:

Просмотреть файл

@ -5,16 +5,15 @@ has_children: false
nav_order: 7
---
## Calculator API
## Abort processing policy
### Aborting the processing
The ability to terminate a response gracefully is of importance in a number of cases such as error handling or business logic. Using the `return-response` policies short-circuits the request and yields a response that often does not originate from the backend. Consider what general situations may make sense without shifting too much business logic into APIM.
- Open the *Add two integers* operation in the Calculator API.
- Open the 'Code View'.
- Add the inbound policy to test for a condition (just `true` for our example) and return an error.
- Open the **Add two integers** operation in the **Calculator** API.
- Open the **Code View**.
- Add the **inbound** policy to test for a condition (just `true` for our example) and return an error.
- Invoke the API.
- Observe the 500 error.

Просмотреть файл

@ -10,7 +10,7 @@ nav_order: 1
Proper version management not only helps organize your API, it also aids in API Management. In this exercise we are going to version an existing API.
> Integrate version management from the beginning with a `v1` or similar identifier.
> Good practice: Integrate version management from the beginning with a **v1** or similar identifier.
### Add a new version

Просмотреть файл

@ -10,8 +10,8 @@ nav_order: 2
### Add a new revision
- Select the *Star Wars* API v2.
- Select the *Revisions* tab.
- Select the **Star Wars** API **v2**.
- Select the **Revisions** tab.
- Add a new revision with description `Adding a caching policy.`
![APIM Revisions Menu](../../assets/images/apim-revisions-menu.png)
@ -23,8 +23,8 @@ nav_order: 2
### Add caching
- Switch to the *Design* tab, then select the `GetPeople` operation.
> *Revision 2* automatically became the active revision you are now making changes in. You can also switch between revisions, but **be aware that changes to the *Current* revision are live immediately**.
- Switch to the **Design** tab, then select the `Get People` operation.
> **Revision 2** automatically became the active revision you are now making changes in. You can also switch between revisions, but **be aware that changes to the *Current* revision are live immediately**.
![APIM Revision Add Caching](../../assets/images/apim-revision-add-caching-1.png)
@ -48,7 +48,7 @@ nav_order: 2
### Test the new revision
- From the Azure portal, test the `GetPeople` operation.
- From the Azure portal, test the `Get People` operation.
> Note the revision number at the top of the page as well as in the request URL.
The request URL should look similar to: `https://<your-apim-name>.azure-api.net/sw/v2;rev=2/people/`.
@ -60,7 +60,7 @@ nav_order: 2
### Make current revision
- Select the _Revisions_ tab.
- Select the **Revisions** tab.
- Click on the ellipsis for `rev2` and make it the current revision.
![APIM Revision Make Current](../../assets/images/apim-revision-make-current-1.png)

Просмотреть файл

@ -1,12 +1,12 @@
---
title: Basic with Azure Monitor
title: Basics with Azure Monitor
parent: Analytics & Monitoring
has_children: false
nav_order: 1
---
## Basic Monitoring with Azure Monitor
## Basics Monitoring with Azure Monitor
Analytics is available on the _Analytics_ blade in APIM.

Просмотреть файл

@ -12,7 +12,7 @@ Azure API Management allows for easy integration with Azure Application Insights
### Create an Azure Application Insights instance
Before you can use Azure Application Insights, you first need to create an instance of the service.
Before you can use Azure Application Insights, you first need to create an instance of the service. The naming convention for Application Insights is: `appi-<environment>-<region>-<application-name>-<owner>-<instance>`
1. Open the **Azure portal** and navigate to **Application Insights**.
@ -38,7 +38,7 @@ Before you can use Azure Application Insights, you first need to create an insta
![APIM App Insights Logger](../../assets/images/apim-app-insights-logger-2.png)
> Behind the scenes, a [Logger](https://docs.microsoft.com/rest/api/apimanagement/2019-12-01/logger/createorupdate) entity is created in your API Management instance, containing the Instrumentation Key of the Application Insights instance.
> Behind the scenes, a [Logger](https://docs.microsoft.com/rest/api/apimanagement/2019-12-01/logger/createorupdate) entity is created in your API Management instance, containing the Connection String of the Application Insights instance.
### Enable Application Insights logging for your API

Просмотреть файл

@ -24,7 +24,7 @@ An Event Hubs namespace provides a unique scoping container in which you create
1. Press **Create** to create the namespace, then enter the following:
1. Select the **Resource Group** you created in previous labs.
1. Enter a unique **Namespace name**.
1. Enter a unique **Namespace name**, the naming convention for Event Hub Namespace is: `evhns-<environment>-<region>-<application-name>-<owner>-<instance>`
1. Select the **Location** you used in previous labs.
1. Choose **Basic** for the **Pricing Tier**. To learn about differences between tiers, see [Quotas and limits](event-hubs-quotas.md), [Event Hubs Premium](event-hubs-premium-overview.md), and [Event Hubs Dedicated](event-hubs-dedicated-overview.md) articles.
1. Leave the **Throughput Units** setting as it is. To learn more about throughput units or processing units: [Event Hubs scalability](event-hubs-scalability.md).
@ -32,9 +32,7 @@ An Event Hubs namespace provides a unique scoping container in which you create
![Create an Event Hub Namespace](../../assets/images/event-hub-review-create.png)
1. Press **Go to resource**.
![Event Hub Namespace Created](../../assets/images/event-hub-namespace-created.png)
1. Press **Go to resource** when it's created.
1. Confirm that you see the **Event Hubs Namespace** page similar to the following example:
@ -44,17 +42,17 @@ An Event Hubs namespace provides a unique scoping container in which you create
## Create an Event Hub
To create an event hub within the namespace, follow these steps:
We will create an Event hub to receive logs from our APIM. To create an event hub within the namespace, follow these steps:
1. From the **Event Hubs** blade select **+ Event Hub**>
1. From the **Event Hubs** blade select **+ Event Hub**
![Add Event Hub](../../assets/images/event-hub-create-1.png)
1. Type a name for your event hub, then select **Create**.
1. Type a name for your event hub, the naming convention is `evh-<the-goal>-<environment>-<region>-<application-name>-<owner>-<instance>` then select **Create**.
The **partition count** setting allows you to parallelize consumption across many consumers. For more information, see [Partitions](event-hubs-scalability.md#partitions).
The **partition count** setting allows you to parallelize consumption across many consumers. For more information, see [Partitions](https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-features#partitions).
The **message retention** setting specifies how long the Event Hubs service keeps data. For more information, see [Event retention](event-hubs-features.md#event-retention).
The **message retention** setting specifies how long the Event Hubs service keeps data. For more information, see [Event retention](https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-features#event-publishers).
![Create Event Hub](../../assets/images/event-hub-create-2.png)
@ -92,7 +90,7 @@ API Management loggers are configured using the [API Management REST API](https:
1. Press **Sign in** and use your Azure credentials that you have been using with this workshop, if prompted.
1. Fill in the following **Parameters**:
1. loggerId: **eventhublogger**
1. loggerId: **event-hub-logger** (you will use it in the next steps)
1. resourceGroupName: your resource group
1. serviceName: your Azure APIM instance
1. subscriptionId: your Azure subscription
@ -101,35 +99,35 @@ API Management loggers are configured using the [API Management REST API](https:
1. Replace the request **Body** with the following json. Make sure you replace the parameters appropriately:
```json
{
"properties": {
"loggerType": "azureEventHub",
"description": "adding a new logger",
"credentials": {
"name": "<your event hub namespace>",
"connectionString": "<your Connection string-primary key>"
}
```json
{
"properties": {
"loggerType": "azureEventHub",
"description": "adding a new logger",
"credentials": {
"name": "<your event hub namespace>",
"connectionString": "<your Connection string-primary key>"
}
}
```
}
```
1. Your request parameters might then look similar to this:
> Note my deviation by intential masking my `SharedAccessKey`. Please do not alter your key.
```json
{
"properties": {
"loggerType": "azureEventHub",
"description": "adding a new logger",
"credentials": {
"name": "eh-sjk-01062022/myeventhub",
"connectionString": "Endpoint=sb://eh-sjk-01062022.servicebus.windows.net/;SharedAccessKeyName=sendpolicy;SharedAccessKey=********;EntityPath=myeventhub"
}
}
}
```
```json
{
"properties": {
"loggerType": "azureEventHub",
"description": "adding a new logger",
"credentials": {
"name": "evhns-dev-we-hol-ms-011/evh-logger-dev-we-hol-ms-01",
"connectionString": "Endpoint=sb://evhns-dev-we-hol-ms-011.servicebus.windows.net/;SharedAccessKeyName=sendpolicy;SharedAccessKey******=;EntityPath=evh-logger-dev-we-hol-ms-01"
}
}
}
```
1. Press **Run**.
1. You should get a **201** response, confirming that the resource has been created.
@ -140,7 +138,7 @@ API Management loggers are configured using the [API Management REST API](https:
## Configure log-to-eventhub policies
Once your logger is configured in API Management, you can configure your log-to-eventhub policy to log the desired events. The log-to-eventhub policy can be used in either the *inbound* policy section or the *outbound* policy section.
Once your logger is configured in API Management, you can configure your log-to-eventhub policy to log the desired events. The log-to-eventhub policy can be used in either the **inbound** policy section or the **outbound** policy section.
1. Browse to your APIM instance.
1. Select the **APIs** blade.
@ -148,7 +146,7 @@ Once your logger is configured in API Management, you can configure your log-to-
In this example, we're adding a policy to the **Echo API**.
1. Select **All operations**.
1. On the top of the screen, select the **Design** tab.
1. In the *Inbound* or *Outbound* processing window, enter the Code editor.
1. In the **Inbound** or **Outbound** processing window, enter the Code editor.
1. Enter a new line after the `<base />` tag in the `inbound` or `outbound` policy section.
1. Select **Show snippets**.
1. In the window on the right, select **Advanced policies** > **Log to EventHub**. This inserts the `log-to-eventhub` policy statement template.
@ -171,13 +169,13 @@ Once your logger is configured in API Management, you can configure your log-to-
</log-to-eventhub>
```
1. Replace `<your logger id>` with the value you used for `{loggerId}` in the request URL to create the logger in the previous step (e.g. `eventhublogger`).
1. Replace `<your logger id>` with the value you used for `{loggerId}` in the request URL to create the logger in the previous step (e.g. `event-hub-logger`).
> You can use any expression that returns a string as the value for the `log-to-eventhub` element. In this example, a string in JSON format containing the date and time, service name, request ID, request IP address, and operation name is logged.
![APIM Add to Event Hub](../../assets/images/apim-add-log-to-event-hub-2.png)
1. Click **Save** to save the updated policy configuration. As soon as it is saved the policy is active and events are logged to the designated Event Hub.
1. Click **Save** to update the policy configuration. As soon as it is saved the policy is active and events are logged to the designated Event Hub.
---
@ -188,4 +186,4 @@ Once your logger is configured in API Management, you can configure your log-to-
![Event Hub APIM events](../../assets/images/event-hub-apim-events.png)
> What to do with the data that is now in Event Hub is beyond the scope of this lab as this lab primarily focused on APIM to Event Hub integration.
> What to do with the data that is now in Event Hub is beyond the scope of this lab as this lab primarily focused on APIM to Event Hub integration.

Просмотреть файл

@ -3,3 +3,5 @@ title: Analytics & Monitoring
has_children: true
nav_order: 7
---
## Analytics & Monitoring

Просмотреть файл

@ -1,74 +0,0 @@
---
title: Managed Identities
parent: Security
has_children: false
nav_order: 3
---
## Security
### Managed Service Identity
In Azure, an Active Directory identity can be assigned to a managed resource such as an Azure Function, App Service or even an API Management instance. Once an identity is assigned, it has many capabilities to work with other resources that leverage Azure AD for authentication, much like a service principal.
#### Register API Management with Active Directory
![Register APIM](../../assets/images/apim-security-register-principal.png)
#### Key Vault - Create Key Vault and add a secret
- Create a Key Vault instance
- Add a [secret](https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal#add-a-secret-to-key-vault) to the Key Vault instance
- Name:`favoritePerson`
- Value: `3`
![Create Key Vault](../../assets/images/apim-security-create-key-vault.png)
#### Key Vault - Access policy and principal assignment
Create an access policy
![Create Key Vault](../../assets/images/apim-security-key-vault-1.jpg)
Select the `Get` operation from the list of Secret permissions
![Create Key Vault](../../assets/images/apim-security-key-vault-2.jpg)
Select the principal and search for the name of your API Management instance
![Create Key Vault](../../assets/images/apim-security-key-vault-3.jpg)
![Create Key Vault](../../assets/images/apim-security-key-vault-4.jpg)
Remember to click **Save**
![Create Key Vault](../../assets/images/apim-security-key-vault-5.jpg)
#### API Management, Key Vault and Managed Service Identity
- Add a new operation to the Star Wars API
- Update the policies for the new operation
![New operation](../../assets/images/apim-security-add-operation.png)
```xml
<!-- Inbound -->
<base />
<send-request mode="new" response-variable-name="secretResponse" timeout="20" ignore-error="false">
<set-url>https://{your-keyvault-base-uri}.azure.net/secrets/favoritePerson/?api-version=7.0</set-url>
<set-method>GET</set-method>
<authentication-managed-identity resource="https://vault.azure.net" />
</send-request>
<set-variable name="favoritePersonRequest" value="@{
var secret = ((IResponse)context.Variables["secretResponse"]).Body.As<JObject>();
return "/people/" + secret["value"].ToString() + "/";
}" />
<rewrite-uri template="@((string)context.Variables["favoritePersonRequest"])" />
```
#### Test the operation
- Test the operation (use the developer portal, Azure portal or tools like Postman and curl)
- Notice the request URL will be similar to: `https://{your-apim-instance}.azure-api.net/sw/favorite`

Просмотреть файл

@ -6,11 +6,11 @@ nav_order: 1
---
## Security
## JSON Web Tokens (JWT)
In this lab, we are going to see how to use JSON Web Tokens with your APIs.
### JSON Web Tokens (JWT) - Creation
### Creation
JSON Web Tokens are an open-industry standard method for representing claims securely between two parties. More info at <https://jwt.io>.
@ -36,10 +36,10 @@ Use the following sites:
![JWT.io Website](../../assets/images/jwt-io.png)
### JSON Web Tokens (JWT) - Validation
### Validation
- Back in APIM, open the *Calculator* API and select *All operations*.
- In the 'Code View' add an inbound `validate-jwt` policy with the signing key.
- Back in APIM, open the **Calculator** API and select **All operations**.
- In the **Code View** add an inbound `validate-jwt` policy with the signing key.
```xml
<policies>
@ -55,14 +55,14 @@ Use the following sites:
</policies>
```
- Invoke the *Divide two integers* method on the API from the *Test* tab. Observe the `401` Unauthorized error.
- Invoke the **Divide two integers** method on the API from the **Test** tab. Observe the `401` Unauthorized error.
![APIM Request with no JWT](../../assets/images/apim-request-no-jwt.png)
- Now add the following `Authorization` header to the test:
- Name: `Authorization`
- Value: `Bearer <jwt token>`
- Replace `<jwt token>` with the *encoded* value from <https://jwt.io> above
- Replace `<jwt token>` with the **encoded** value from <https://jwt.io> above
Note the bearer token in the Request payload.
@ -72,11 +72,11 @@ Use the following sites:
![](../../assets/images/apim-request-valid-jwt.png)
### JSON Web Tokens (JWT) - Check that a Claim Exists
### Check that a Claim Exists
Not only is it important that a JWT is valid, but, as we use it for authorization, we must also assert that the token contains expected claims before granting access to our APIs.
- Open the *Calculator* API and select *All operations*.
- Open the **Calculator** API and select **All operations**.
- Modify the inbound `validate-jwt` policy to not only validate the JWT but ensure that a specific `admin` claim exists. Recall that we set `admin`: `true` in our JWT token on <https://jwt.io> above.
```xml
@ -98,7 +98,7 @@ Not only is it important that a JWT is valid, but, as we use it for authorizatio
</policies>
```
- Invoke the *Divide two integers* method with the `Authorization` header as above and observe the `200` success. We have not fundamentally changed the test scenario as we only restricted the claims to something that we already had in our payload.
- Invoke the **Divide two integers** method with the `Authorization` header as above and observe the `200` success. We have not fundamentally changed the test scenario as we only restricted the claims to something that we already had in our payload.
- Now change the `required-claims` with a claim that does not exist (e.g. `adminx`)
@ -121,13 +121,15 @@ Not only is it important that a JWT is valid, but, as we use it for authorizatio
</policies>
```
- Invoke the *Divide two integers* method with the `Authorization` header once more and observe the `401` Unauthorized error as the token specifies `admin` but the policy requires `adminx`.
- Invoke the **Divide two integers** method with the `Authorization` header once more and observe the `401` Unauthorized error as the token specifies `admin` but the policy requires `adminx`.
### JSON Web Tokens (JWT) - Extract Claim and Pass to Backend
### Extract Claim and Pass to Backend
It may often be necessary to pass (specific) claims onto the backend API to inform further processing. One such way - and this can be tailored to an API's individuality - is to extract a claim and place it into a designated header the backend expects.
- Open the *Calculator* API and select *All operations*.
Let's add the username contained inside the JSON Web Tokens into a specific header.
- Open the **Calculator** API and select **All operations**.
- Append the inbound policy section to extract the `name` claim and place it into a header underneath the `validate-jwt` policy.
- Change the claim back from `adminx` to `admin` as we are interested in a successful test again.
@ -157,11 +159,11 @@ It may often be necessary to pass (specific) claims onto the backend API to info
</policies>
```
- Invoke the *Divide two integers* method with the `Authorization` header once more and observe the `200` Success.
- Use the *Trace* feature to inspect what was passed to backend. You should see the new header and the correct value from the claims.
- Invoke the **Divide two integers** method with the `Authorization` header once more and observe the `200` Success.
- Use the **Trace** feature to inspect what was passed to backend. You should see the new header and the correct value from the claims.
![APIM JWT Claim in Trace](../../assets/images/apim-jwt-claim-in-trace.png)
### JSON Web Tokens (JWT) - Improvements
### Improvements
Based on what you have learned thus far, consider how you can improve your policies. For example, you may not want to hard-code the `issuer-signing-key` and instead use a Named Value that you can more easily administer and change outside of an API's policies. If you have time in this exercise, go ahead and give it a try.

Просмотреть файл

@ -1,6 +1,6 @@
---
title: Oauth2 And Azure APIM
parent: Oauth2
title: OAuth2 And Azure APIM
parent: OAuth2
grand_parent: Security
has_children: false
nav_order: 4

Просмотреть файл

@ -1,6 +1,6 @@
---
title: Create Azure AD Tenant
parent: Oauth2
parent: OAuth2
grand_parent: Security
has_children: false
nav_order: 5
@ -11,23 +11,23 @@ nav_order: 5
1. Sign in to your organization's [Azure portal](https://portal.azure.com/).
1. From the Azure portal menu, select **Create a resource**.
1. Select **Identity**, and then select **Azure Active Directory**.
![Azure Active Directory Create resoure page](../../assets/images/azure-ad-portal.png)
1. Select **Identity**, and then select **Azure Active Directory**.
The **Create directory** page appears.
![Azure Active Directory Create page](../../assets/images/azure-ad-create-new-tenant.png)
![Azure Active Directory Create page](../../assets/images/azure-ad-create-new-tenant-1.png)
1. On the **Create directory** page, enter the following information:
1. On the **Create directory** page, enter the following information with a unique available value:
- **Organization name**
- **Initial domain name**
- Type _Contoso_ into the **Organization name** box.
- Finaly, leave the _United States_ option in the **Country or region** box.
- Type _Contoso_ into the **Initial domain name** box.
- Leave the _United States_ option in the **Country or region** box.
![Azure Active Directory Create page](../../assets/images/azure-ad-create-new-tenant-2.png)
1. Select **Create**.
Your new tenant is created with the domain labapimtenant.onmicrosoft.com.
Your new tenant is created with the domain `<your domain>.onmicrosoft.com`.

Просмотреть файл

@ -1,6 +1,6 @@
---
title: Authorization Code Flow
parent: Oauth2
title: Authorization Code
parent: OAuth2
grand_parent: Security
has_children: false
nav_order: 5
@ -8,7 +8,9 @@ nav_order: 5
## Authorization Code
In Authorization code grant type, User is challenged to prove their identity providing user credentials. Upon successful authorization, the token end point is used to obtain an access token. The obtained token is sent to the resource server and gets validated before sending the secured data to the client application.
### Authorization Code Flow
In Authorization code grant type, User is challenged to prove their identity providing user credentials. Upon successful authorization, the token endpoint is used to obtain an access token. The obtained token is sent to the resource server and gets validated before sending the secured data to the client application.
![Authorization Code Flow](../../assets/images/convergence-scenarios-native.svg)
@ -31,38 +33,41 @@ To protect an API with Azure AD, first register an application in Azure AD that
![backend app registration2](../../assets/images/authflow2.png)
- On the app Overview page, find the Application (client) ID value and record it for later.
- On the app Overview page, find the Application (client) ID value and **record it for later**.
![backend app registration3](../../assets/images/authflow3.png)
- Select Expose an API and set the Application ID URI with the default value. Record this value for later.
- Select the Add a scope button to display the Add a scope page. Then create a new scope that's supported by the API (for example, Calculator.Read).
- Select the Add scope button to create the scope. Repeat this step to add all scopes supported by your API.
- When the scopes are created, make a note of them for use in a subsequent step.
- Select **Expose an API** and **set** the Application ID URI with the default value. Record this value for later.
![backend app registration4a](../../assets/images/authflow4a.png)
![backend app registration4](../../assets/images/authflow4.png)
- Select the **Add a scope**. Then create a new scope that's supported by the API (for example, Calculator.Read).
![backend app registration4b](../../assets/images/authflow4b.png)
- Select the **Add scope** button to create the scope.
- Repeat this step to add all scopes supported by your API. When the scopes are created, **make a note of them** for use in a subsequent step (optional for this lab).
![backend app registration4c](../../assets/images/authflow4c.png)
### Register another application (client-app) in Azure AD to represent the Developer Portal( client application)
Every client application that calls the API needs to be registered as an application in Azure AD. In this example, the client application is the Developer Console in the API Management developer portal. In this case we will register another application in Azure AD to represent the Developer Console:
- Select New registration.
![client app registration1](../../assets/images/authflow1.png)
- Select **New registration**.
- In the Name section, enter a meaningful application name that will be displayed to users of the app. For example `oauth-client-app`
- In the Supported account types section, select an option that suits your scenario.
- Leave the Redirect URI section empty.
- Select Register to create the application.
- In the **Supported account** types section, select an option that suits your scenario.
- Leave the **Redirect URI** section empty.
- Select **Register** to create the application.
![client app registration2](../../assets/images/authflow2.png)
![client app registration5a](../../assets/images/authflow5a.png)
- On the app Overview page, find the Application (client) ID value and record it for later.
- On the app **Overview page**, find the **Application (client) ID** value and **record it for later**.
- Create a client secret for this application to use in a subsequent step.
- From the left menu options for your client app, select Certificates & secrets, and select New client secret.
- Under Add a client secret, provide a Description. Choose when the key should expire and select Add. When the secret is created, note the key value for use in a subsequent step.
- From the left menu options for your client app, select **Certificates & secrets**, and select New client **secret**.
- Under Add a client secret, provide a **Description**. Choose when the key should expire and select **Add**. When the secret is created, note the **key value** for use in a subsequent step.
![client app registration5](../../assets/images/authflow5.png)
![client app registration5b](../../assets/images/authflow5b.png)
### Grant permissions for client-app to call backend-app
@ -88,14 +93,13 @@ Every client application that calls the API needs to be registered as an applica
At this point, we have created the applications in Azure AD, and granted proper permissions to allow the client-app to call the backend-app.
In this demo, the Developer Console is the client-app and has a walk through on how to enable OAuth 2.0 user authorization in the Developer Console.
Steps mentioned below:
- In Azure portal, browse to your API Management instance and Select OAuth 2.0 > Add.
- Provide a Display name and Description.
- For the Client registration page URL, enter a placeholder value, such as http://localhost.
- For Authorization grant types, select Authorization code.
- In Azure portal, browse to your **API Management instance**, select **OAuth 2.0** then **Add**.
- Provide a **Display name** and **Description**.
- For the Client **registration page URL**, enter a placeholder value, such as http://localhost.
- For Authorization grant types, select **Authorization code**.
![authcode6](../../assets/images/authflow6.png)
@ -106,18 +110,18 @@ Specify the Authorization endpoint URL and Token endpoint URL. These values can
![authcode8](../../assets/images/authflow8.png)
#### Endpoints versions
### Endpoints versions
We recommend using v2 endpoints. When using v2 endpoints, use the scope you created for the backend-app in the Default scope field. Also, make sure to set the value for the accessTokenAcceptedVersion property to 2 in your application manifest in Azure AD Client APP and Backend app.
![authcode9](../../assets/images/authflow9.png)
- Next, specify the client credentials. These are the credentials for the client-app.
- For Client ID, use the Application ID of the client-app.
- For **Client ID**, use the Application ID of the client-app.
![authcode10](../../assets/images/authflow10.png)
- For Client secret, use the key you created for the client-app earlier.
- For **Client secret**, use the key you created for the client-app earlier.
- Immediately following the client secret is the redirect_urls
![authcode11](../../assets/images/authflow11.png)
@ -131,18 +135,18 @@ Now that you have configured an OAuth 2.0 authorization server, the Developer Co
The next step is to enable OAuth 2.0 user authorization for your API. This enables the Developer Console to know that it needs to obtain an access token on behalf of the user, before making calls to your API.
- Go to APIs menu under the APIM
- Select the `Basic Calculator API` and Go to `Settings`.
- Go to **APIs** menu under the APIM
- Select the **Basic Calculator** and Go to **Settings**.
- Under Security, choose OAuth 2.0, select the OAuth 2.0 server you configured earlier and select save.
![authcode13](../../assets/images/authflow13.png)
- Publish the developer portal again to refresh this changes
![](../../assets/images/apim-developerportal-publish.png)
![Apim Publish](../../assets/images/apim-developer-portal-publish.png)
#### Calling the API from the Developer Portal
### Calling the API from the Developer Portal
Now that the OAuth 2.0 user authorization is enabled on your API, the Developer Console will obtain an access token on behalf of the user, before calling the API.
@ -150,7 +154,7 @@ Now that the OAuth 2.0 user authorization is enabled on your API, the Developer
![authcode14](../../assets/images/authflow14.png)
- Browse to any operation under the Basic Calculator API in the developer portal and select Try it. This brings you to the Developer Console.
- Browse to any operation under the **Basic Calculator** API in the developer portal and select Try it. This brings you to the Developer Console.
- Note a new item in the Authorization section, corresponding to the authorization server you just added.
![authcode15](../../assets/images/authflow15.png)
@ -176,40 +180,45 @@ To pre-Authorize requests, we can use `validate-jwt` Policy by validating the ac
We will now configure the Validate JWT policy to pre-authorize requests in API Management, by validating the access tokens of each incoming request. If a request does not have a valid token, API Management blocks it.
- Browses to the APIs from the left menu of APIM
- Click on `Basic Calculator Api` and open the inbound policy to add the validate-jwt policy(It checks the audience claim in an access token and returns an error message if the token is not valid.) and save it.
![authcode19](../../assets/images/authflow19.png)
- You will need to get the id of your scope, you set from you backend-app registration. Normally this comes in the form `api://d183fdbe-fc28-4ef7-9ca1-e7b4a4cd1ff8/Calculator.read` , we need to use the id `d183fdbe-fc28-4ef7-9ca1-e7b4a4cd1ff8` as audience
![backend app registration4](../../assets/images/authflow4.png)
- Click on **Basic Calculator** Api and open the **inbound** policy to add the `validate-jwt policy` (it checks the audience claim in an access token and returns an error message if the token is not valid) and save it.
``` xml
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration" />
<audiences>
<audience>YOUR-BACKENDAPP-SCOPE-ID</audience>
<audience>your-backendapp-scope-id-here</audience>
</audiences>
</validate-jwt>
```
> If you have configuration from previous par of this lab, just remove it.
You should have something like this:
![authcode19](../../assets/images/authflow19.png)
- You will need to get the id of your scope, you set from you backend-app registration. Normally this comes in the form `api://<your-backend-id>/Calculator.read` , we need to use the id `<your-backend-id>` as audience
![backend app registration4](../../assets/images/authflow4a.png)
- Go back to the developer portal and send the api with invalid token.
- You would observe the 401 unauthorized.
![authcode20](../../assets/images/authflow20.png)
- Modify the token from authorization header to the valid token and send the api again to observe the 200-ok response.
- Modify the token from authorization header to the valid token and send the api again to observe the 200 Ok response.
#### Understanding validate-jwt Policy
### Understanding validate-jwt Policy
![authcode21](../../assets/images/authflow21.png)
In this section, we will be focusing on understanding how `validate-jwt` policy works (the image in the right side is the decoded JWT Token)
- The validate-jwt policy supports the validation of JWT tokens from the security viewpoint, It validates a JWT (JSON Web Token) passed via the HTTP Authorization header
- If the validation fails, a 401 code is returned. The policy requires an openid-config endpoint to be specified via an openid-config element. API Management expects to browse this endpoint when evaluating the policy as it has information which is used internally to validate the token.
- If the validation fails, a 401 code is returned. The policy requires an `openid-config` endpoint to be specified via an `openid-config` element. API Management expects to browse this endpoint when evaluating the policy as it has information which is used internally to validate the token.
Please Note : OpenID config URL differs for the v1 and v2 endpoints.
- The required-claims section contains a list of claims expected to be present on the token for it to be considered valid. The specified claim value in the policy must be present in the token for validation to succeed.
The claim value should be the Application ID of the Registered Azure AD Backend-APP.

Просмотреть файл

@ -1,5 +1,5 @@
---
title: Oauth2
title: OAuth2
parent: Security
has_children: true
nav_order: 2

Просмотреть файл

@ -0,0 +1,79 @@
---
title: Managed Identities
parent: Security
has_children: false
nav_order: 3
---
## Managed Identities
In Azure, an Active Directory identity can be assigned to a managed resource such as an Azure Function, App Service or even an API Management instance. Once an identity is assigned, it has many capabilities to work with other resources that leverage Azure AD for authentication, much like a service principal.
### Register API Management with Active Directory
![Register APIM](../../assets/images/apim-security-register-principal.png)
## Key Vault
### Create Key Vault and add a secret
- Create a **Key Vault** instance, the naming convention is: `kv-<environment>-<region>-<application-name>-<owner>-<instance>`
![Create Key Vault](../../assets/images/apim-security-create-key-vault.png)
- Next, add a [secret](https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal#add-a-secret-to-key-vault) to the Key Vault instance
- Name:`favoritePerson`
- Secret value: `3`
### Access policy and principal assignment
Create an access policy
![Create Key Vault](../../assets/images/apim-security-key-vault-1.png)
Select the `Get` operation from the list of Secret permissions
![Create Key Vault](../../assets/images/apim-security-key-vault-2.png)
Select the principal and search for the name of your API Management instance
![Create Key Vault](../../assets/images/apim-security-key-vault-3.png)
Remember to click **Create**
You should see something like this:
![Create Key Vault](../../assets/images/apim-security-key-vault-4.png)
### API Management, Key Vault and Managed Service Identity
- Go back to your APIM
- Add a new operation to the **Star Wars** API (if you did the previous parts of the labs, choose the version of the API you want)
![New operation](../../assets/images/apim-security-add-operation.png)
- Update the policies for **this** new operation
```xml
<inbound>
<base />
<send-request mode="new" response-variable-name="secretResponse" timeout="20" ignore-error="false">
<set-url>https://{your-keyvault-name}.vault.azure.net/secrets/favoritePerson/?api-version=7.0</set-url>
<set-method>GET</set-method>
<authentication-managed-identity resource="https://vault.azure.net" />
</send-request>
<set-variable name="favoritePersonRequest" value="@{
var secret = ((IResponse)context.Variables["secretResponse"]).Body.As<JObject>();
return "/people/" + secret["value"].ToString() + "/";
}" />
<rewrite-uri template="@((string)context.Variables["favoritePersonRequest"])" />
</inbound>
```
Don't forget to change the `set-url` value with your Key Vault name.
### Test the operation
- Sign in to the developer portal and test this new operation
- Notice the request URL will be similar to: `https://{your-apim-instance}.azure-api.net/sw/favorite`

Просмотреть файл

@ -1,11 +1,13 @@
---
title: API Management Devops
title: Overview
parent: DevOps
has_children: false
nav_order: 1
---
Review [the documentation][1] for advice on how to [use DevOps and CI/CD to publish APIs][1].
## Overview
Review the documentation for advice on how to [use DevOps and CI/CD to publish APIs][1].
Azure API Management recommends the use of [APIOps](https://learn.microsoft.com/azure/architecture/example-scenario/devops/automated-api-deployments-apiops) as a devops methodology for maintaining a production deployment of Azure API Management. Please see the [hands-on-lab for APIOps](https://azure.github.io/apiops) for a complete walk-through of the APIOps DevOps methodology.

Просмотреть файл

@ -3,3 +3,5 @@ title: DevOps
has_children: true
nav_order: 9
---
## DevOps

Просмотреть файл

@ -1,15 +1,17 @@
---
title: Powerapp + Azure Apim API
title: Power Apps and APIM
parent: Fusion Dev
has_children: false
nav_order: 1
---
## Power Apps and APIM
The *premier* Star Wars Fan club is growing and the club officers would like to upgrade from their existing member tracking worksheet to a mobile application that would be available to their members all over the world. The members would also like to see information about their favorite Star Wars movies and characters in the application that would update as new shows and movies are released.
In this exercise, you will be using [Star Wars API](https://swapi.dev/) with Azure API Management instance that you created [in part three](https://azure.github.io/apim-lab/apim-lab/3-addingApis/apimanagement-3-1.html) of this lab. The Excel worksheet of member profiles will serve as the primary backing data source and will be used to generate a base application. You will export the Star Wars API from API Management as a Power Platform Custom Connector so that the Canvas App can access real-time Star Wars character information. For each of the Fan Club members, you can then search the Star Wars API character data and show information about their favorite character in the Canvas App.
In this exercise, you will be using [Star Wars API](https://swapi.dev/) with Azure API Management instance that you created [in part three](../3-adding-apis/adding-apis-3-1-from-scratch.md) of this lab. The Excel worksheet of member profiles will serve as the primary backing data source and will be used to generate a base application. You will export the Star Wars API from API Management as a Power Platform Custom Connector so that the Canvas App can access real-time Star Wars character information. For each of the Fan Club members, you can then search the Star Wars API character data and show information about their favorite character in the Canvas App.
*Note: This exercise requires access to Power Apps Premium connectors. Sign up for a [free Developer Plan](https://powerapps.microsoft.com/en-us/developerplan/).*
> *Note: This exercise requires access to Power Apps Premium connectors. Sign up for a [free Developer Plan](https://powerapps.microsoft.com/en-us/developerplan/).*
### Update CORS policy
@ -23,7 +25,7 @@ From the existing Star Wars API Api in Azure API Management, click the ellipsis
![](https://user-images.githubusercontent.com/1610195/134442238-785e77fd-0230-433a-95ab-ac479a1427e6.png)
If you are unable to create a Power Connector from Azure API Management, you can also export an `OpenAPI v2 (JSON)` file that can be imported as a Custom Connector within Power Platform. You can find a sample [here](https://github.com/Azure/apim-lab/blob/main/apim-lab/9-fusiondev/Star%20Wars%20API.swagger.json).
If you are unable to create a Power Connector from Azure API Management, you can also export an `OpenAPI v2 (JSON)` file that can be imported as a Custom Connector within Power Platform. You can find a sample [here](https://github.com/Azure/apim-lab/blob/main/apim-lab/9-fusion-dev/Star%20Wars%20API.swagger.json).
### View your custom connector in Power Platform

Просмотреть файл

Двоичные данные
assets/images/ado-build-pipeline1.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 30 KiB

Двоичные данные
assets/images/ado-build-pipeline2.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 40 KiB

Двоичные данные
assets/images/ado-deploy-qa.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 62 KiB

Двоичные данные
assets/images/ado-release-pipeline.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 30 KiB

Двоичные данные
assets/images/ado-release-prod.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 71 KiB

Двоичные данные
assets/images/ado-release-qa-parameters.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 28 KiB

Двоичные данные
assets/images/apim-activate-subscription.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 44 KiB

После

Ширина:  |  Высота:  |  Размер: 56 KiB

Двоичные данные
assets/images/apim-add-blank-api.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 61 KiB

После

Ширина:  |  Высота:  |  Размер: 62 KiB

Двоичные данные
assets/images/apim-add-calc-api-1.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 75 KiB

После

Ширина:  |  Высота:  |  Размер: 74 KiB

Двоичные данные
assets/images/apim-add-calc-api-2.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 126 KiB

После

Ширина:  |  Высота:  |  Размер: 102 KiB

Двоичные данные
assets/images/apim-add-color-api-1.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 177 KiB

После

Ширина:  |  Высота:  |  Размер: 49 KiB

Двоичные данные
assets/images/apim-add-color-api-2.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 326 KiB

После

Ширина:  |  Высота:  |  Размер: 306 KiB

Двоичные данные
assets/images/apim-add-log-to-event-hub-1.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 242 KiB

После

Ширина:  |  Высота:  |  Размер: 196 KiB

Двоичные данные
assets/images/apim-add-log-to-event-hub-2.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 204 KiB

После

Ширина:  |  Высота:  |  Размер: 89 KiB

Двоичные данные
assets/images/apim-add-product-1.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 48 KiB

После

Ширина:  |  Высота:  |  Размер: 45 KiB

Двоичные данные
assets/images/apim-add-product-2.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 96 KiB

После

Ширина:  |  Высота:  |  Размер: 102 KiB

Двоичные данные
assets/images/apim-add-product-access-1.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 57 KiB

После

Ширина:  |  Высота:  |  Размер: 67 KiB

Двоичные данные
assets/images/apim-add-product-access-2.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 66 KiB

После

Ширина:  |  Высота:  |  Размер: 85 KiB

Двоичные данные
assets/images/apim-apis.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 165 KiB

После

Ширина:  |  Высота:  |  Размер: 182 KiB

Двоичные данные
assets/images/apim-app-insights-api-1.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 179 KiB

После

Ширина:  |  Высота:  |  Размер: 119 KiB

Двоичные данные
assets/images/apim-app-insights-api-2.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 249 KiB

После

Ширина:  |  Высота:  |  Размер: 235 KiB

Двоичные данные
assets/images/apim-app-insights-logger-1.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 119 KiB

После

Ширина:  |  Высота:  |  Размер: 141 KiB

Двоичные данные
assets/images/apim-app-insights-logger-2.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 93 KiB

После

Ширина:  |  Высота:  |  Размер: 89 KiB

Двоичные данные
assets/images/apim-azure-monitor-analytics-1.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 158 KiB

После

Ширина:  |  Высота:  |  Размер: 156 KiB

Двоичные данные
assets/images/apim-azure-monitor-analytics-2.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 205 KiB

После

Ширина:  |  Высота:  |  Размер: 203 KiB

Двоичные данные
assets/images/apim-azure-monitor-analytics-3.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 182 KiB

После

Ширина:  |  Высота:  |  Размер: 153 KiB

Двоичные данные
assets/images/apim-calc-api-swagger-1.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 112 KiB

После

Ширина:  |  Высота:  |  Размер: 83 KiB

Двоичные данные
assets/images/apim-calc-api-swagger-2.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 156 KiB

После

Ширина:  |  Высота:  |  Размер: 155 KiB

Двоичные данные
assets/images/apim-color-api-add-products.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 250 KiB

После

Ширина:  |  Высота:  |  Размер: 230 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 36 KiB

После

Ширина:  |  Высота:  |  Размер: 35 KiB

Двоичные данные
assets/images/apim-creation-email.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 40 KiB

Двоичные данные
assets/images/apim-deploy-blade-vnet.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 16 KiB

После

Ширина:  |  Высота:  |  Размер: 50 KiB

Двоичные данные
assets/images/apim-deploy-blade.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 54 KiB

После

Ширина:  |  Высота:  |  Размер: 133 KiB

Двоичные данные
assets/images/apim-dev.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 40 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 17 KiB

После

Ширина:  |  Высота:  |  Размер: 8.5 KiB

Двоичные данные
assets/images/apim-developer-portal-CORS.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 86 KiB

После

Ширина:  |  Высота:  |  Размер: 252 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 210 KiB

После

Ширина:  |  Высота:  |  Размер: 436 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 170 KiB

После

Ширина:  |  Высота:  |  Размер: 185 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 286 KiB

После

Ширина:  |  Высота:  |  Размер: 285 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 303 KiB

После

Ширина:  |  Высота:  |  Размер: 302 KiB

Двоичные данные
assets/images/apim-developer-portal-publish.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 85 KiB

После

Ширина:  |  Высота:  |  Размер: 235 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 6.7 KiB

После

Ширина:  |  Высота:  |  Размер: 32 KiB

Двоичные данные
assets/images/apim-developer-portal-sign-in.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 28 KiB

После

Ширина:  |  Высота:  |  Размер: 26 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 47 KiB

После

Ширина:  |  Высота:  |  Размер: 99 KiB

Двоичные данные
assets/images/apim-developer-portal-signup.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 31 KiB

После

Ширина:  |  Высота:  |  Размер: 90 KiB

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше