@ -0,0 +1,6 @@ |
|||
--- |
|||
title: "{{ replace .Name "-" " " | title }}" |
|||
date: {{ .Date }} |
|||
draft: true |
|||
--- |
|||
|
|||
@ -0,0 +1,24 @@ |
|||
baseURL = "/" |
|||
languageCode = "en-us" |
|||
theme = "learn" |
|||
|
|||
[outputs] |
|||
home = [ "HTML", "RSS", "JSON"] |
|||
|
|||
[params] |
|||
showVisitedLinks = true |
|||
disableBreadcrumb = false |
|||
disableNextPrev = false |
|||
themeVariant = "red" |
|||
openshift_console_url="https://openshift.itix.fr:8443" |
|||
microcks_url="https://microcks.app.itix.fr" |
|||
apicurio_studio_url="https://studio.apicur.io" |
|||
jenkins_url="https://jenkins-microcks.app.itix.fr" |
|||
ansible_tower_url="https://ansible.app.itix.fr" |
|||
3scale_admin_portal_url="https://rhfrance-userXY-admin.3scale.net" |
|||
3scale_developer_portal_url="https://rhfrance-userXY.3scale.net" |
|||
github_repository_url="https://github.com/nmasse-itix/api-lifecycle-workshop" |
|||
api_backend="backend-springboot" |
|||
|
|||
[blackfriday] |
|||
hrefTargetBlank = true |
|||
@ -0,0 +1,11 @@ |
|||
--- |
|||
title: "API Lifecycle Workshop" |
|||
--- |
|||
|
|||
# Welcome in this API Lifecycle Workshop! |
|||
|
|||
APIs are the cornerstone of so many recent breakthroughs: from mobile applications, to the Internet of Things, to cloud computing. All those technologies expose, consume, and are built on APIs. And those APIs are a key driver for generating new revenue. Salesforce generates 50% of its revenue through APIs, Expedia generates 90% of its, and eBay generates 60% of its. With APIs becoming so central, it becomes essential to deal with full API lifecycle management. The success of your digital transformation project depends on it! |
|||
|
|||
This workshop presents the full API lifecycle management activities that can guide you from an idea to the realization, from the inception of an API program up to management at scale throughout your whole company. |
|||
|
|||
Click the big red arrow on the right side of the screen to start with a **definition of the API Lifecyle**! |
|||
@ -0,0 +1,21 @@ |
|||
+++ |
|||
title = "Conclusion" |
|||
weight = 15 |
|||
chapter = true |
|||
pre = "<b>15. </b>" |
|||
+++ |
|||
|
|||
### Chapter 15 |
|||
|
|||
# Conclusion |
|||
|
|||
The cycles repeat, and this is at the center of both cycles. This is not by coincidence: an **API strategy** is the cornerstone of a successful API program. Knowing which goals you need to reach will help you to focus on what matters the most. |
|||
|
|||
Red Hat technologies and communities can help with full API lifecycle management. The diagram below shows tools for full API lifecycle management: |
|||
|
|||
 |
|||
|
|||
Communities such as Apicurio and Microcks will help you with the design, mock, and tests. A whole development offering such as Red Hat Fuse, Red Hat OpenShift Application Runtimes, or Red Hat CodeReady Workspaces can help you develop reliable API back ends. Red Hat Ansible Automation can help you with the Continuous Delivery of your APIs. Red Hat Single Sign-On can help secure your APIs, and Red Hat 3scale API Management handles the rest of the API lifecycle. Last but not least, Red Hat can help you define your API strategy through a service offering: the API Model Canvas. |
|||
|
|||
Red Hat OpenShift Container Platform is a the core of this lifecycle, since it is the component that brings agility and makes this approach flow more easily. |
|||
|
|||
@ -0,0 +1,12 @@ |
|||
+++ |
|||
title = "Consume" |
|||
weight = 12 |
|||
chapter = true |
|||
pre = "<b>12. </b>" |
|||
+++ |
|||
|
|||
### Chapter 12 |
|||
|
|||
# Consume |
|||
|
|||
In the **Consume** phase, client applications will start consuming your APIs and you might want to have staged plans to match their growing consumption. To ensure a high-quality user experience, you might also want to set up an application validation process to reach your production APIs—if this is part of your API strategy, of course. |
|||
@ -0,0 +1,14 @@ |
|||
+++ |
|||
title = "Deploy" |
|||
weight = 7 |
|||
chapter = true |
|||
pre = "<b>7. </b>" |
|||
+++ |
|||
|
|||
### Chapter 7 |
|||
|
|||
# Deploy |
|||
|
|||
In the **Deploy** phase, you will make sure you have a Continuous Integration/Continuous Deployment (CI/CD) pipeline that automates the delivery of your APIs to the production environment. The CI/CD pipeline reuses the tests you defined earlier to ensure the APIs to be deployed do not violate your specifications. Those integration tests are automated and run automatically as part of the pipeline. |
|||
|
|||
The automated integration tests should also ensure the backward compatibility of your APIs. If a 1.2 version of an API is released, it must be backward compatible with any release of the 1.x branch (1.0, 1.1, and so on). |
|||
@ -0,0 +1,10 @@ |
|||
--- |
|||
title: "Exercise: CI/CD" |
|||
weight: 2 |
|||
--- |
|||
|
|||
## Deploy the first implementation of the ACME Brewery API in TEST and PROD! |
|||
|
|||
The ACME Brewery API is implemented and conform to our specification. We can now envision a deployment in all the ACME environments. Unfortunatelly ACME as a lots of environments and deploying manually in each and every environment would be error prone and time consuming. It is time to think about automation and Continuous Deployment! |
|||
|
|||
TODO |
|||
@ -0,0 +1,17 @@ |
|||
--- |
|||
title: "Exercise: Create two environments" |
|||
weight: 1 |
|||
--- |
|||
|
|||
## Create two environments: TEST and PROD! |
|||
|
|||
The ACME Brewery API is implemented and conform to our specification. We can now envision a deployment in all the ACME environments. |
|||
|
|||
Let's start by provisioning a TEST and a PROD environments. |
|||
|
|||
- Open the [OpenShift Web Console]({{< param openshift_console_url >}}/console/catalog) |
|||
- In the top-left dropdown box, select the `Beer Catalog (TEST)` project |
|||
- In the top-right corner, select **Add to project**, then **Select from project**. |
|||
- Select the `Beer Catalog environment` template and click **Next** |
|||
|
|||
TODO |
|||
@ -0,0 +1,14 @@ |
|||
+++ |
|||
title = "Design" |
|||
weight = 3 |
|||
chapter = true |
|||
pre = "<b>3. </b>" |
|||
+++ |
|||
|
|||
### Chapter 3 |
|||
|
|||
# Design |
|||
|
|||
The **Design** phase will ensure your organization uses a contract-first approach. This phase entails gathering feedback early, breaking the dependencies between projects, and reducing risks. Also, a contract-first approach is known to reduce the time to market. |
|||
|
|||
In the **Design** phase, you design the contract of your API and share it with your future consumers. The outcome of the **Design** phase is an API contract that describes the messages that can be exchanged with your APIs. |
|||
@ -0,0 +1,19 @@ |
|||
--- |
|||
title: "Exercise" |
|||
weight: 1 |
|||
--- |
|||
|
|||
## Craft the API contract of the ACME Brewery API! |
|||
|
|||
The ACME brewery is about to adopt APIs **in order to expose their catalog and inventory** to the outside world. Help them design an API contract! |
|||
|
|||
- Open the [APICurio Studio]({{< param apicurio_studio_url >}}/apis/import) |
|||
- Register if you are a newcomer or login if you already have an account |
|||
- Copy [this URL](beer-catalog-1.0.json) and import it in APIcurio |
|||
- Study the existing design |
|||
- Invite one of your colleague |
|||
- **Together**, complete it with a method to place an order |
|||
|
|||
Optional, you can publish it on your GIT repository if your have one. |
|||
|
|||
To complete your understanding, explain **how the collaborative features help Developers, future Customers and the Product Owners to refine an API Contract**! |
|||
@ -0,0 +1,12 @@ |
|||
+++ |
|||
title = "Develop" |
|||
weight = 11 |
|||
chapter = true |
|||
pre = "<b>11. </b>" |
|||
+++ |
|||
|
|||
### Chapter 11 |
|||
|
|||
# Develop |
|||
|
|||
In the **Develop** phase, third parties will start discovering your APIs and developing applications based on your APIs. The user experience of those applications will depend on the quality of your APIs but also on the client applications. Make sure you are providing enough resources for developers to get the most out of your APIs. Those resources can be best practices, information on how to handle security and retries on errors, and so on. |
|||
@ -0,0 +1,12 @@ |
|||
+++ |
|||
title = "Discover" |
|||
weight = 10 |
|||
chapter = true |
|||
pre = "<b>10. </b>" |
|||
+++ |
|||
|
|||
### Chapter 10 |
|||
|
|||
# Discover |
|||
|
|||
When your APIs are deployed in production and they are “live,” you enter the **Discover** phase. In this phase, you need to help your partners and other third parties discover your APIs. Just like your corporate website is the showroom for your products and offerings, an API developer portal is a showroom for your APIs. Make sure you put as much effort into this showroom as you do for your corporate website if you want to drive revenue through APIs! |
|||
@ -0,0 +1,12 @@ |
|||
+++ |
|||
title = "Implement" |
|||
weight = 6 |
|||
chapter = true |
|||
pre = "<b>6. </b>" |
|||
+++ |
|||
|
|||
### Chapter 6 |
|||
|
|||
# Implement |
|||
|
|||
In the **Implement** phase, the actual API is **developed** using either an integration framework such as Red Hat Fuse or using the development language of your choice. Using an integration framework should be a key part of your APIs’ lifecycle to promote reuse, fast iterations, and value additions through orchestration. It also helps to modernize the existing parts of your information system. The usual agile development practices apply here. |
|||
@ -0,0 +1,23 @@ |
|||
--- |
|||
title: "Exercise: Build and deploy" |
|||
weight: 1 |
|||
--- |
|||
|
|||
## Build and deploy the first implementation of the ACME Brewery API! |
|||
|
|||
The ACME did a good job in implementing the ACME Brewery API. You can review the source code [from the GIT repository]({{< param github_repository_url >}}/tree/master/{{< param api_backend >}}). |
|||
|
|||
Let's deploy this first version in our DEV environment! |
|||
|
|||
- Open the [OpenShift Web Console]({{< param openshift_console_url >}}/console/catalog), click `SSO` and login with your username. |
|||
- Find the **Red Hat OpenJDK 8** in the catalog and click on it |
|||
- Click **Next >** |
|||
- In **Add to project**, select `Beer Catalog (DEV)` |
|||
- Choose the version 1.2 |
|||
- In **Application Name**, type `beer-catalog-impl`` |
|||
- In **Git Repository**, type `{{< param github_repository_url >}}` |
|||
- Click **view advanced options** |
|||
- In **Context Dir**, type `/{{< param api_backend >}}` |
|||
- At the bottom of the page, click **Create** |
|||
|
|||
To complete your understanding, explain **the different steps OpenShift went through to deploy the API implementation**. |
|||
@ -0,0 +1,25 @@ |
|||
--- |
|||
title: "Exercise: Test" |
|||
weight: 2 |
|||
--- |
|||
|
|||
## Test the first implementation of the ACME Brewery API! |
|||
|
|||
The ACME did a good job in implementing the ACME Brewery API and you deployed it successfully in the previous exercise. |
|||
|
|||
It is now time to run the integration tests we defined in the **Test** step to make sure our first implementation is conform to our specification. |
|||
|
|||
- Open the [OpenShift Web Console]({{< param openshift_console_url >}}/console/catalog) |
|||
- Make sure you are in the `Beer Catalog (DEV)` project (the dropdown box in the top left corner) |
|||
- Copy the public URL of your implementation |
|||
- Go to [Microcks]({{< param microcks_url >}}/#/services), click the **Details** button of the `Beer Catalog 1.0` service |
|||
- Click **New Test** |
|||
- In the **Test Endpoint**, paste the public URL of your implementation and **append `/api` to the end of the URL** |
|||
- In the **Runner** dropdown box, choose `POSTMAN` |
|||
- Click **Launch Test !** |
|||
- Wait for the test to complete |
|||
- **Is your implementation conform ?** |
|||
- Click on **Full results** |
|||
- Expand each method to discover the requests and responses exchanged during the test |
|||
|
|||
To complete your understanding, explain **how a repository of test attempts can help post-mortem analysis**. |
|||
@ -0,0 +1,12 @@ |
|||
+++ |
|||
title = "Manage" |
|||
weight = 9 |
|||
chapter = true |
|||
pre = "<b>9. </b>" |
|||
+++ |
|||
|
|||
### Chapter 9 |
|||
|
|||
# Manage |
|||
|
|||
In the **Manage** phase, after the APIs are deployed and secured, they need to be managed. This activity encompasses versioning, deprecation, and retirement. As a best practice, versioning should follow the semantic versioning scheme. This means when it is deployed, any new minor version of an API replaces the previous version. All consumers that were using the previous version are then using the latest version. When a breaking change occurs, a major version is released and deployed side by side with the previous one. Consumers can migrate from the previous version to the current one. They migrate at their own pace by adapting their code to the new version. |
|||
@ -0,0 +1,12 @@ |
|||
+++ |
|||
title = "Mock" |
|||
weight = 4 |
|||
chapter = true |
|||
pre = "<b>4. </b>" |
|||
+++ |
|||
|
|||
### Chapter 4 |
|||
|
|||
# Mock |
|||
|
|||
In the **Mock** phase, you will define meaningful payload examples of your APIs and try to refine your specifications with business expectations for common and edge cases. Those examples are then turned into a live mock that can be exposed to your first consumers. “Business expectations” entail everything that cannot be specified using a formal schema. An example could be that when querying items by status, all returned items must have the desired status. You could also think about mutually exclusive options or dependencies between fields: for example, if the field companyName is set, then the field accountType needs to be “enterprise.” |
|||
@ -0,0 +1,32 @@ |
|||
--- |
|||
title: "Exercise" |
|||
weight: 1 |
|||
--- |
|||
|
|||
## Expose a Mock of the ACME Brewery API! |
|||
|
|||
As the ACME Brewery API matures, the sales representative of the ACME Brewery already found his first customers. In this exercise, you will have to **expose a mock of the ACME Brewery API** so that future customers can start their implementation ahead and provide feedback early. |
|||
|
|||
- Install [Postman](https://www.getpostman.com/downloads/) |
|||
- Load [this collection](postman_collection.json) in Postman |
|||
- Examine the provided examples |
|||
- Discover the mocks generated by [Microcks]({{< param microcks_url >}}/#/services) |
|||
- Try to use the generated mock using the following URLs: |
|||
|
|||
```sh |
|||
curl -D - {{< param microcks_url >}}/rest/Beer+Catalog+API/1.0/beer?page=0 |
|||
``` |
|||
|
|||
```sh |
|||
curl -D - {{< param microcks_url >}}/rest/Beer+Catalog+API/1.0/beer/Weissbier |
|||
``` |
|||
|
|||
```sh |
|||
curl -D - {{< param microcks_url >}}/rest/Beer+Catalog+API/1.0/beer/findByStatus/available |
|||
``` |
|||
|
|||
```sh |
|||
curl -D - {{< param microcks_url >}}/rest/Beer+Catalog+API/1.0/beer/findByStatus/out_of_stock |
|||
``` |
|||
|
|||
To complete your understanding, explain **how the mock is generated** and **how the future customers of ACME can use it to develop their implementation ahead**. |
|||
@ -0,0 +1,12 @@ |
|||
+++ |
|||
title = "Monetize" |
|||
weight = 14 |
|||
chapter = true |
|||
pre = "<b>14. </b>" |
|||
+++ |
|||
|
|||
### Chapter 14 |
|||
|
|||
# Monetize |
|||
|
|||
As your APIs mature, so does your business model. At some point, you might be interested in billing your consumers according to their usage of your APIs; if so, this is the **Monetize** phase. A desire to monetize is especially likely if you are targeting a myriad of small third parties to benefit from a mass effect. In that case, you definitely want to have monetization with billing and payment built in. |
|||
@ -0,0 +1,14 @@ |
|||
+++ |
|||
title = "Monitor" |
|||
weight = 13 |
|||
chapter = true |
|||
pre = "<b>13. </b>" |
|||
+++ |
|||
|
|||
### Chapter 13 |
|||
|
|||
# Monitor |
|||
|
|||
After your first version has been released, you will need to prepare the next version and the one after that. This requires you to set up a kind of feedback loop to know what to improve next. This is the **Monitor** phase. |
|||
|
|||
To get accurate data in your feedback loop, you will have to monitor various aspects of your APIs. This ranges from developer engagement to API health, to API usage, and so on. The “Time to first Hello, World!” is a useful metric to track to know if your APIs are easy enough to be learned quickly by new developers. |
|||
@ -0,0 +1,12 @@ |
|||
+++ |
|||
title = "Overview" |
|||
weight = 1 |
|||
chapter = true |
|||
pre = "<b>1. </b>" |
|||
+++ |
|||
|
|||
### Chapter 1 |
|||
|
|||
# Overview |
|||
|
|||
Click the big red arrow on the right side of the screen to start with a **definition of the API Lifecyle**! |
|||
@ -0,0 +1,69 @@ |
|||
--- |
|||
title: "The API Lifecycle" |
|||
weight: 1 |
|||
--- |
|||
|
|||
*This post was originally published on the [Red Hat Developer Blog](https://developers.redhat.com/blog/2019/02/25/full-api-lifecycle-management-a-primer/)*. |
|||
|
|||
As shown below, the API lifecycle is two-fold. The leftmost cycle covers the producer activities, while the rightmost cycle covers the consumer activities. |
|||
|
|||
 |
|||
|
|||
## What are the goals for your APIs? |
|||
|
|||
Any API program has to start with a **Strategy** phase where you will have to define the goals you want to achieve with your APIs. It also specifies which markets you need to address, which resources you have at your disposal, the time frame you have in which to achieve your goals, and so on. This is a critical step to help you put effort where it matters the most. |
|||
|
|||
The **Design** phase will ensure your organization uses a contract-first approach. This phase entails gathering feedback early, breaking the dependencies between projects, and reducing risks. Also, a contract-first approach is known to reduce the time to market. |
|||
|
|||
In the **Design** phase, you design the contract of your API and share it with your future consumers. The outcome of the **Design** phase is an API contract that describes the messages that can be exchanged with your APIs. |
|||
|
|||
## Specify your APIs |
|||
|
|||
In the **Mock** phase, you will define meaningful payload examples of your APIs and try to refine your specifications with business expectations for common and edge cases. Those examples are then turned into a live mock that can be exposed to your first consumers. “Business expectations” entail everything that cannot be specified using a formal schema. An example could be that when querying items by status, all returned items must have the desired status. You could also think about mutually exclusive options or dependencies between fields: for example, if the field companyName is set, then the field accountType needs to be “enterprise.” |
|||
|
|||
In an acceptance test-driven development approach, you will have to define your test cases, based on examples, before implementing your APIs. This will help refine the business expectations about your APIs; share them between developers, testers, and business customers; and later ensure your APIs conform to those expectations. |
|||
|
|||
Here’s an example that will highlight the importance of the **Mock** and **Test** phases. If you are a retail company, you will have to return an error if someone under 21 tries to buy alcohol. That’s not something you can formally model in an API contract, but it will instead be reflected in your mocks and your tests. |
|||
|
|||
## Develop and Deploy your APIs |
|||
|
|||
Then, in the **Implement** phase, the actual API is **developed** using either an integration framework such as Red Hat Fuse or using the development language of your choice. Using an integration framework should be a key part of your APIs’ lifecycle to promote reuse, fast iterations, and value additions through orchestration. It also helps to modernize the existing parts of your information system. The usual agile development practices apply here. |
|||
|
|||
In the **Deploy** phase, you will make sure you have a Continuous Integration/Continuous Deployment (CI/CD) pipeline that automates the delivery of your APIs to the production environment. The CI/CD pipeline reuses the tests you defined earlier to ensure the APIs to be deployed do not violate your specifications. Those integration tests are automated and run automatically as part of the pipeline. |
|||
|
|||
The automated integration tests should also ensure the backward compatibility of your APIs. If a 1.2 version of an API is released, it must be backward compatible with any release of the 1.x branch (1.0, 1.1, and so on). |
|||
|
|||
The **Secure** phase is a reminder that security is a key step in the API lifecycle. Automated security testing, such as static analysis or vulnerability testing, should be part of your CD pipeline. Secure development practices, such as code reviews, a security development lifecycle, or OWASP Top 10 should also be part of your development lifecycle. |
|||
|
|||
In the **Manage** phase, after the APIs are deployed and secured, they need to be managed. This activity encompasses versioning, deprecation, and retirement. As a best practice, versioning should follow the semantic versioning scheme. This means when it is deployed, any new minor version of an API replaces the previous version. All consumers that were using the previous version are then using the latest version. When a breaking change occurs, a major version is released and deployed side by side with the previous one. Consumers can migrate from the previous version to the current one. They migrate at their own pace by adapting their code to the new version. |
|||
|
|||
This concludes the producer cycle of full API lifecycle management, and we can now speak about the consumer cycle. |
|||
|
|||
## Promote your APIs |
|||
|
|||
When your APIs are deployed in production and they are “live,” you enter the **Discover** phase. In this phase, you need to help your partners and other third parties discover your APIs. Just like your corporate website is the showroom for your products and offerings, an API developer portal is a showroom for your APIs. Make sure you put as much effort into this showroom as you do for your corporate website if you want to drive revenue through APIs! |
|||
|
|||
In the **Develop** phase, third parties will start discovering your APIs and developing applications based on your APIs. The user experience of those applications will depend on the quality of your APIs but also on the client applications. Make sure you are providing enough resources for developers to get the most out of your APIs. Those resources can be best practices, information on how to handle security and retries on errors, and so on. |
|||
|
|||
In the **Consume** phase, client applications will start consuming your APIs and you might want to have staged plans to match their growing consumption. To ensure a high-quality user experience, you might also want to set up an application validation process to reach your production APIs—if this is part of your API strategy, of course. |
|||
|
|||
## Refine your APIs |
|||
|
|||
After your first version has been released, you will need to prepare the next version and the one after that. This requires you to set up a kind of feedback loop to know what to improve next. This is the **Monitor** phase. |
|||
|
|||
To get accurate data in your feedback loop, you will have to monitor various aspects of your APIs. This ranges from developer engagement to API health, to API usage, and so on. The “Time to first Hello, World!” is a useful metric to track to know if your APIs are easy enough to be learned quickly by new developers. |
|||
|
|||
As your APIs mature, so does your business model. At some point, you might be interested in billing your consumers according to their usage of your APIs; if so, this is the **Monetize** phase. A desire to monetize is especially likely if you are targeting a myriad of small third parties to benefit from a mass effect. In that case, you definitely want to have monetization with billing and payment built in. |
|||
|
|||
## An API strategy to ensure the cycles repeat |
|||
|
|||
The cycles repeat, and this is at the center of both cycles. This is not by coincidence: an **API strategy** is the cornerstone of a successful API program. Knowing which goals you need to reach will help you to focus on what matters the most. |
|||
|
|||
Red Hat technologies and communities can help with full API lifecycle management. The diagram below shows tools for full API lifecycle management: |
|||
|
|||
 |
|||
|
|||
Communities such as Apicurio and Microcks will help you with the design, mock, and tests. A whole development offering such as Red Hat Fuse, Red Hat OpenShift Application Runtimes, or Red Hat CodeReady Workspaces can help you develop reliable API back ends. Red Hat Ansible Automation can help you with the Continuous Delivery of your APIs. Red Hat Single Sign-On can help secure your APIs, and Red Hat 3scale API Management handles the rest of the API lifecycle. Last but not least, Red Hat can help you define your API strategy through a service offering: the API Model Canvas. |
|||
|
|||
Red Hat OpenShift Container Platform is a the core of this lifecycle, since it is the component that brings agility and makes this approach flow more easily. |
|||
|
|||
@ -0,0 +1,15 @@ |
|||
--- |
|||
title: "The workshop environment" |
|||
weight: 3 |
|||
--- |
|||
|
|||
During this workshop, you will go through the different stages composing the API Full Lifecycle. |
|||
|
|||
The workshop setup is as shown in schema below. We'll use: |
|||
|
|||
* A multi-tenant `INFRA` environment to host the components used during building and deploying. Namely Apicurio, Microcks, Jenkins and Ansible Tower. |
|||
* One `DEV` environment per attendee where you will deploy your API implementation (based on Spring Boot but this is also subject to variants). |
|||
* One `TEST` environment where API implementation will be deployed once tested alongside with an API Gateway. In `TEST` environment, we primarily focus on testing/validating the API Gateway policies and configuration as well as feeding API Management system with API declaration, |
|||
* One `PROD` environment where API implementation and API Gateway configuration are promoted after having tested. On the API Management backend side, API definition should also appear as deployed onto a Production environment. |
|||
|
|||
 |
|||
@ -0,0 +1,20 @@ |
|||
--- |
|||
title: "Exercise: Discover the platform" |
|||
weight: 4 |
|||
--- |
|||
|
|||
In this exercise, we will have a look at the platform hosting this workshop and the different tools we will use throughout the whole API Lifecycle. |
|||
|
|||
Your instructor will now assign you a number. Make sure you write it down since you will need it for all exercises! |
|||
|
|||
All usernames on this platform follow the same scheme: `userXY` where `XY` is the number your instructor assigned to you. |
|||
All numbers are two digits long. So with numbers below 10, you will need to add a leading zero. |
|||
|
|||
Example: |
|||
|
|||
- if the number assigned to you is 3, your username is `user03` |
|||
- if the number assigned to you is 27, your username is `user27` |
|||
|
|||
First, open the [OpenShift Web Console]({{< param openshift_console_url >}}/console/catalog), click `SSO` and login with your username. |
|||
|
|||
Raise your hand if you have trouble to complete this step! An instructor will come help you promptly. |
|||
@ -0,0 +1,18 @@ |
|||
--- |
|||
title: "The Use Case" |
|||
weight: 2 |
|||
--- |
|||
|
|||
Before we dig in, let’s examine a use case that will help illustrate this approach through an example: the use case of ACME Inc., a local brewery. ACME produces, stores, and distributes beers to its beloved customers, and the whole process is managed in-house. |
|||
|
|||
 |
|||
*(Creative Commons licensed icons by Laymik from Noun Project)* |
|||
|
|||
The increasing competition and the growing demand of the customer base are forcing ACME to rethink its distribution model. Namely, the distribution will be left to independent resellers that could sell beers locally, online or on-site. The main challenge is how to open up the information system so that independent resellers can discover the beer catalog, check inventory, and so on. This can be done through the exposition of an API, of course. |
|||
|
|||
 |
|||
*(Creative Commons licensed icons by Laymik from Noun Project)* |
|||
|
|||
Let's help ACME to succeed in the API world! |
|||
|
|||
Source: [An API Journey: From Idea to Deployment the Agile Way–Part I, from Laurent Broudoux](https://developers.redhat.com/blog/2018/04/11/api-journey-idea-deployment-agile-part1/) |
|||
@ -0,0 +1,12 @@ |
|||
+++ |
|||
title = "Secure" |
|||
weight = 8 |
|||
chapter = true |
|||
pre = "<b>8. </b>" |
|||
+++ |
|||
|
|||
### Chapter 8 |
|||
|
|||
# Secure |
|||
|
|||
The **Secure** phase is a reminder that security is a key step in the API lifecycle. Automated security testing, such as static analysis or vulnerability testing, should be part of your CD pipeline. Secure development practices, such as code reviews, a security development lifecycle, or OWASP Top 10 should also be part of your development lifecycle. |
|||
@ -0,0 +1,14 @@ |
|||
+++ |
|||
title = "Strategy" |
|||
weight = 2 |
|||
chapter = true |
|||
pre = "<b>2. </b>" |
|||
+++ |
|||
|
|||
### Chapter 2 |
|||
|
|||
# Strategy |
|||
|
|||
Any API program has to start with a **Strategy** phase where you will have to define the goals you want to achieve with your APIs. It also specifies which markets you need to address, which resources you have at your disposal, the time frame you have in which to achieve your goals, and so on. This is a critical step to help you put effort where it matters the most. |
|||
|
|||
Learn how to craft an API Strategy with **the next exercise**! |
|||
@ -0,0 +1,24 @@ |
|||
--- |
|||
title: "Exercise" |
|||
weight: 1 |
|||
--- |
|||
|
|||
## Find an API strategy for the ACME Brewery! |
|||
|
|||
The ACME brewery is about to change their business model to adopt APIs. Using the API Canvas Model, help them craft their API Strategy! |
|||
|
|||
Complete the API Model Canvas with the relevant information for ACME: |
|||
|
|||
- **Description of the API:** `__________________` |
|||
- **API high level Design:** `__________________` |
|||
- **Strategy and Objectives for the API:** `__________________` |
|||
- **Key Partners, Activities and Resources:** `__________________` |
|||
- **Developer Relations:** `__________________` |
|||
- **Developer Program:** `__________________` |
|||
- **Developer Segmentation, Targeting and Positioning:** `__________________` |
|||
- **Cost Structure:** `__________________` |
|||
- **In-flow Metrics:** `__________________` |
|||
|
|||
 |
|||
|
|||
To complete your understanding, explain **how the API Canvas Model helps in finding an API Strategy**! |
|||
@ -0,0 +1,14 @@ |
|||
+++ |
|||
title = "Test" |
|||
weight = 5 |
|||
chapter = true |
|||
pre = "<b>5. </b>" |
|||
+++ |
|||
|
|||
### Chapter 5 |
|||
|
|||
# Test |
|||
|
|||
In an acceptance test-driven development approach, you will have to define your test cases, based on examples, before implementing your APIs. This will help refine the business expectations about your APIs; share them between developers, testers, and business customers; and later ensure your APIs conform to those expectations. |
|||
|
|||
Here’s an example that will highlight the importance of the **Mock** and **Test** phases. If you are a retail company, you will have to return an error if someone under 21 tries to buy alcohol. That’s not something you can formally model in an API contract, but it will instead be reflected in your mocks and your tests. |
|||
@ -0,0 +1,14 @@ |
|||
--- |
|||
title: "Exercise" |
|||
weight: 1 |
|||
--- |
|||
|
|||
## Craft an integration test suite for the ACME Brewery API! |
|||
|
|||
The ACME Brewery is about to start implementing the ACME Brewery API but before jumping into the code, we will have to craft an integration test suite. This way, we can refine the business expectations and validate that our implementation, once developed, conforms to our specifications. |
|||
|
|||
- Load [this collection](postman_collection.json) in Postman, if not already done |
|||
- Examine the provided test cases |
|||
- Try to run a test in [Microcks]({{< param microcks_url >}}/#/services) against the generated mock |
|||
|
|||
To complete your understanding, explain **for what purpose do we define tests before writing the implementation**. |
|||
@ -0,0 +1 @@ |
|||
<a href="/"><img src="/images/logo.png" /></a> |
|||
@ -0,0 +1,144 @@ |
|||
{ |
|||
"swagger": "2.0", |
|||
"info": { |
|||
"title": "Beer Catalog API", |
|||
"description": "An API for querying beer catalog of Acme Inc.", |
|||
"contact": { |
|||
"name": "Laurent Broudoux", |
|||
"url": "http://github.com/lbroudoux", |
|||
"email": "laurent.broudoux@gmail.com" |
|||
}, |
|||
"license": { |
|||
"name": "MIT License", |
|||
"url": "https://opensource.org/licenses/MIT" |
|||
}, |
|||
"version": "1.0" |
|||
}, |
|||
"paths": { |
|||
"/beer/{name}": { |
|||
"get": { |
|||
"tags": [ |
|||
"beer" |
|||
], |
|||
"summary": "Get beer having name", |
|||
"description": "Get beer having name", |
|||
"operationId": "GetBeer", |
|||
"responses": { |
|||
"200": { |
|||
"description": "Beer having requested name", |
|||
"schema": { |
|||
"$ref": "#/definitions/Beer" |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"parameters": [ |
|||
{ |
|||
"name": "name", |
|||
"in": "path", |
|||
"description": "Name of beer to retrieve", |
|||
"required": true, |
|||
"type": "string" |
|||
} |
|||
] |
|||
}, |
|||
"/beer/findByStatus/{status}": { |
|||
"get": { |
|||
"tags": [ |
|||
"beer" |
|||
], |
|||
"summary": "Get beers having status", |
|||
"description": "Get beers having status", |
|||
"operationId": "FindBeersByStatus", |
|||
"responses": { |
|||
"200": { |
|||
"description": "List of beers having requested status", |
|||
"schema": { |
|||
"type": "array", |
|||
"items": { |
|||
"$ref": "#/definitions/Beer" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"parameters": [ |
|||
{ |
|||
"name": "status", |
|||
"in": "path", |
|||
"description": "Status of beers to retrieve", |
|||
"required": true, |
|||
"type": "string" |
|||
}, |
|||
{ |
|||
"name": "page", |
|||
"in": "query", |
|||
"description": "Number of page to retrieve", |
|||
"type": "number" |
|||
} |
|||
] |
|||
}, |
|||
"/beer": { |
|||
"get": { |
|||
"tags": [ |
|||
"beer" |
|||
], |
|||
"summary": "List beers within catalog", |
|||
"description": "List beers within catalog", |
|||
"operationId": "ListBeers", |
|||
"responses": { |
|||
"200": { |
|||
"description": "Array of beers", |
|||
"schema": { |
|||
"type": "array", |
|||
"items": { |
|||
"$ref": "#/definitions/Beer" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"parameters": [ |
|||
{ |
|||
"name": "page", |
|||
"in": "query", |
|||
"description": "Number of page to retrieve", |
|||
"type": "number" |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
"tags": [ |
|||
{ |
|||
"name": "beer", |
|||
"description": "Beer resource" |
|||
} |
|||
], |
|||
"definitions": { |
|||
"Beer": { |
|||
"properties": { |
|||
"name": { |
|||
"description": "Name of Beer", |
|||
"type": "string" |
|||
}, |
|||
"country": { |
|||
"description": "Origin country of Beer", |
|||
"type": "string" |
|||
}, |
|||
"type": { |
|||
"description": "Type of Beer", |
|||
"type": "string" |
|||
}, |
|||
"rating": { |
|||
"description": "Rating from customers", |
|||
"type": "number" |
|||
}, |
|||
"status": { |
|||
"description": "Stock status", |
|||
"type": "string" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 76 KiB |
@ -0,0 +1,369 @@ |
|||
{ |
|||
"variables": [], |
|||
"info": { |
|||
"name": "Beer Catalog API", |
|||
"_postman_id": "7194f912-d5f5-3ca0-cf75-8a0b912abc4e", |
|||
"description": "version=1.0 - An API for querying beer catalog of Acme Inc.", |
|||
"schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" |
|||
}, |
|||
"item": [ |
|||
{ |
|||
"name": "beer", |
|||
"description": "Folder for beer", |
|||
"item": [ |
|||
{ |
|||
"name": "Get beer having name", |
|||
"event": [ |
|||
{ |
|||
"listen": "test", |
|||
"script": { |
|||
"type": "text/javascript", |
|||
"exec": [ |
|||
"var expectedName = globals[\"name\"];", |
|||
"var jsonData = JSON.parse(responseBody);", |
|||
"", |
|||
"var schema = {", |
|||
" \"type\": \"object\",", |
|||
" \"properties\": {", |
|||
" \"name\": { \"type\": \"string\", \"enum\": [expectedName] },", |
|||
" \"country\": { \"type\": \"string\" },", |
|||
" \"type\": { \"type\": \"string\" },", |
|||
" \"rating\": { \"type\": \"number\" },", |
|||
" \"status\": { \"type\": \"string\" }", |
|||
" }", |
|||
"};", |
|||
"", |
|||
"tests[\"Valid name in response\"] = tv4.validate(jsonData, schema);" |
|||
] |
|||
} |
|||
} |
|||
], |
|||
"request": { |
|||
"url": { |
|||
"raw": "http:///beer/:name", |
|||
"host": [ |
|||
"http:" |
|||
], |
|||
"port": "", |
|||
"path": [ |
|||
"", |
|||
"", |
|||
"beer", |
|||
":name" |
|||
], |
|||
"query": [], |
|||
"variable": [ |
|||
{ |
|||
"description": "", |
|||
"key": "name", |
|||
"value": "" |
|||
} |
|||
] |
|||
}, |
|||
"method": "GET", |
|||
"header": [], |
|||
"body": {}, |
|||
"description": "Get beer having name" |
|||
}, |
|||
"response": [ |
|||
{ |
|||
"id": "809e4ade-2462-454b-b8de-880f520e8c79", |
|||
"name": "Rodenbach", |
|||
"originalRequest": { |
|||
"url": { |
|||
"raw": "http:///beer/:name", |
|||
"host": [ |
|||
"http:" |
|||
], |
|||
"port": "", |
|||
"path": [ |
|||
"", |
|||
"", |
|||
"beer", |
|||
":name" |
|||
], |
|||
"query": [], |
|||
"variable": [ |
|||
{ |
|||
"description": "", |
|||
"key": "name", |
|||
"value": "Rodenbach" |
|||
} |
|||
] |
|||
}, |
|||
"method": "GET", |
|||
"header": [], |
|||
"body": {} |
|||
}, |
|||
"status": "OK", |
|||
"code": 200, |
|||
"_postman_previewlanguage": "json", |
|||
"_postman_previewtype": "parsed", |
|||
"header": [], |
|||
"cookie": [], |
|||
"responseTime": 0, |
|||
"body": "{\"name\": \"Rodenbach\", \"country\": \"Belgium\", \"type\": \"Brown ale\", \"rating\": 4.2, \"status\": \"available\"}" |
|||
}, |
|||
{ |
|||
"id": "b205add4-5386-4c79-a38c-61cd75a94435", |
|||
"name": "Weissbier", |
|||
"originalRequest": { |
|||
"url": { |
|||
"raw": "http:///beer/:name", |
|||
"host": [ |
|||
"http:" |
|||
], |
|||
"port": "", |
|||
"path": [ |
|||
"", |
|||
"", |
|||
"beer", |
|||
":name" |
|||
], |
|||
"query": [], |
|||
"variable": [ |
|||
{ |
|||
"description": "", |
|||
"key": "name", |
|||
"value": "Weissbier" |
|||
} |
|||
] |
|||
}, |
|||
"method": "GET", |
|||
"header": [], |
|||
"body": {} |
|||
}, |
|||
"status": "OK", |
|||
"code": 200, |
|||
"_postman_previewlanguage": "json", |
|||
"_postman_previewtype": "parsed", |
|||
"header": [], |
|||
"cookie": [], |
|||
"responseTime": 0, |
|||
"body": "{\n \"name\": \"Weissbier\",\n \"country\": \"Germany\",\n \"type\": \"Wheat\",\n \"rating\": 4.1,\n \"status\": \"out_of_stock\"\n}" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"name": "Get beers having status", |
|||
"event": [ |
|||
{ |
|||
"listen": "test", |
|||
"script": { |
|||
"type": "text/javascript", |
|||
"exec": [ |
|||
"var expectedStatus = globals[\"status\"];", |
|||
"var jsonData = JSON.parse(responseBody);", |
|||
"", |
|||
"var schema = {", |
|||
" \"type\": \"array\",", |
|||
" \"items\": {", |
|||
" \"type\": \"object\",", |
|||
" \"properties\": {", |
|||
" \"name\": { \"type\": \"string\" },", |
|||
" \"country\": { \"type\": \"string\" },", |
|||
" \"type\": { \"type\": \"string\" },", |
|||
" \"rating\": { \"type\": \"number\" },", |
|||
" \"status\": { \"type\": \"string\", \"enum\": [expectedStatus] }", |
|||
" }", |
|||
" }", |
|||
"};", |
|||
"", |
|||
"tests[\"Valid response\"] = tv4.validate(jsonData, schema);" |
|||
] |
|||
} |
|||
} |
|||
], |
|||
"request": { |
|||
"url": { |
|||
"raw": "http:///beer/findByStatus/:status", |
|||
"host": [ |
|||
"http:" |
|||
], |
|||
"port": "", |
|||
"path": [ |
|||
"", |
|||
"", |
|||
"beer", |
|||
"findByStatus", |
|||
":status" |
|||
], |
|||
"query": [], |
|||
"variable": [ |
|||
{ |
|||
"key": "status", |
|||
"value": "" |
|||
} |
|||
] |
|||
}, |
|||
"method": "GET", |
|||
"header": [], |
|||
"body": {}, |
|||
"description": "Get beers having status" |
|||
}, |
|||
"response": [ |
|||
{ |
|||
"id": "2cef0eba-abe8-468e-8dc9-0731f5758b52", |
|||
"name": "Get available beers", |
|||
"originalRequest": { |
|||
"url": { |
|||
"raw": "http:///beer/findByStatus/:status", |
|||
"host": [ |
|||
"http:" |
|||
], |
|||
"port": "", |
|||
"path": [ |
|||
"", |
|||
"", |
|||
"beer", |
|||
"findByStatus", |
|||
":status" |
|||
], |
|||
"query": [], |
|||
"variable": [ |
|||
{ |
|||
"description": "", |
|||
"key": "status", |
|||
"value": "available" |
|||
} |
|||
] |
|||
}, |
|||
"method": "GET", |
|||
"header": [], |
|||
"body": {} |
|||
}, |
|||
"status": "OK", |
|||
"code": 200, |
|||
"_postman_previewlanguage": "json", |
|||
"_postman_previewtype": "parsed", |
|||
"header": [], |
|||
"cookie": [], |
|||
"responseTime": 0, |
|||
"body": "[{\"name\": \"Rodenbach\", \"country\": \"Belgium\", \"type\": \"Brown ale\", \"rating\": 4.2, \"status\": \"available\"},\n{\"name\": \"Westmalle Triple\", \"country\": \"Belgium\", \"type\": \"Trappist\", \"rating\": 3.8, \"status\": \"available\"}]" |
|||
}, |
|||
{ |
|||
"id": "5b0ccc56-539d-428c-8334-d641a900b60e", |
|||
"name": "Get out_of_stock beers", |
|||
"originalRequest": { |
|||
"url": { |
|||
"raw": "http:///beer/findByStatus/:status", |
|||
"host": [ |
|||
"http:" |
|||
], |
|||
"port": "", |
|||
"path": [ |
|||
"", |
|||
"", |
|||
"beer", |
|||
"findByStatus", |
|||
":status" |
|||
], |
|||
"query": [], |
|||
"variable": [ |
|||
{ |
|||
"description": "", |
|||
"key": "status", |
|||
"value": "out_of_stock" |
|||
} |
|||
] |
|||
}, |
|||
"method": "GET", |
|||
"header": [], |
|||
"body": {} |
|||
}, |
|||
"status": "OK", |
|||
"code": 200, |
|||
"_postman_previewlanguage": "json", |
|||
"_postman_previewtype": "parsed", |
|||
"header": [], |
|||
"cookie": [], |
|||
"responseTime": 0, |
|||
"body": "[{\"name\": \"Weissbier\", \"country\": \"Germany\", \"type\": \"Wheat\", \"rating\": 4.1, \"status\": \"out_of_stock\"}]" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"name": "List beers within catalog", |
|||
"event": [ |
|||
{ |
|||
"listen": "test", |
|||
"script": { |
|||
"type": "text/javascript", |
|||
"exec": [ |
|||
"tests[\"Status code is OK\"] = (responseCode.code === 200 || responseCode.code === 404);" |
|||
] |
|||
} |
|||
} |
|||
], |
|||
"request": { |
|||
"url": { |
|||
"raw": "http:///beer?page={{page}}", |
|||
"host": [ |
|||
"http:" |
|||
], |
|||
"port": "", |
|||
"path": [ |
|||
"", |
|||
"", |
|||
"beer" |
|||
], |
|||
"query": [ |
|||
{ |
|||
"key": "page", |
|||
"value": "{{page}}", |
|||
"equals": true, |
|||
"description": "" |
|||
} |
|||
], |
|||
"variable": [] |
|||
}, |
|||
"method": "GET", |
|||
"header": [], |
|||
"body": {}, |
|||
"description": "List beers within catalog" |
|||
}, |
|||
"response": [ |
|||
{ |
|||
"id": "6941bfe0-0e27-4ee6-a244-f03dfca6fe25", |
|||
"name": "List page 0", |
|||
"originalRequest": { |
|||
"url": { |
|||
"raw": "http:///beer?page=0", |
|||
"host": [ |
|||
"http:" |
|||
], |
|||
"port": "", |
|||
"path": [ |
|||
"", |
|||
"", |
|||
"beer" |
|||
], |
|||
"query": [ |
|||
{ |
|||
"key": "page", |
|||
"value": "0", |
|||
"equals": true, |
|||
"description": "" |
|||
} |
|||
], |
|||
"variable": [] |
|||
}, |
|||
"method": "GET", |
|||
"header": [], |
|||
"body": {} |
|||
}, |
|||
"status": "OK", |
|||
"code": 200, |
|||
"_postman_previewlanguage": "json", |
|||
"_postman_previewtype": "parsed", |
|||
"header": [], |
|||
"cookie": [], |
|||
"responseTime": 0, |
|||
"body": "[\n {\n \"name\": \"Rodenbach\",\n \"country\": \"Belgium\",\n \"type\": \"Brown ale\",\n \"rating\": 4.2,\n \"status\": \"available\"\n },\n {\n \"name\": \"Westmalle Triple\",\n \"country\": \"Belgium\",\n \"type\": \"Trappist\",\n \"rating\": 3.8,\n \"status\": \"available\"\n },\n {\n \"name\": \"Weissbier\",\n \"country\": \"Germany\",\n \"type\": \"Wheat\",\n \"rating\": 4.1,\n \"status\": \"out_of_stock\"\n }\n]" |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 375 KiB |
|
After Width: | Height: | Size: 290 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 145 KiB |
|
After Width: | Height: | Size: 114 KiB |