CHttp Visual Studio Code Extension

I have been recently working on CHttp which is a tool to send HTTP requests and to measure the performance of REST APIs.

The primary goal of the tool is the ability to measure GET HTTP requests using version HTTP/2 and HTTP/3. As the tool is based on .NET (currently version 8), it requires a reasonably up-to-date Windows installation or the libmsquic package in case of Linux.

The standalone tool can be installed from GitHub, as a dotnet tool by using the dotnet tool install -g LaDeak.CHttp command or by as a Visual Studio Code Extension.

Using CHttp Visual Studio Code Extension

The extension works with CHttp files. It is based on a file format that has been introduced by Huachao's REST Client extension.

Let's take a simple example to send an HTTP request:

GET https://localhost:5001/endpoint

Note, that the tool in the VS Code Extensions uses HTTP/2 by default. To change it, one can specify a different HTTP version as:

GET https://localhost:5001/endpoint HTTP/1.1

One can define headers and content. Separate headers and content with an empty line.

POST https://localhost:5001/jsonrequest
Content-Type:application/json

{
    "message": "hello world"
}

To add comments use #or // characters. To separate queries, use the ### character combination.

Variables

It is possible to define and re-use file level variables using the @variable syntax. Then a variable can be referenced with the {{variable}} syntax.

@baseUrl = localhost:5001
@path = delay
###
GET https://{{baseUrl}}/{{path}} HTTP/2

Variables may also reference another request's response content or headers. To achieve this, create a named request:

###
# @name jsonSample
GET https://localhost:5001/jsonresponse
###
@nextRequestContent = {{jsonSample.response.body.message}}
###
# echo
GET https://localhost:5001/echo

{{nextRequestContent}}

In the above case the top request is named by the # @name jsonSample attribute. A variable @nextRequestContent references the response body's message JSON field. Use json-path to refer to a custom element of the response. Use the [requestname].response.header.content-type to refer to response headers.

Then use this variable in another request with {{nextRequestContent}} reference.

Attributes

Use attributes to change the HTTP request behavior. At the time of writing the following attributes are supported:

  • clientscount

  • requestcount

  • timeout (in seconds)

  • no-certificate-validation

  • no-redirect

  • name

  • kerberos-auth

For example, to ignore certificate validation errors, set the @no-certificate-validation attribute with value true.

# @no-certificate-validation true
GET https://localhost:5001/endpoint HTTP/1.1

Performance Measurements

Run performance measurements by defining either @clientscount or @requestcount attributes. Their default values are 10 and 100 respectively.

@baseUrl = localhost:5001

###
# @clientsCount 10
# @requestCount 100
GET https://{{baseUrl}}

While it is possible to set a request content, for performance measurements it is not suggested as larger requests can impact the performance measurement on client side.

Such requests will result an output of:

RequestCount: 100, Clients: 10
| Mean:          322,698 us   |
| StdDev:         80,236 us   |
| Error:           8,024 us   |
| Median:        310,700 us   |
| Min:           198,700 us   |
| Max:           652,700 us   |
| 95th:          473,700 us   |
| Throughput:      0.000  B/s |
| Req/Sec:      2,82E+04      |
------------------------------------------------------------------------
   244,100 us #########
   289,500 us ###################
   334,900 us ###################
   380,300 us ##############
   425,700 us ####
   471,100 us ##
   516,500 us ##
   561,900 us #
   607,300 us 
   652,700 us #
------------------------------------------------------------------------
HTTP status codes:
1xx: 0, 2xx: 100, 3xx: 0, 4xx: 0, 5xx: 0, Other: 0
------------------------------------------------------------------------

The output has three sections. The top section displays statistical results. The middle section draws a distribution of requests. The last section displays an aggregate view of the response codes.

I this case the mean execution time is 322.698 us. The distribution has a single mode. All requests 100 returned status codes from the 200-299 range.

Diff Performance Measurements

Compare two named performance measurement results with the DIFF command. Use the @name [value] pattern to give a referrable name to a query:

###
# @name comparison
# @clientsCount 10
# @requestCount 100
GET https://{{baseUrl}}/post HTTP/2

###
# @name basePerformance
# @clientsCount 10
# @requestCount 100
POST https://{{baseUrl}}/post

{"data":"hello world"}

###
DIFF basePerformance comparison

Diff results an aggregate view of the differences between the two requests.

RequestCount: 100, Clients: 10
| Mean:          448,127 us      -55,265 us   |
| StdDev:        151,588 us     +120,312 us   |
| Error:          15,159 us      +12,031 us   |
| Median:        413,600 us     -115,100 us   |
| Min:           265,300 us     -137,600 us   |
| Max:             1,285 ms     +225,800 us   |
| 95th:          763,700 us     +220,100 us   |
| Throughput:      0.000  B/s          0  B/s |
| Req/Sec:      1,16E+04       +9244,993      |
------------------------------------------------------------------------
   266,040 us +++++++++++++
   404,380 us =============###
   542,720 us ====############
   681,060 us =++
   819,400 us ##
   957,740 us =
     1,096 ms =+
     1,234 ms 
     1,373 ms 
     1,511 ms +
------------------------------------------------------------------------
HTTP status codes:
1xx: 0 +0, 2xx: 100 +0, 3xx: 0 +0, 4xx: 0 +0, 5xx: 0 +0, Other: 0 +0
------------------------------------------------------------------------
*Warning: session files contain different urls: https://localhost:5001/,https://localhost:5001/post
------------------------------------------------------------------------