0.0.8 • Published 6 months ago

restclients v0.0.8

Weekly downloads
-
License
Apache-2.0
Repository
github
Last release
6 months ago

Rest Clients

Rest Clients is a simple and secured Rest API Client, pure design and zero dependency, local storage and easy to share. This tool is intended to make HTTP requests sent via command line.

This project is inspired by REST Client.

Features

Rest Clients includes multiple features to make sending request easier.

  • Send HTTP request in .rcs, .rest or .http file
  • Auto show request context like Network in Chrome dev tool
  • Compose MULTIPLE requests in a single file (separated by ### delimiter)
  • Show response body raw content
  • Authentication support for:
    • Basic Auth
  • Environments and static/dynamic variables support
    • Use variables in any place of request(URL, Headers, Body)
    • Support environment, file static variables
    • Interactively assign file prompt variables per request
    • Built-in dynamic variables
      • {{$guid}}
      • {{$randomInt min max}}
      • {{$timestamp [offset option]}}
      • {{$datetime rfc1123|iso8601 [offset option]}}
      • {{$localDatetime rfc1123|iso8601 [offset option]}}
      • {{$processEnv [%]envVarName}}
      • {{$dotenv [%]variableName}}
    • Easily create/update/delete environments and environment variables in setting file
    • File variables can reference environment, dynamic variables
    • Support for multiple environments and a shared environment to provide variables that available in all environments
  • Scripting to extract data from response, set variables and more.
  • HTTP language support
    • .rcs, .http and .rest file extensions support
    • Comments (line starts with # or //) support
    • Support json and xml response body preview

🚀 Quick Starts

To quick starts, run the following command:

git clone https://github.com/restclients/restclients.git
cd ./example
npx restclients -r ./example -n "posts" -s "example.config.js" -d ".env" -e "int" -f example

Installation & Usage

npm install restclients

Define a command in package.json

"scripts": {
    "rcs": "restclients -r rootDir -s rcs.setting.js -d .env"
}

Run the following command to send request.

### send all requests
npm run rcs
### send requests with option
npm run rcs -- -n namePattern -f filePattern

Options

  • --rootDir, -r\ Specify the root directory to search rest clients file
  • --namePattern, -n\ Specify the rest request name match pattern
  • --filePattern, -f\ Specify the rest clients file name match pattern
  • --verbose, -v\ Show verbose log
  • --dotenvFile, -d\ Specify the dot env file path
  • --settingFile, -s\ Specify the setting file path
  • --environment, -e\ Specify the target environment

HTTP file

In the HTTP file, define the request content

https://test.example.com/users/1

The standard RFC 2616 that including request method, headers, and body.

POST https://test.example.com/users/1 HTTP/1.1
content-type: application/json

{
    "name": "Jimmy",
    "updatedTime": "2024-12-08T01:49:07.039Z"
}

In addtion, save multiple requests in the same HTTP file with a new line starting with three or more consecutive # symbol as a separator.

GET https://test.example.com/users/1 HTTP/1.1

### Get group profile

GET https://test.example.com/groups/1 HTTP/1.1

### Update user profile

POST https://test.example.com/users/1 HTTP/1.1
content-type: application/json

{
    "name": "Jimmy",
    "updatedTime": "2024-12-08T01:49:07.039Z"
}

The content after the starting ### is the request name. Use the -n option to match the request name of which requests are to be executed.

## Only send the "Get group profile" API request
restclients -n "Get group profile"

The request in the same HTTP file is executed in sequence.

Request Line

The first non-empty line following the request separator is the Request Line. Below are some examples of Request Line:

GET https://test.example.com/users/1 HTTP/1.1
GET https://test.example.com/users/1
https://test.example.com/users/1

If request method is missing, restclients use GET method, the above three requests are the same.

Query String

Generally, the request query string is in the request line as following:

GET https://test.example.com/users?page=2&pageSize=10

Sometimes, too many query parameters are in a single request, putting all the query parameters in Request Line is hard to read and modify. So, separate query parameters into multiple lines(one or more query parameters a line), we will parse the lines immediately after the Request Line which starts with ? and &.

GET https://test.example.com/users
    ?page=2
    &pageSize=10
GET https://test.example.com/users
    ?page=2&pageSize=10
    &name=Jimmy

Request Headers

The lines which are immediately follow the Request Line and before the first empty line will be parsed as Request Headers. These headers should follow the standard field-name: field-value format, with each line representing a single header. By default if you don't explicitly specify a User-Agent header, Rest Clients will automatically add one with the value restclients. To change the default value, add $restclients.userAgent setting.

Below are examples of Request Headers:

https://test.example.com/users/1
User-Agent: my-restclients
Content-Type: application/json

Request Body

A blank line is used to separate the Request Headers and Request Body. The request body content is after the blank line and before the request separator line starting with ### or EOF.

POST https://test.example.com/users/1 HTTP/1.1
Content-Type: application/xml
Authorization: Bearer xxx

<request>
    <name>sample</name>
    <updatedTime>Wed, 21 Oct 2015 18:27:50 GMT</updatedTime>
</request>

If the request body start with the letter <, the rest should be a file path to read the data from. It can be a absolute or relative (relative to rootDir or current HTTP file) file path.

POST https://test.example.com/users/1 HTTP/1.1
Content-Type: application/xml
Authorization: Bearer xxx

< /Uses/xxx/example/sample.txt
POST https://test.example.com/users/1 HTTP/1.1
Content-Type: application/xml
Authorization: Bearer xxx

< ./sample.txt

If there is letter @ after <, the variables in the file will be processed (UTF-8 is assumed as the default encoding). To change the default encoding, append the encoding type following the @.

POST https://test.example.com/users/1 HTTP/1.1
Content-Type: application/xml
Authorization: Bearer xxx

<@ ./sample.txt
POST https://test.example.com/users/1 HTTP/1.1
Content-Type: application/xml
Authorization: Bearer xxx

<@utf16le ./sample.utf16le.txt

If the content type of request body is application/x-www-form-urlencoded, the request body can be one line or multiple lines which start with &.

POST https://test.example.com/users/login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

name=foo&password=pass&option=id%26email
POST https://test.example.com/users/login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

name=foo
&password=pass
&option=id%26email

If the content type of request body is multipart/form-data, the body part can be a file or plain text.

POST https://test.example.com/users/profile HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryM6cFocZWsx5Brf1A

------WebKitFormBoundaryM6cFocZWsx5Brf1A
Content-Disposition: form-data; name="form"

test data
------WebKitFormBoundaryM6cFocZWsx5Brf1A
Content-Disposition: form-data; name="file"; filename="sample.txt"
Content-Type: application/octet-stream


< ./sample.txt
------WebKitFormBoundaryM6cFocZWsx5Brf1A--

Authentication

Support Basic Auth, Bearer Token.

Basic Auth

HTTP Basic Auth is a widely used protocol for simple username/password authentication.

GET https://test.example.com/users/1 HTTP/1.1
Authorization: Basic user:passwd
GET https://test.example.com/users/1 HTTP/1.1
Authorization: Basic dXNlcjpwYXNzd2Q=

Bearer Token

Send the request with a Bearer Token

GET https://test.example.com/users/1 HTTP/1.1
Authorization: Bearer tokencontent

Use Variables

When define a HTTP Request, variables can be used to parametrize its elements. A variable can be in the Requset Line, Query String, Request Headers and Request Body (including the external file content).

A variable is enclosed in double curly braces as {{variable}}.

If the variable can not be resolved, send request with the original content.

### POST https://test.example.com/users/1 with body `{{data}}`

@hostname=test.exmaple.com
POST https://{{hostname}}/users/1 HTTP/1.1
Authorization: Bearer tokencontent

{{data}}

Support several types of variables listed below in priority order. If variable names conflict, the value of the one higher on this list will be used.

  • Prompt variables defined in HTTP file, input value before request sending and available within the same files only.

  • Environment variables defined in Setting File and available in any HTTP file.

  • File variables defined in HTTP file and available within the same files only.

In additional, Rest Clients provides built-in dynamic variables with dynamically generated values or get values from process environment and dot env file.

Environment variables

Environment variables help to store a set of environment definitions inside your project. For example, instead of providing a hostname in your request explicitly, you can create the {{hostname}} variable in different environments: a local hostname in the int environment and a public hostname in the stage environment. The special shared environment(identified by special environment name $shared) to provide a set of variables that are available in all environments.

Then run the restclients command with a option -e to select an environment. Only variables defined in selected environment and shared environment are available.

Environment variables are defined in setting file, the default file path is restclients.config.js and the option -s is to change the default file path. In user defined environment, to access shared environment, use the {{$shared variableName}} syntax.

The following sample setting file defines two environments: int and stage.

module.exports = {
  $restclients: {
    userAgent: "myRestclients",
  },
  $shared: {
    key1: "KEYYYY",
    key2: "KEYYY2",
  },
  int: {
    hostname: "int.example.com",
    token: "INT_TOKEN",
    key: "{{$shared key1}}",
  },
  stage: {
    hostname: "stage.example.com",
    token: "STAGE_TOKEN",
    key: "{{$shared key2}}",
  },
};

The example Rest Clients request is as follows:

POST https://{{hostname}}/users/1 HTTP/1.1
Authorization: {{token}}
Content-Type: application/json

{
    "key": "{{key}}"
}

Prompt variables

The scope of a prompt variable is a HTTP file, in which it was declared. Input the variable value before sending a request. A HTTP Request can have more than one prompt variable.

The prompt variables are defined like a single-line comment // @prompt {var1} or # @prompt {var1}.

A variable description can also be defined by // @prompt {var1} {description} or # @prompt {var1} {description} which will prompt an input popup with the specified description message.

The reference syntax is the same as others, like {{var}}. The prompt variable will override the other conflict variable.

@hostname = test.example.com
@port = 8633
@host = {{hostname}}:{{port}}
@contentType = application/json

### basic
# @prompt userId
# @prompt email Your email address display on webpage
# @prompt password Your password
POST https://{{host}}/users/{{userId}} HTTP/1.1
Content-Type: {{contentType}}

{
    "email": "{{email}}",
    "password": "{{password}}"
}

File variables

The scope of a file variable is an HTTP file, in which it was declared. Use file variables if you want to refer to the same variable in multiple requests within the same file.

To create file variable, type @variableName = variableValue above the Request Line section. For example:

@hostname = test.example.com
@port = 8633
@host = {{hostname}}:{{port}}
@contentType = application/json
@createdAt = {{$datetime iso8601}}

###

@userId=1

GET https://{{host}}/users/{{userId}} HTTP/1.1

###

@name=Jimmy Choo

POST https://{{host}}/users?name={%name} HTTP/1.1
Content-Type: {{contentType}}

{
    "content": "foo bar",
    "created_at": "{{createdAt}}"
}

Use the backslash \ to escape special characters in variable value as \n.

Use the percent % to url encode (with encodeURIComponent function) the variable value as {{%name}}.

Use the at sign @ to base64 encode the variable value as {{@name}}.

Dynamic variables

Dynamic variables generate a value each time you run the request. Their names start with $.

  • {{$guid}}: generate a v4 UUID
  • {{$processEnv [%]envVarName}}: access local machine environment variable value. If the sensitive information like secret keys which should not be committed to the code repository, store them in the local environment.

    Export environment values to shell or similar on windows:

    export INT_TOKEN=intintint
    export STAGE_TOKEN=stagestagestage
    export USER_NAME=useruser

    with environment variables:

    module.exports = {
      $restclients: {
        userAgent: "myRestclients",
      },
      $shared: {
        key1: "KEYYYY",
        key2: "KEYYY2",
      },
      int: {
        hostname: "int.example.com",
        token: "INT_TOKEN",
        key: "{{$shared key1}}",
      },
      stage: {
        hostname: "stage.example.com",
        token: "STAGE_TOKEN",
        key: "{{$shared key2}}",
      },
    };

    Access local environment variable by name (e.g. INT_TOKEN) in the HTTP file. The example for int environment is as follows:

    # Access INT_TOKEN from local machine environment
    GET https://test.example.com/users?user={{$processEnv USER_NAME}}
    Authorization: {{$processEnv INT_TOKEN}}

    %: optional, use the value of envVarName in environment variable to access local environment variables.

    # Access local machine environment variable by the value of token in environment variable
    # Access INT_TOKEN for `int` environment, and STAGE_TOKEN for `stage` environment
    GET https://test.example.com/users?user={{$processEnv USER_NAME}}
    Authorization: {{$processEnv %token}}
  • {{$dotenv [%]envVarName}}: access the environment value stored in the .env file. Default file path is .restclients.env, use the option -d to change the defalut file path.

  • {{$randomInt min max}}: generate a random integer between min (inclusive) and max (exclusive).

  • {{$timestamp [offset option]}}: generate current Unix timestamp with datetime offset from now.

    • 3 hours ago, for example {{$timestamp -3 h}}
    • the day after tomorrow, for example {{$timestamp 2 d}}
  • {{$datetime rfc1123|iso8601|"custom format"|'custom format' [offset option]}}: generate current UTC datetime string with datetime offset in ISO8601, RFC1123 or a custom format. custom format should be wrapped it in single or double quotes.

    • one year later in ISO8601 format, for example: {{$datetime iso8601 1 y}}
    • with custom datetime format, for example: {{$datetime "DD-MM-YYYY" 1 y}}
  • {{$localDatetime rfc1123|iso8601|"custom format"|'custom format' [offset option]}}: generate current local timezone datatime string with datetime offset in ISO8601, RFC1123 or a custom format. custom format should be wrapped it in single or double quotes. * one year later in ISO8601 format, for example: {{$localDatetime iso8601 1 y}}

    The offset options you can specify in `$timestamp`, `$datetime` and `$localDatetime` are:
    
    Option | Description
    -------|------------
    y      | Year
    M      | Month
    w      | Week
    d      | Day
    h      | Hour
    m      | Minute
    s      | Second
    ms     | Millisecond
  • Support register customized dynamic variables will come soon.

The example using dynamic variables is as follow:

POST https://test.example.com/users/1 HTTP/1.1
Content-Type: application/json
Authorization: {{$processEnv %token}}
Date: {{$datetime rfc1123}}

{
    "userName": "{{$dotenv USERNAME}}",
    "requestId": "{{$guid}}",
    "updatedAt": "{{$timestamp}}",
    "createdAt": "{{$timestamp -1 d}}",
    "randomInt": "{{$randomInt 5 200}}",
    "customDate": "{{$datetime 'YYYY-MM-DD'}}",
    "localDate": "{{$localDatetime 'YYYY-MM-DD'}}"
}

Scripting

Support to handle the response with Javascirpt. Use // @script file.js or # @script file.js to specify the path and name of the Javascript file.

The example using Javascript to save oauth token from response to dotenv file.

#### Get OAuth Token

# @script ./setOAuthToken.rcs.js
POST https://test.example.com/oauth/token
requestId: {{$guid}}
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id={{$dotenv CLIENT_ID}}
&client_secret={{$dotenv CLIENT_SECRET}}

setOAuthToken.rcs.js content is as follows:

function setEnvValue(key, value) {
  const { readFileSync, writeFileSync } = require("fs");
  const { EOL } = require("os");
  const ENV_VARS = readFileSync(option.dotenvFile, "utf8").split(EOL);

  const target = ENV_VARS.indexOf(
    ENV_VARS.find((line) => {
      const keyValRegex = new RegExp(`(?<!#\\s*)${key}(?==)`);

      return line.match(keyValRegex);
    })
  );

  if (target !== -1) {
    ENV_VARS.splice(target, 1, `${key}=${value}`);
  } else {
    ENV_VARS.push(`${key}=${value}`);
  }

  writeFileSync(option.dotenvFile, ENV_VARS.join(EOL));
}

(() => {
  logging.info("set OAuth2 token start");
  logging.info("request: %j", request);
  setEnvValue(
    "OAUTH2_TOKEN",
    JSON.parse(request.res.body)?.access_token
  );
})();

Run the script using Script.runInContext function. The context passed to function is as follows:

  • Context:
    • vars:
      • addEnvironmentVariable(key, value), add key/value to current environment variables
      • addFileVariable(key, value), add key/value to file variables
      • resolveVariables(...keys), resolve the value of the key in environment variables, prompt variables, file variables and dynamic variables.

        Use syntax resolveVariables([key1,key2,key3...]) and resolveVariables(key1,key2,key3,...)

    • request:
      • filename: current HTTP file absolute file path and file name
      • name: request name, the content after the starting ###
      • range: request line range, for example: 50,54
      • uri: the uri of the request, for example: file:///restclients/example/basic.rcs#L50-L54
      • header: request header defined in HTTP file
      • url: request url
      • method: request method
      • resolvedPromptVariable: the value of prompt variables
      • body: request body
      • scriptContent: content of the script to be executed, Buffer type
      • time: request cost time, for example: 932 ms
      • res:
        • statusCode: request response status code, for example 200
        • headers: response headers
        • body: response body, Buffer type
    • require(module): nodejs built-in require function
    • logging:
      • debug(firstArg, ...rest): debug levle logging
      • info(firstArg, ...rest): info levle logging
      • warn(firstArg, ...rest): warn levle logging
      • error(firstArg, ...rest): error levle logging

        Using util.format(format[, ...args]) to format message

    • option: running configuration, a frozen object and cannot be changed
      • rootDir: current root directory absolute file path, for example: /Workspace/restclients/example
      • httpClient: nodejs fetch client
      • dotenvFile: dotenv file path, for example: /Workspace/restclients/example/.env
      • settingFile: setting file path, for exmaple: /Workspace/restclients/example/example.config.js
      • environment: current selected environment, for example: int
      • filePattern: pattern to match the file path to be executed
      • namePattern: pattern to match the request name to be executed

Settings

Settings is also defined in setting file under the reserved key $restclients.

 module.exports = {
    $restclients: {
      userAgent: "myRestclients",
    }
    ....
 }
  • $restclients.userAgent: set the default user agent value in request header

ToDo

0.0.8

6 months ago

0.0.7

6 months ago

0.0.6

7 months ago

0.0.5

7 months ago

0.0.4

7 months ago

0.0.3

7 months ago

0.0.2

7 months ago

0.0.1

7 months ago