# CHttp Visual Studio Code Extension

I have been recently working on [CHttp](https://github.com/ladeak/Http3Tools) 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](https://github.com/ladeak/Http3Tools/releases), as a dotnet tool by using the `dotnet tool install -g LaDeak.CHttp` command or by as a Visual Studio Code [Extension](https://marketplace.visualstudio.com/items?itemName=ladeak-net.ladeak-chttp).

## 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](https://github.com/Huachao/vscode-restclient) extension.

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

```http
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:

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

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

```http
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.

```http
@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:

```http
###
# @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.

```http
# @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. 

```http
@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:

```results
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:

```http
###
# @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.


```results
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
------------------------------------------------------------------------
```