<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mostafa Moradian</title>
    <description>The latest articles on DEV Community by Mostafa Moradian (@mostafa).</description>
    <link>https://dev.to/mostafa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F180580%2F1b77323c-3777-4503-ac10-054bc117a630.jpg</url>
      <title>DEV Community: Mostafa Moradian</title>
      <link>https://dev.to/mostafa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mostafa"/>
    <language>en</language>
    <item>
      <title>GatewayD: The Case For A Database Gateway</title>
      <dc:creator>Mostafa Moradian</dc:creator>
      <pubDate>Tue, 05 Sep 2023 09:26:41 +0000</pubDate>
      <link>https://dev.to/gatewayd/gatewayd-the-case-for-a-database-gateway-5edb</link>
      <guid>https://dev.to/gatewayd/gatewayd-the-case-for-a-database-gateway-5edb</guid>
      <description>&lt;p&gt;It has been a year and a half since I embarked on the journey of bringing my long-standing idea to life. This idea had been lying dormant on my list of projects, but I finally decided to develop a database gateway tailored for building data-driven applications. Yes, you read it correctly: a database gateway. Allow me to explain briefly.&lt;/p&gt;

&lt;p&gt;The entire project has been carried out in stealth mode, with only a select few witnessing the product demo. During the initial phase, I dedicated three intense months to delve into various database technologies, meticulously examining their internals and understanding the specific needs of users. This extensive reading, research, and investigation allowed me to gain valuable insights and prioritize what truly matters. As a developer myself, I focused on addressing the challenges and demands that I encounter daily, ensuring that the final product caters to my needs effectively.&lt;/p&gt;

&lt;p&gt;After spending quite some time on the initial PoC and then the MVP, I had the opportunity to participate in the &lt;a href="https://2023.nordicpgday.org/"&gt;Nordic PgDay 2023&lt;/a&gt;, where I gathered substantial validation for my idea. Throughout the event, I diligently took note of (almost) forty distinct pain points, which I identified while attending talks, workshops, and engaging with professionals possessing diverse levels of expertise. Among the attendees were PostgreSQL maintainers, developers, DBAs, and enthusiasts. I intend to share my findings in a separate post. However, for now, let’s shift our attention to exploring the core aspects of the idea itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;In the vast database world, we encounter numerous layers and actors, but it appears that some areas receive less attention compared to other segments of software engineering and development. One particular aspect of concern is the realm of APIs.&lt;/p&gt;

&lt;p&gt;When it comes to HTTP-based APIs, such as REST, gRPC, and GraphQL, we find a plethora of well-established technologies that effectively expose data and functionality to the outside world. An extensive array of supporting tools, including frameworks, webservers, documentation, testing, mocking, versioning, monitoring, security, gateways, load-balancers, and analytics, have evolved to complement these APIs. On the other hand, when we delve into the database realm, we observe that some tools are not as mature as their counterparts. This disparity can be attributed to the unique nature of the databases and varying degrees of attention received by different aspects and parties.&lt;/p&gt;

&lt;p&gt;An exemplary illustration of well-developed API-related tools lies in API gateways. These software components sit between clients and servers, offering a range of functionalities like security, monitoring, analytics, load-balancing, caching, and scalability support. Over the years, numerous API gateways have matured and become highly efficient. They excel at intercepting traffic and performing their magic to enhance the API experience.&lt;/p&gt;

&lt;p&gt;It is precisely at this point where the concept of a database gateway emerges. Inspired by the success of API gateways, a database gateway serves as an intermediary, bridging the gap between users and the database. Just as API gateways offer a wealth of benefits for APIs, a well-designed database gateway could potentially address the current gaps and bring significant improvements in the database realm. By emulating the magic of API gateways for databases, we can explore new possibilities and unlock greater potential in data management and utilization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing GatewayD: The Database Gateway Solution
&lt;/h2&gt;

&lt;p&gt;The solution to address the existing database challenges involves the implementation of a database gateway, strategically positioned between clients and databases. With its traffic-intercepting capabilities, this software piece performs its magic to bring forth a range of benefits. From ensuring security and monitoring to enabling analytics, load-balancing, caching, scalability, and various other use cases, the database gateway emerges as a versatile tool.&lt;/p&gt;

&lt;p&gt;GatewayD, akin to an API gateway for databases, embodies the very essence of this solution, aiming to tackle the issues mentioned earlier. Comprising several key components, as shown in the below high-level architecture, GatewayD sets out to revolutionize the database landscape:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GatewayD Core (CLI)&lt;/strong&gt;: At the heart of the architecture lies the GatewayD core, positioned between clients and databases, effectively intercepting traffic. Serving as a database-agnostic TCP proxy, it is meticulously crafted in Go and designed to be extensible through plugins. This core component has the exceptional capability to serve multiple databases seamlessly, simplifying the management of plugins through automated installation and management.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GatewayD Plugins&lt;/strong&gt;: GatewayD boasts an array of dynamic plugins that enhance its functionality. Crafted in Go, these plugins are loaded at runtime, catering to diverse use cases. The following section will provide further insights into the diverse possibilities these plugins offer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GatewayD SDK&lt;/strong&gt;: To facilitate the development of plugins, the GatewayD SDK provides a collection of Go utility libraries. These robust tools enable developers to create plugins efficiently, fostering innovation and versatility.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GatewayD Plugin Template(s)&lt;/strong&gt;: Emphasizing efficiency and simplicity, GatewayD offers template projects. Developers can rapidly bootstrap and develop Go-based plugins using these templates. Leveraging the power of gRPC, a GatewayD plugin can be written in any language supporting gRPC. Presently, Go is fully supported, and a Python PoC template is also developed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CXoX2_RV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rogfd7esh67hx63kbz3k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CXoX2_RV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rogfd7esh67hx63kbz3k.png" alt="GatewayD high-level architecture" width="800" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Unleashing the Power of GatewayD: Addressing Critical Database Issues
&lt;/h2&gt;

&lt;p&gt;In a manner akin to API gateways, GatewayD empowers users through its plugin system, offering the flexibility to develop customized solutions to tackle pressing database challenges. By harnessing the potential of these plugins, GatewayD aims to address various crucial issues faced in the database world:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;High Total Cost of Ownership (TCO)&lt;/strong&gt;: GatewayD seeks to alleviate the total cost of database ownership significantly. By automating tasks and reducing complexity, it curtails expenses related to maintenance, staff, on-premises hardware, cloud infrastructure, migration, and other associated costs. A streamlined approach helps optimize resource utilization and enhances operational efficiency, ultimately leading to cost savings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vendor Lock-In&lt;/strong&gt;: Promoting vendor neutrality, GatewayD aims to support multiple databases, allowing seamless migration from one database to another. By facilitating a smooth transition between databases, it liberates users from vendor lock-in, empowering them with the freedom to choose the most suitable database solution for their needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security and Privacy Enhancement&lt;/strong&gt;: GatewayD puts a strong focus on bolstering database security and privacy. With capabilities to detect and prevent SQL injection attacks, encrypt data in transit, anonymize and manage data, among other features, it ensures that sensitive information remains well-protected, safeguarding against potential threats and unauthorized access.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability Boost&lt;/strong&gt;: Emphasizing the importance of scalability, GatewayD strives to enhance the performance of databases. Through scalable solutions, including horizontal scaling, it empowers databases to handle increasing workloads, ensuring smooth operations as demands grow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reducing Inherent Complexities (Black-Box Mentality)&lt;/strong&gt;: GatewayD is dedicated to simplifying the complexities often associated with databases. Its innovative approach automates tasks for developers, DBAs, and SREs, streamlining the database management process and making it more accessible to all stakeholders. By lifting the veil on the black-box mentality, GatewayD empowers users to have greater control and understanding of their databases.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;GatewayD aims to revolutionize the database ecosystem, providing a powerful solution to elevate the efficiency, reliability, and extensibility of database operations. With its dynamic plugin architecture and extensive capabilities, GatewayD opens the door to a new era of streamlined database management and enhanced data utilization.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The GatewayD Features
&lt;/h2&gt;

&lt;p&gt;GatewayD core boasts a wide range of features, making it a versatile and powerful TCP proxy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Connection Pooling and Proxying&lt;/strong&gt;: GatewayD efficiently pools connections to database servers, effectively proxying them to clients. Additionally, it manages connections to clients and proxies them to database servers. This intelligent pooling mechanism optimizes resource utilization and enhances performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database-Agnostic&lt;/strong&gt;: GatewayD is designed to be database-agnostic, offering seamless compatibility with various databases. PostgreSQL is the current focus, yet we have plans to support MySQL-based databases. This inherent flexibility enables easy extension to support different database systems, enhancing its adaptability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Plugin-Based and Extensible&lt;/strong&gt;: GatewayD’s innovative plugin-based architecture allows for limitless possibilities. Developers can craft custom plugins to expand the functionality of GatewayD, tailoring it to meet unique requirements and use cases. This extensibility ensures GatewayD remains future-proof and adaptable to evolving needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-Tenancy Support&lt;/strong&gt;: GatewayD excels at serving multiple databases simultaneously, providing a multi-tenant environment. This capability fosters efficient resource sharing, allowing users to manage multiple databases with ease.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observability&lt;/strong&gt;: GatewayD prioritizes observability, enabling users to gain insights into its internal workings and the functioning of its plugins. Comprehensive observability features, including logs, metrics, and tracing, empower users with valuable data to monitor and analyze GatewayD’s performance effectively.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So far I’ve implemented two plugins, and I am working on a few more. These plugins are developed for PostgreSQL, but they can be extended to other databases as well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://docs.gatewayd.io/plugins/gatewayd-plugin-cache"&gt;gatewayd-plugin-cache&lt;/a&gt; (OSS)&lt;/strong&gt;: Transparent caching in Redis for PostgreSQL with automatic cache invalidation based on incoming queries and TTL&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.gatewayd.io/products/advanced-cache/"&gt;gatewayd-plugin-cache-advanced&lt;/a&gt; (Enterprise)&lt;/strong&gt;: Transparent caching in Redis for PostgreSQL with advanced features like WAL-based invalidation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.gatewayd.io/products/sql-ids-ips/"&gt;gatewayd-plugin-sql-ids-ips&lt;/a&gt; (Enterprise)&lt;/strong&gt;: Detecting and preventing SQL injection attack for PostgreSQL using deep learning and other techniques&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Competitive Landscape
&lt;/h2&gt;

&lt;p&gt;In the realm of database gateway solutions, several notable competitors hold their ground, each with its unique use cases and advantages. Below, I’ll provide factual information on some prominent contenders that I’ve investigated:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Connection Poolers:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PgBouncer&lt;/strong&gt;: A lightweight connection pooler specifically designed for PostgreSQL. It excels at pooling connections to PostgreSQL but is limited to this database only. PgBouncer operates as a single-threaded solution and lacks extensibility and plugin support. Despite these limitations, it remains a popular choice for efficiently managing PostgreSQL connections, and providing valuable features.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pgpool-II&lt;/strong&gt;: Functioning as a middleware, Pgpool-II operates between PostgreSQL servers and database clients. It effectively pools connections to PostgreSQL, offering a range of other features. Similar to PgBouncer, it lacks extensibility and plugin support, and its scope is confined to PostgreSQL.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Database Proxies:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ProxySQL&lt;/strong&gt;: As a high-performance SQL proxy, ProxySQL provides robust features but is not extensible and lacks plugin support. It exclusively supports MySQL, making it an excellent choice for MySQL users seeking enhanced performance and capabilities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MaxScale&lt;/strong&gt;: This database proxy supports multiple database servers, including MySQL and MariaDB. Notably, MaxScale stands out due to its extensibility, allowing for customization through C/C++ development. Its versatility makes it a preferred choice for users with heterogeneous database environments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Acra&lt;/strong&gt;: Positioned as a comprehensive database security suite, Acra offers encryption, access control, data masking, and intrusion detection features. Although it lacks extensibility and plugin support, it provides valuable security enhancements for both PostgreSQL and MySQL.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. General Purpose Proxies:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HAProxy&lt;/strong&gt;: Renowned for its reliability, HAProxy provides high availability, load balancing, and proxying for TCP and HTTP-based applications. While not equipped with traditional plugins, HAProxy supports extensibility through Lua scripting. Furthermore, its database-agnostic nature allows seamless integration with various databases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s not overlook the remarkable contributions of Vitess and Citus, both of which have significantly enhanced MySQL and PostgreSQL’s scalability to unprecedented levels. These powerful extensions have revolutionized the way we handle data, opening up new horizons for scaling our databases like never before.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How-Tos&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Install and Use GatewayD&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;GatewayD is available as a &lt;a href="https://github.com/gatewayd-io/gatewayd/pkgs/container/gatewayd"&gt;Docker image&lt;/a&gt; and can be installed using Docker. It can also be installed using &lt;a href="https://github.com/gatewayd-io/gatewayd/releases"&gt;the binary releases&lt;/a&gt; for Linux, macOS and Windows. It can also be &lt;a href="https://docs.gatewayd.io/getting-started/installation/#building-gatewayd-from-source"&gt;built from source&lt;/a&gt;. Please refer to the &lt;a href="https://docs.gatewayd.io/getting-started/installation"&gt;installation guide&lt;/a&gt; for more information.&lt;/p&gt;

&lt;p&gt;A typical use case is to use GatewayD as a transparent cache for PostgreSQL, which is explained in &lt;a href="https://docs.gatewayd.io/getting-started/running-gatewayd/"&gt;this guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;GatewayD is configured using a YAML files. There are two configuration files: one for the core and one for the plugins. Please refer to the &lt;a href="https://docs.gatewayd.io/using-gatewayd/configuration"&gt;configuration guide&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Develop Plugins&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;GatewayD plugins can be developed using the GatewayD &lt;a href="https://github.com/gatewayd-io/plugin-template-go"&gt;Go plugin template&lt;/a&gt;. A &lt;a href="https://github.com/gatewayd-io/plugin-template-python"&gt;Python plugin template&lt;/a&gt; is in the works. Please refer to the &lt;a href="https://docs.gatewayd.io/developing-plugins/plugin-developers-guide"&gt;plugin developers guide&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Contribute&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;GatewayD is an open-source project and contributions are welcome. Please refer to the &lt;a href="https://github.com/gatewayd-io/gatewayd/blob/main/CONTRIBUTING.md"&gt;contributing guide&lt;/a&gt; for more information. &lt;a href="https://github.com/gatewayd-io/proposals"&gt;Proposals&lt;/a&gt; are also welcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I hope I could explain the idea behind GatewayD and how it can be used to solve some of the problems we face in the database world. I am working on a few more plugins and will share them in the coming weeks and months. I am also working on more features for GatewayD core. I’ll share more information about them in the coming weeks. The project is still in beta, and we need beta testers to help find issues.&lt;/p&gt;

&lt;p&gt;GatewayD Cloud is also in the works and will be available soon-ish. It is a managed service for GatewayD that can be used to deploy and manage GatewayD instances. It can also be used to manage plugins and other related services. Stay tuned!&lt;/p&gt;

</description>
      <category>database</category>
      <category>postgres</category>
      <category>gatewayd</category>
      <category>gateway</category>
    </item>
    <item>
      <title>Load Testing Your API with Postman</title>
      <dc:creator>Mostafa Moradian</dc:creator>
      <pubDate>Mon, 20 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/k6/load-testing-your-api-with-postman-3fgh</link>
      <guid>https://dev.to/k6/load-testing-your-api-with-postman-3fgh</guid>
      <description>&lt;p&gt;In this article, I'll explain how to use a Postman collection I have created to load test our instance of our test API. The process is pretty straightforward, as is shown below. You need to feed your exported Postman collection to our postman-to-k6 converter, and use the generated k6 script to load test your own API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# convert postman collection to k6 test&lt;/span&gt;
postman-to-k6 test-api.json &lt;span class="nt"&gt;-e&lt;/span&gt; env.json &lt;span class="nt"&gt;-o&lt;/span&gt; k6-script.js

&lt;span class="c"&gt;# run load test&lt;/span&gt;
k6 run &lt;span class="nt"&gt;--vus&lt;/span&gt; 100 &lt;span class="nt"&gt;--duration&lt;/span&gt; 5m k6-script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Our Test API &amp;amp; Its Testing Scenario
&lt;/h2&gt;

&lt;p&gt;In order to demonstrate the power of k6 in different scenarios, we have created our test API with various example endpoints, which is available at &lt;a href="https://test-api.k6.io"&gt;test-api.k6.io&lt;/a&gt;. These endpoints are available in the Postman collection:&lt;/p&gt;

&lt;h3&gt;
  
  
  Public APIs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;List all public crocodiles&lt;/li&gt;
&lt;li&gt;Get a single public crocodile&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Registration and authentication
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Register a new user&lt;/li&gt;
&lt;li&gt;Bearer/JWT token authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Private APIs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;List all your crocodiles&lt;/li&gt;
&lt;li&gt;Get a single crocodile&lt;/li&gt;
&lt;li&gt;Create a new crocodile (max 100)&lt;/li&gt;
&lt;li&gt;Update your crocodile&lt;/li&gt;
&lt;li&gt;Update selected fields on your crocodile&lt;/li&gt;
&lt;li&gt;Remove your crocodile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The scenario is to test all the public and private APIs. For the private APIs, a user is created and its token is extracted. The extracted token is used to make other API calls. The order is very important in the private APIs, since you cannot delete a non-existing resource, for example. By the way, crocodile is our mascot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Test API Postman Collection
&lt;/h2&gt;

&lt;p&gt;To ease testing of our test API and demonstrate the usage of our Postman to k6 converter, I've created a Postman collection with almost all of our test API requests. You'll see how you can access this Postman collection shortly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G7br-ubL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://k6.io/blog/static/d4838295f84cd559ada9a497527e27cc/244a1/test-api-postman-collection.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G7br-ubL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://k6.io/blog/static/d4838295f84cd559ada9a497527e27cc/244a1/test-api-postman-collection.png" alt="Test API Postman collection" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This collection includes a set of collection variables, environment variables, pre-scripts, tests, authorization with two different mechanisms, and usages of the &lt;a href="https://learning.postman.com/docs/postman/scripts/postman-sandbox-api-reference/"&gt;Postman Sandbox API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Load Testing Our Test API with The Postman Collection
&lt;/h2&gt;

&lt;p&gt;We have created a tool that converts your Postman collection to k6 script, which is called &lt;a href="https://github.com/loadimpact/postman-to-k6"&gt;postman-to-k6&lt;/a&gt;. You can read more about its features in its &lt;a href="https://blog.loadimpact.com/new-postman-to-k6-converter-tool-with-support-for-pre-request-and-test-scripts"&gt;release notes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In order to convert your Postman collection to k6 script, you should take the following steps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Optional: Clone the repository and skip to the step 5&lt;/strong&gt; :&lt;/p&gt;

&lt;p&gt;I've created a repository for this article that contains the exported Postman collection, along with the converted script and related files. You can clone the repository and import the &lt;code&gt;test-api.json&lt;/code&gt; and &lt;code&gt;env.json&lt;/code&gt; files into the Postman application and possibly play with them if you want.&lt;/p&gt;

&lt;p&gt;This repository contains everything that is needed for load testing our test API, so you can skip to step 4. When using your own collection, you should take all the steps to be able to have a k6 script out of your Postman collection, and to be able to run your load test with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://github.com/k6io/example-postman-collection.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Install Node.js (if you haven't already done so)&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;For this, I highly recommend that you use something like &lt;a href="https://github.com/nvm-sh/nvm"&gt;nvm&lt;/a&gt;, which is a Node.js version manager that you can use to have multiple version of Node.js at the same time on your machine and be able to switch to any of them quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Install the postman-to-k6 tool&lt;/strong&gt; :&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/loadimpact/postman-to-k6"&gt;postman-to-k6&lt;/a&gt; tool is developed to help you convert the requests inside your Postman collections to k6 scripts, which are actually JavaScript code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; postman-to-k6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Convert your exported Postman collection to k6 script&lt;/strong&gt; :&lt;/p&gt;

&lt;p&gt;Assuming your exported collection is named &lt;code&gt;test-api.json&lt;/code&gt;, you can run this command to convert it to a k6 script. The &lt;code&gt;env.json&lt;/code&gt; includes all your environment variables that are exported from Postman.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;postman-to-k6 test-api.json &lt;span class="nt"&gt;-e&lt;/span&gt; env.json &lt;span class="nt"&gt;-o&lt;/span&gt; k6-script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need more fine-tuning of your test (like we did above), like adding data or changing environment variables inside your code, just take a look at the Options section of the &lt;a href="https://github.com/loadimpact/postman-to-k6#options"&gt;postman-to-k6 README&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The script generated by the converter should look like below. As you see, I've manually added the &lt;a href="https://k6.io/docs/using-k6/options#duration"&gt;duration&lt;/a&gt; (of the test run) to be 1 minute and also added the &lt;a href="https://k6.io/docs/using-k6/options#vus"&gt;virtual users (VU)&lt;/a&gt; count. These two options let the script run for a minute with 100 virtual users. These 100 VUs try to make as many requests as they can to test the server, which you'll see in the next screenshot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./libs/shim/core.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./libs/shim/urijs.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;URI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./libs/urijs.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;group&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;k6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;maxRedirects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1m&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;vus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;request&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;postman&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;initial&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)]({&lt;/span&gt;
    &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;BASE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://test-api.k6.io/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;USERNAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test@example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;superCroc2020&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;FIRSTNAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;LASTNAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;EMAIL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test@example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ACCESS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;REFRESH&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;CROCID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Public APIs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;postman&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;]({&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;List all public crocodiles&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3ddd46c4-1618-4883-82ff-1b1e3a5f1091&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{BASE_URL}}/public/crocodiles/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="nx"&gt;postman&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;]({&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Get a single public crocodile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;9625f17a-b739-4f91-af99-fba1d898953b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{{BASE_URL}}/public/crocodiles/1/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// NOTE: The rest of the requests can be accessed&lt;/span&gt;
    &lt;span class="c1"&gt;// from the repository in step 1&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generated script is a little bit different from normal k6 scripts, since it includes various abstractions to support different Postman functionality, but you can mix them with regular &lt;a href="https://docs.k6.io/docs/http-requests"&gt;http requests&lt;/a&gt; from k6. Also, there is a &lt;code&gt;libs&lt;/code&gt; directory beside the script that includes shims and libraries needed for the Postman scripts to work correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Install k6&lt;/strong&gt; :&lt;/p&gt;

&lt;p&gt;k6 supports various platforms, including Windows, Linux, macOS and docker. In order to &lt;a href="https://docs.k6.io/docs/installation"&gt;install&lt;/a&gt; it, just grab an &lt;a href="https://dl.bintray.com/loadimpact/windows/k6-latest-amd64.msi"&gt;Windows installer&lt;/a&gt; or a &lt;a href="https://hub.docker.com/r/loadimpact/k6"&gt;docker image&lt;/a&gt; and run it on your machine. On Linux distributions, you can use &lt;a href="https://docs.k6.io/docs/installation#section-linux-deb-and-rpm-packages"&gt;APT or YUM&lt;/a&gt;, and on macOS, you can use &lt;a href="https://docs.k6.io/docs/installation#section-mac-brew"&gt;Homebrew&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;NOTE: Regarding installation on Windows, you can also use &lt;a href="https://chocolatey.org/packages/k6"&gt;choco k6 package&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Run k6 with the generated script&lt;/strong&gt; :&lt;/p&gt;

&lt;p&gt;Now that you have your collections converted into a k6 script, you can invoke k6 like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;k6 run k6-script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result of running the script is shown in the following console output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
          /&lt;span class="se"&gt;\ &lt;/span&gt;     |‾‾|  /‾‾/  /‾/
     /&lt;span class="se"&gt;\ &lt;/span&gt; /  &lt;span class="se"&gt;\ &lt;/span&gt;    |  |_/  /  / /
    /  &lt;span class="se"&gt;\/&lt;/span&gt;    &lt;span class="se"&gt;\ &lt;/span&gt;   |      |  /  ‾‾&lt;span class="se"&gt;\&lt;/span&gt;
   /          &lt;span class="se"&gt;\ &lt;/span&gt;  |  |‾&lt;span class="se"&gt;\ &lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;| &lt;span class="o"&gt;(&lt;/span&gt;_&lt;span class="o"&gt;)&lt;/span&gt; |
  / __________ &lt;span class="se"&gt;\ &lt;/span&gt; |__|  &lt;span class="se"&gt;\_&lt;/span&gt;_&lt;span class="se"&gt;\ \_&lt;/span&gt;__/ .io

  execution: &lt;span class="nb"&gt;local
     &lt;/span&gt;output: -
     script: k6-script.js

    duration: 1m0s, iterations: -
         vus: 100,  max: 100

    &lt;span class="k"&gt;done&lt;/span&gt; &lt;span class="o"&gt;[==========================================================]&lt;/span&gt; 1m0s / 1m0s

    █ Public APIs

    █ Registration and authentication

    █ Private APIs

    data_received..............: 8.8 MB 146 kB/s
    data_sent..................: 4.8 MB 80 kB/s
    group_duration.............: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;753.07ms &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;239.15ms &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;495ms    &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4.06s    p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;1.37s    p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;1.73s
    http_req_blocked...........: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;12.31ms  &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;362ns    &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.52µs   &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3.47s    p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;1.83µs   p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;1.96µs
    http_req_connecting........: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.95ms   &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s       &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s       &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;779.59ms p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;0s       p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;0s
    http_req_duration..........: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;211.11ms &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;104.42ms &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;183.12ms &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;924.43ms p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;304.25ms p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;404.24ms
    http_req_receiving.........: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1ms      &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;41.14µs  &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;169.38µs &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;130.94ms p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;328.31µs p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;2.22ms
    http_req_sending...........: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;205.91µs &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;38.06µs  &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;163.76µs &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;113.06ms p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;258.45µs p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;302.86µs
    http_req_tls_handshaking...: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8.69ms   &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s       &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0s       &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2.43s    p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;0s       p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;0s
    http_req_waiting...........: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;209.9ms  &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;104.05ms &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;182.22ms &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;891.77ms p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;301.29ms p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;402.41ms
    http_reqs..................: 26363  439.382653/s
    iteration_duration.........: &lt;span class="nv"&gt;avg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2.28s    &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.43s    &lt;span class="nv"&gt;med&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2.01s    &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6.55s    p&lt;span class="o"&gt;(&lt;/span&gt;90&lt;span class="o"&gt;)=&lt;/span&gt;2.86s    p&lt;span class="o"&gt;(&lt;/span&gt;95&lt;span class="o"&gt;)=&lt;/span&gt;3.64s
    iterations.................: 2588   43.133267/s
    vus........................: 100    &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100 &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100
    vus_max....................: 100    &lt;span class="nv"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100 &lt;span class="nv"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Remarks about using the postman-to-k6 converter
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1️. Should we base our load tests on the Postman converter and our Postman collections?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're using the converter as a way of onboarding, no. If you expect to convert your collection continuously and without doing a lot of manual edits afterwards, yes.&lt;/p&gt;

&lt;p&gt;We recommend you to use the converter as an easy way to onboard and then rewrite your scripts to idiomatic k6 code, as we believe it to be more maintainable and less likely to degrade over time. If you convert from postman collections continuously, however, and run the script output as-is, it might make sense to keep it as is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Is everything available out of the box in the converted script?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Since k6 uses Goja to run JavaScript, and it is not compatible with browsers' and Node.js APIs, hence there are some missing functionality. This can be fixed by &lt;a href="https://k6.io/docs/using-k6/modules"&gt;importing bundled JavaScript modules&lt;/a&gt;. For a list of compatible libraries, please see &lt;a href="https://jslib.k6.io/"&gt;jslib.k6.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What adjustments did you make to the script to make it work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, I removed the pre-script containing &lt;code&gt;pm.sendRequest&lt;/code&gt;, because it is not supported by the converter. Then, I replaced the &lt;code&gt;jsonData.hasOwnProperty&lt;/code&gt; syntax with the equivalent k6 syntax for &lt;a href="https://k6.io/docs/javascript-api/k6-http/response-k6-http"&gt;extracting JSON response information&lt;/a&gt;: &lt;code&gt;response.json("selector")&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jAawTE-y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://k6.io/blog/static/0bba6dfb2a3874cbbff545c53a5e17e0/95ab6/test-api-postman-pre-script.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jAawTE-y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://k6.io/blog/static/0bba6dfb2a3874cbbff545c53a5e17e0/95ab6/test-api-postman-pre-script.png" alt="Postman Collection Pre-scripts" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Postman API vs. k6 API
&lt;/h2&gt;

&lt;p&gt;Here's a quick comparison of the &lt;a href="https://learning.postman.com/docs/postman/scripts/postman-sandbox-api-reference/"&gt;Postman API&lt;/a&gt; versus the &lt;a href="https://k6.io/docs/javascript-api"&gt;k6 API&lt;/a&gt;. To be fair, I have included features from Postman GUI application. Since k6 is scriptable from the start, you have the option to write the logic in JavaScript. Postman also supports javascript to do various tasks, but the focus is on exposing features via a richer set of GUI elements.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Postman API&lt;/th&gt;
&lt;th&gt;k6 API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Importing external libraries&lt;/td&gt;
&lt;td&gt;Selected libraries&lt;/td&gt;
&lt;td&gt;Selected libraries plus bundled ones&lt;br&gt;(non-browser, non-Node.js APIs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Making requests&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Processing response&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parametrization&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;REST&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GraphQL&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cookies&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proxy&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSL&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAPI/Swagger&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;(import directly)&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;(via k6 generator in openapi-generator)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checks&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;(assertions)&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;(Check API)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Groups&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;(Collections)&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;(Group API)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML parsing&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;(needs library)&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;(internal HTML API)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File upload&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test Lifecycle&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;(only with scripts)&lt;/td&gt;
&lt;td&gt;✅&lt;br&gt;(internal)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As you saw above, there are many features supported by each API, each to some extent. Some features needs external libraries, some are internal. Both APIs are scriptable in JavaScript, and not everything is supported by both, due to the various browser and Node.js APIs used in the libraries.&lt;/p&gt;

&lt;p&gt;Yet, there are some features only available on k6, which is partially due to the fact that the Postman is catered for API testing or API functional testing, but k6 is focused more on API load testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Functional testing vs. load testing
&lt;/h3&gt;

&lt;p&gt;Functional testing concerns with giving input to the system (as a black-box) via an API and examining the results, while load testing is basically doing the same thing as functional testing, but with additional &lt;strong&gt;load&lt;/strong&gt; on the input to the system.&lt;/p&gt;

&lt;p&gt;Functional testing provides input on each endpoint, and the returned results are verified in terms of correctness against a set of specifications. In turn, load testing provides a huge amount of load on each endpoint, and rather tries to aggregate the metadata returned by all the responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Load testing metrics for measuring performance
&lt;/h3&gt;

&lt;p&gt;Concerning the measurements, the metadata will include the time it took for the request to settle and the response to return, which are measure by various &lt;a href="https://k6.io/docs/using-k6/metrics"&gt;metrics&lt;/a&gt;. For example you can measure the HTTP request duration of all requests and get their minimum, maximum, average, median, 90th and 95th percentiles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pass/fail a test with thresholds
&lt;/h3&gt;

&lt;p&gt;You also have the option to pass/fail a test if it does/doesn't reach certain &lt;a href="https://k6.io/docs/using-k6/thresholds"&gt;threshold(s)&lt;/a&gt;. For example, you can specify that you want the average response time to be less than 500ms. If the average is below that, the test will fail, much like asserts in software testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Filter results with tags
&lt;/h3&gt;

&lt;p&gt;Since you're dealing with lots of different results from different endpoints, your life would be easier if you could filter the results. &lt;a href="https://k6.io/docs/using-k6/tags-and-groups#tags"&gt;Tags&lt;/a&gt; are supported by k6 to fulfill this requirement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Load testing WebSocket servers
&lt;/h3&gt;

&lt;p&gt;In terms of protocol implementation, &lt;a href="https://k6.io/docs/using-k6/protocols/websockets"&gt;WebSocket&lt;/a&gt; is one of the features available only in k6, compared to Postman, and you can load test your WebSocket server with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article I've tried to give a quick introduction to Postman, the postman-to-k6 converter and our k6 load testing tool. All these tools combined can help you turn your API requests in Postman into k6 script in order to load test your API. Many of the Postman features are supported by the postman-to-k6 tool.&lt;/p&gt;

&lt;p&gt;Our ultimate goal is to streamline the process of onboarding you to our load testing tool, k6. In doing so, we have created a bunch of &lt;a href="https://k6.io/docs/integrations"&gt;tools&lt;/a&gt; that can help you easily integrate load testing in your infrastructure.&lt;/p&gt;

</description>
      <category>k6</category>
      <category>postman</category>
      <category>loadtesting</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Beginner's Guide to Load Testing with k6</title>
      <dc:creator>Mostafa Moradian</dc:creator>
      <pubDate>Sun, 23 Jun 2019 11:01:52 +0000</pubDate>
      <link>https://dev.to/mostafa/beginner-s-guide-to-load-testing-with-k6-1od2</link>
      <guid>https://dev.to/mostafa/beginner-s-guide-to-load-testing-with-k6-1od2</guid>
      <description>&lt;p&gt;Let’s start with some questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have you ever thought about ways to find out if your infrastructure setup could stand under high loads of users?&lt;/li&gt;
&lt;li&gt;Have you ever been able to run a load test without dealing with so many configurations and steep learning curve of current testing tools?&lt;/li&gt;
&lt;li&gt;Have you ever thought about ways to script your way through testing, either for load/performance or otherwise?&lt;/li&gt;
&lt;li&gt;Have you ever thought that load testing can be simplified and be included as part of your CI/CD process?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You are not alone in that. I remember days when I was the lead developer of a team working on developing an API to serve our ever-increasing set of Apps with many micro-services like content- and user-management, billing, analytics and the like. At that time, we used to use the latest best practices in software engineering in source control and CI/CD processes. We have set up our CI/CD process using docker and hosted GitLab and used GitLab CI to deal with CI process. After a while of testing and code-push, we have decided to go with an alpha-stage API that can answer our needs with a new App we used to develop.&lt;/p&gt;

&lt;p&gt;After a while of development, testing and improvement, we decided to test our API under load to see if it can hold up to the promises. Since we have seen that after 200,000 users subscribing and 60,000 of them using one of our other Apps, there is an slow-down on the request/response flow to the other API, which roughly had the same setup.&lt;/p&gt;

&lt;p&gt;So, in order to not miss the opportunity of (load) testing before customers coming in, we decided to investigate ways to load test our API. After our investigations into Locust, Apache JMeter and the like, we decided to go with Apache JMeter, which was (and still is) the tool of the trade. We thought it would be a good candidate for this purpose. It took us almost three days to be able to learn and execute simple load tests with the GUI version. We were able to produce load test from one server and analyze the results. The results were good, because it gave us a bit more insight into what we should expect from our API, in terms of number of concurrent users and our API’s response time under load.&lt;/p&gt;

&lt;p&gt;But later we didn’t use the tool, since there was no clear way to integrate it into our CI/CD process at that time, and we didn’t have enough time to learn and use it. We wanted something more developer-friendly, more integrable to our workflow, and easier to learn. Nowadays, it has been improved very much and it integrates with CI/CD pipelines easily.&lt;/p&gt;




&lt;p&gt;Now, I am working for a company, &lt;a href="https://loadimpact.com/" rel="noopener noreferrer"&gt;Load Impact&lt;/a&gt;, which deals with load and performance testing as their core business. They have a FOSS, easily scriptable tool (JavaScript), called &lt;a href="https://k6.io/" rel="noopener noreferrer"&gt;k6&lt;/a&gt;, which can be used for load testing. They also offer a cloud service on top of the same exact tool, for provisioning and running the tests, from different regions of the world (&lt;a href="https://loadimpact.com/cloud-execution/" rel="noopener noreferrer"&gt;Cloud Execution&lt;/a&gt;), and it finally give you a nice dashboard (&lt;a href="https://loadimpact.com/insights/" rel="noopener noreferrer"&gt;Insights&lt;/a&gt;) with analyzed results of the tests with shiny charts. It also has good &lt;a href="https://loadimpact.com/integrations/" rel="noopener noreferrer"&gt;integrations&lt;/a&gt; with CI/CD tools and platforms.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FfkmdMN3%2F1-Dgp-DE9w-Bwx-VKtm-Tk-BLnz-A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FfkmdMN3%2F1-Dgp-DE9w-Bwx-VKtm-Tk-BLnz-A.png" alt="**Left**: load test script written in JavaScript, **Right**: Cloud service of Load Impact (Insights), **Credits**: [https://loadimpact.com/](https://loadimpact.com/)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enough said! Let’s dive deep into what load testing is and how we can use k6 for doing load testing on our infrastructure. I will try to write more about the cloud service in the future, too.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is Load/Performance Testing?
&lt;/h4&gt;

&lt;p&gt;Performance testing is a subset of performance engineering in computer science practice which deals with quality assurance of software by putting pressure and workload, either manually or automatically, on the software to see how it behaves and to make sure it is responsive and stable enough under that load. It’s all about expectations. For example, you expect your API or website to serve 10K users simultaneously, but when you put pressure on it, it quickly becomes evident that your calculations differs from the reality and the reverse proves to be the case. Then you should analyze the weak points in your design or setup to see how you can benefit from high load.&lt;/p&gt;

&lt;p&gt;There are many types of tests catered for different purposes in performance testing (Source: &lt;a href="https://en.wikipedia.org/wiki/Software_performance_testing" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Software_performance_testing&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Load testing&lt;/strong&gt;: basically, putting load on the system to see how it behaves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stress testing&lt;/strong&gt;: load testing to find the maximum amount of load the system can handle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soak testing&lt;/strong&gt;: load testing a system continuously and monitoring for memory leaks and behavior of the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spike testing&lt;/strong&gt;: load testing with sudden increase or decrease of the load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Breakpoint testing&lt;/strong&gt;: like stress testing, but incremental load is put on the system over time to see how it behaves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration testing&lt;/strong&gt;: changing configuration to see how the system behaves under different configurations, under load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation testing&lt;/strong&gt;: Isolating a fault domain and repeating the test to confirm the failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internet testing&lt;/strong&gt;: global load testing for big companies to see how to system behaves from different regions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most common purpose of performance testing is to find out how reliable, stable, performant and responsive the system is. Metrics like throughput and response time is a good measure of such a system.&lt;/p&gt;

&lt;h4&gt;
  
  
  k6: Scripting, Running and Monitoring Load Tests
&lt;/h4&gt;

&lt;p&gt;k6 is a Free/Open-Source tool, written in Go, which can ingest tests written in JavaScript (ES5.1+) and turn them into requests to load test your website or API.&lt;/p&gt;

&lt;p&gt;You can either build the k6 from source or &lt;a href="https://docs.k6.io/docs/installation" rel="noopener noreferrer"&gt;download and install an official binary distribution&lt;/a&gt;. There is also &lt;a href="https://hub.docker.com/r/loadimpact/k6/" rel="noopener noreferrer"&gt;an official docker image&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The not-so-beginner approach is to build k6, which obviously you should have Go installed on your machine. To do this, first &lt;a href="https://golang.org/dl/" rel="noopener noreferrer"&gt;download and install Go&lt;/a&gt; and while having &lt;code&gt;$GOROOT&lt;/code&gt; and &lt;code&gt;$GOPATH&lt;/code&gt; environment variables set on your shell of choice, run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/loadimpact/k6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It will automatically download and install k6 on your machine’s &lt;code&gt;$GOPATH/bin&lt;/code&gt; directory, which you can then run it using the following script:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Once you have saved this script somewhere accessible to k6, naming it &lt;code&gt;script.js&lt;/code&gt; or your own desired file name, you can run it with 10 virtual users (VU) and over a period of 30 seconds, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;k6 run -u 10 -d 30s script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It basically runs k6 on your machine using 10 virtual users over the course of 30 seconds, and it checks to see if the test URL returns 200 in all tests.&lt;/p&gt;

&lt;p&gt;This was a very short introduction to performance/load testing and the k6 tool. I will try to write more advanced load testing articles to show you how to load test your website and/or API.&lt;/p&gt;

&lt;p&gt;This series will continue with more in-depth performance/load testing articles assuming the readers don’t have previous experience on this topic.&lt;/p&gt;

&lt;p&gt;As always, I do really appreciate your suggestions, comments and inputs on this.&lt;/p&gt;

</description>
      <category>loadtesting</category>
      <category>performancetesting</category>
      <category>loadimpact</category>
      <category>k6</category>
    </item>
  </channel>
</rss>
