In this article, we will investigate a new technology and construct a small API endpoint to address a corporate issue of connectivity between two services.
The task: Trigger GitHub Actions from BitBucket
In a corporate environment, there’s often a challenge in communication between two different systems. Our client organization is not an exception and as they were migrating the codebase from Bitbucket to GitHub they faced a challenge to make these two services talk to each other. They wanted a simple communication: once there is a change in the code in Bitbucket, trigger the pipeline in GitHub. That was it.
There was no easy solution to this problem:
- Standard BitBucket Webhook feature can only initiate GET calls, whereas GitHub Actions APIs provide a POST endpoint to create a workflow dispatch event.
- Third-party webhook integrations, such as Bitbucket Post Webhook, may take a long time to get approval in a corporate environment, but could ultimately provide a long-term solution.
The solution: Build an intermediate REST API endpoint
As Bitbucket Webhook could only call a GET endpoint a decision was made to create a small temporary endpoint in a private corporate network that will trigger a GitHub Actions API POST endpoint.
AWS infrastructure was a given and API Gateway seemed an appropriate service.
We looked at the following options:
- Using CloudFormation seemed too much an investment for a temporary task.
- Continue building in the existing Terraform stack seemed an overkill for this task as well.
- Cloud Development Kit (CDK) seemed to be an option.
- Winglang, something we have just heard by then, seemed both too good to be true and too much of an abstraction.
After struggling for a few days with CDK, we decided to give Winglang a go and were quite surprised how efficiently it served our use case.
Winglang
Wing is a general-purpose programming language, designed to develop entire cloud applications, including their infrastructure and application code. It is an attempt to combine infrastructure and runtime code into a single language which should give developers the ability to control all aspects of backend service development and its infrastructure in one codebase.
At the time of writing, AWS support was fully implemented, while other platforms such as Azure and GCP were supported partially.
Install Winglang
Run an NPM command to install a Wing CLI tool.
Note, as of the time this was written, the requirements to run the latest version of Wing CLI (0.58.16) include Node.js version 20 or higher.
Create a new project
Run Wing CLI command to create a new sample project.
There is an experimental TypeScript support. If you want to try this, add --language ts option:
The result of the command is a sample project that includes Winglang code in main.wing as well as standard JS project configuration in a package.json.
Use Wing commands for your dev workflow
Update the package.json file with the project workflow commands: compile, init, plan, apply in the scripts section.
Compile to Terraform
Winglang uses Terraform to orchestrate cloud infrastructure, so the first step is to compile Winglang code into Terraform code. If you need to set up Terraform on your machine, please refer to the Terraform installation article.
Note, that we are using tf-aws platform as we are using AWS as our cloud provider.
After the compile command runs without any issues, it generates a new target folder. This folder contains the Terraform code for the infrastructure and the JavaScript code for the application logic.
Every time you modify Winglang code, you should run the compile command.
Initialise your Terraform project
The next step is to initialise the Terraform configuration by executing init command.
This command performs several different initialisation steps in order to prepare the current working directory for use with Terraform.
Preview your infrastructure
The terraform plan command creates an execution plan, which lets you preview the changes that Terraform plans to make to your infrastructure.
This command does not execute the proposed changes. Instead, it allows you to validate whether the suggested modifications meet your expectations before applying them.
Deploy your code to the cloud
Finally, we can deploy our changes to the cloud by running the apply command.
Build your API
To solve the missing piece in our connectivity problem, we will build a REST endpoint that will trigger GitHub Actions pipeline.
We updated main.w file to listen for a GET HTTP request and perform a PORT HTTP request to GitHub API in its handler function.
In a single Winglang file, it’s possible to combine not only the configuration for the infrastructure, but also the code that governs the logic of the application. This means that all the necessary components for our project can be consolidated and managed in one place, making it a more efficient and streamlined process.
Manage secrets
We need a security token to trigger the GitHub API. Since a security token is a sensitive information, we’ll store it as a secret.
Winglang provides a special class, cloud.secret, for working with sensitive data in the cloud. Storing a secret enables you to use its value across various compute tasks, while only needing to update or revoke it in a single location.
We will use AWS CLI to create a secret in AWS Secrets Manager by executing the command below.
To test our secret during development, we must create a secrets.json configuration file containing our secret.
Make sure that secrets.json is located at ~/.wing/secrets.json on your local system.
Put everything together
The final solution will include some response handling and will use the secret we created.
This short snippet will not only provision API Gateway instance and a Lambda function with JavaScript application code, but will also orchestrate the whole cloud infrastructure behind it:
- IAM role and policy
- VPC
- VPC Endpoint
- Elastic IP
- Security Group
- CloudWatch log group
- S3 Bucket
Test your infrastructure and application locally
Our API endpoint is now ready for testing. Winglang provides the ability to simulate and visualize your infrastructure on your local machine using Wing Console, which can be served as a web application executed locally.
You can also run Wing Console by installing a VS Code extension and execute it directly in your development environment, alongside your code.
You can test and debug your APIs by sending requests right from the Wing Console in the cloud.Api settings panel. Once we are happy with our configuration and code, we can deploy it to our cloud provider.
Deploy your project to the cloud
Once all the testing has been completed locally, we can deploy our Winglang project to the cloud.
A new Gateway API instance has been created and its endpoint is available from API settings.
Conclusion
We were truly impressed by the solution we were able to implement using Winglang. The unique ability to provision infrastructure and simultaneously write the code for the backend logic within a single codebase makes it an extraordinarily powerful and efficient development approach. This not only streamlines the entire development process but also minimizes the potential for errors, thereby enhancing productivity and reducing the time to market.
minimizesMoreover, the added feature of being able to test and debug your project before deploying it to the cloud environment is a game-changer. It virtually eliminates the risk of deploying faulty code, saving considerable effort and resources. Additionally, it allows developers to troubleshoot and fix issues in a controlled environment, thus ensuring the stability and reliability of the final product.
Source code
The source code described in this article is hosted in Winglang AWS API Gateway and available in Bear Plus GitHub space.