Open API Specification
For all our micro-services, we are using Version 3.0.3 -
The OpenAPI Specification (OAS) defines a standard, language-agnostic interface to RESTful APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined, a consumer can understand and interact with the remote micro-service with a minimal amount of implementation logic
Example OAS specs for our micro-services:
card-manager micro-service: https://card-manager.apps.dev.safibank.online/swagger/card-manager.yml
customer-manger micro-service: https://customer-manager.apps.dev.safibank.online/swagger/customer-manager.yml
advanceai-gateway micro-service: https://advanceai-gateway.apps.dev.safibank.online/swagger/advanceai-gateway.yml
We are converting all the micro-services OAS -Open API Specification yml
files to json
files since the tyk-import API needs json as OAS swagger importer with the below code..and also handling all the special characters encoding with resp.encoding = resp.apparent_encoding
and appending ListenPath on the fly with yaml_output['basePath'] = str(f"/{self.name}/")
the below code can be found here: https://github.com/SafiBank/SaFiMono/blob/main/devops/scripts/tyk/api-import/tyk_api_importer.py
def swagger_json(self): try: headers = {'Accept': 'text/yaml'} resp = requests.get(self.url, headers) resp.encoding = resp.apparent_encoding if resp.status_code == 200: yaml_output = yaml.safe_load(resp.text) if 'basePath' not in yaml_output: yaml_output['basePath'] = str(f"/{self.name}/") print("[DEVOPS-INFO] - yaml safe load successful for " + self.url) self.swagger = str(json.dumps(yaml_output)) self.version_name = str(yaml_output["info"]["version"]) print("[DEVOPS-INFO] - json dumps successful for {url}".format(url=self.url)) return True else: print("[DEVOPS-ERROR] - URL {url} returned resp status_code code {status_code}".format(url=self.url, status_code=resp.status_code)) return False except Exception as e: print("[DEVOPS-ERROR] - Exception during swagger_json for URL {url}".format(url=self.url)) print("[DEVOPS-ERROR] - Exception error message{e}".format(e=e)) return False
Once we have OAS json with the above code - we need to pass this importer file to the tyk-dashboard import API https://tyk.io/docs/getting-started/import-apis/#import-apis-via-the-dashboard-api as mentioned below.
If it’s a new API we check the insert_into_api: False
and if it’s an existing API we check the insert_into_api: True
and run the Dashboard import API to import the API’s to the Tyk API Gateway
.
def swagger_import(self): if self.swagger_json(): tyk_dash_url = str(environ.get('TYK_DASH_URL')) tyk_swagger_import_url = "{tyk_dash_url}/api/import/swagger/".format(tyk_dash_url=tyk_dash_url) tyk_apis_url = "{tyk_dash_url}/api/apis".format(tyk_dash_url=tyk_dash_url) headers = { 'authorization': str(environ.get('TYK_DASH_SECRET')), 'Content-Type': 'application/json' } print("[DEVOPS-INFO] - TYK_DASH_URL " + str(environ.get('TYK_DASH_URL'))) print("[DEVOPS-INFO] - TYK_DASH_SECRET " + str(environ.get('TYK_DASH_SECRET'))) tyk_apis = requests.get(tyk_apis_url, headers=headers) if tyk_apis.status_code == 200: tyk_api = [api for api in tyk_apis.json()["apis"] if api["api_definition"]["name"] == self.name] else: print("[DEVOPS-ERROR] - TYK Dashboard {tyk_apis_url} failed with http status code: {status_code}\n\n". format(tyk_apis_url=tyk_apis_url, status_code=tyk_apis.status_code)) exit(1) if tyk_api: tyk_api_meta = tyk_api[0] print("[DEVOPS-INFO] - updating api with insert_into_api true") payload = json.dumps({ "swagger": self.swagger, "insert_into_api": True, "api_id": tyk_api_meta["api_definition"]["id"], "upstream_url": self.upstream_url }) else: print("[DEVOPS-INFO] - creating new api with insert_into_api false") payload = json.dumps({ "swagger": self.swagger, "insert_into_api": False, "upstream_url": self.upstream_url })
Code Promotion using environments
We use GHA environments to deploy the API’s to different environments - https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment
We just need to declare the two environment variables in each environment dev
, stage
and production
like below in the SaFiMono repo settings under Environments
TYK_DASH_URL
="https://tyk-dash.smallog.tech"TYK_DASH_SECRET
="0b5b572c1cad4XXYYYZZZZZ"
Code Promotion to Development Environment
First, declare TYK_DASH_URL
and TYK_DASH_SECRET
as dev
environment secrets in the github environments.
To import the APIs to development
environment automatically we have GHA workflow pipeline where we can just tag with pattern like this TYK-API-IMPORT-V*
And GHA workflow file is here: https://github.com/SafiBank/SaFiMono/blob/main/.github/workflows/tyk-api-importer.yml
[main][~/git/SaFiMono]$ git tag -a TYK-API-IMPORT-V1.0.11 -m "import apis in dev" [main][~/git/SaFiMono]$ git push origin TYK-API-IMPORT-V1.0.11 Enumerating objects: 1, done. Counting objects: 100% (1/1), done. Writing objects: 100% (1/1), 194 bytes | 194.00 KiB/s, done. Total 1 (delta 0), reused 0 (delta 0), pack-reused 0 To github.com:SafiBank/SaFiMono.git * [new tag] TYK-API-IMPORT-V1.0.11 -> TYK-API-IMPORT-V1.0.11 [main][~/git/SaFiMono]$
Once we tag like that the below job will trigger and import all the micro-services APIs to the development
environment.
jobs: tyk-api-importer-tag: if: startsWith(github.ref, 'refs/tags/TYK-API-IMPORT-') runs-on: ubuntu-latest environment: dev env: TYK_DASH_URL: ${{ secrets.TYK_DASH_URL }} TYK_DASH_SECRET: ${{ secrets.TYK_DASH_SECRET }} TYK_SCRIPT_PATH: "./devops/scripts/tyk/api-import" SERVICE_ENV: "dev" steps: - name: Check out repository code uses: actions/checkout@v3 - name: Setup python uses: actions/setup-python@v2 with: python-version: '3.8' - name: install python packages run: pip install -r ${TYK_SCRIPT_PATH}/requirements.txt - name: Execute py script for github actions trigger mode run: | service_names=$(yq ".on.push.paths[]" .github/workflows/tyk-api-importer.yml | awk -F'/' '{print $2}') python_exit_status=0 service_fail_list="" for SERVICE_NAME in ${service_names}; do echo [DEVOPS-INFO] - SERVICE_NAME: ${SERVICE_NAME} python ${TYK_SCRIPT_PATH}/tyk_api_importer.py --name=${SERVICE_NAME} --env=${SERVICE_ENV} \ --url="https://${SERVICE_NAME}.apps.${SERVICE_ENV}.safibank.online/swagger/${SERVICE_NAME}.yml" \ --upstream_url="http://${SERVICE_NAME}.apps.${SERVICE_ENV}.safibank.internal/swagger/${SERVICE_NAME}.yml" \ || (python_exit_status=1 && service_fail_list="${service_fail_list} ${SERVICE_NAME}") done [[ ${python_exit_status} -ne 0 ]] && echo [DEVOPS-ERROR] - Failed service list: ${service_fail_list} exit ${python_exit_status}
Code Promotion to stage and production environment
First, declare TYK_DASH_URL
and TYK_DASH_SECRET
as stage
and production
environment secrets in the github environments.
To import the APIs to Stage
and Production
environment we have a workflow dispatch in GHA workflow pipeline where we can just choose the Environment
and the Service Name
API
to import and run the GHA Workflow pipeline.
Attachments:
image-20220801-044749.png (image/png)
image-20220801-050832.png (image/png)
image-20220801-051621.png (image/png)
image-20220801-051717.png (image/png)
image-20220801-062621.png (image/png)
image-20220801-062651.png (image/png)