2 releases (1 stable)

1.0.0 Jul 27, 2023
0.1.0 Jun 30, 2023

#1586 in Web programming

MIT license

62KB
1.5K SLoC

License crates.io docs.rs

apictl

apictl is a command-line application for interacting with APIs. See the documentation below or run apictl help for details.

Installation

Binaries are available via releases.

You can also install it using cargo:

cargo install apictl

Getting Started

Example

This repository includes an example .apictl.yaml file. It interacts with Typicode's json-server. You can install it via npm and then run it in some other shell:

npm install -g json-server
json-server http://jsonplaceholder.typicode.com/db

You should now be able to clone this repository run the examples within it:

git clone https://github.com/icub3d/apictl
cd apictl
apictl requests list
apictl requests run -c local get-posts get-user-from-first-post
apictl requests run -c local new-post get-new-post

From Scratch

If you have an existing API you'd like to use, start by creating a configuration for it. It is common for the configuration to be in the repository in which the API is created.

Next, create contexts for the various environments that you'll be using.

Then create requests for any API calls you are interested in running.

Finally, do, some testing on your configuration before publishing your code.

Configuration

You can look at .apictl.yaml for an example configuration. Configurations are defined using YAML. By default, apictl will look for a file named .apictl.yaml in the current directory.

If your project is large enough, you can use a folder to store multiple configuration files. To do this, run apictl with the flag --config CONFIG where CONFIG is the path to your folder. Folder are read in sorted order and configuration are merged. When information overlaps (e.g. two requests with the same name) the later overwrites the former.

Details on values within the configuration can be found below.

Contexts

Contexts are ways to define variables for your API calls. Within your configurations, they are created under the contexts key. Each context is a map that contains the variables and the values to replace. For example, suppose you want to differentiate the URL to use in requests for your local, dev, staging, and prod environments. You might do it like this:

contexts:
  local:
    base_url: http://localhost:3000
  dev:
    base_url: https://dev.app
  staging:
    base_url: https://staging.app
  prod:
    base_url: https://my-cool-api.com

You can now use the variable base_url in your requests and it will be replaced with the value based on the context given. If you want to run a request using dev, you'd add a flag --context dev.

Currently, all variables within the request are replaced if they are strings. If the body contains strings, they are replaced. File references will have their path replaced but not the actual content.

Variables

Once you have your contexts defined, you can using them in your configuration using the pattern ${name} where name is the key in the context.

Multiple Contexts

You can use multiple contexts which are merged in a similar fashion to configurations. This may be useful when you have multiple interactions that may not overlap. For example, you might have multiple authentication mechanisms you'd like to test for the same API. You can use a context for the environment and then for the authentication method.

To use multiple contexts, simply add multiple context flags to your command: --context basic-auth --context local.

Requests

Requests are API endpoints and the information necessary to make the requests. They are They also contain basic information like tags and descriptions that can be used for searching for requests.

Within your configurations, they are created under the requests key. They contain configuration for including the request method, url, query parameters, headers, and the body. All but the body is self-explanatory. Here is an example request:

requests:
  get-posts:
    tags: [get]
    description: a simple get
    url: "${base_url}/posts"
    query_parameters:
      _limit: "${pagination_limit}"

Body

The request body can come in several forms. This section describes each of them in detail and how to use them. Each body type is described by the type field.

Form

If you just want to submit key/value pairs, You can use the "form" type and it will POST a application/x-www-form-urlencoded. An example of this:

requests:
  new-post:
    tags: [post]
    description: an example post using the form type
    url: "${base_url}/posts"
    method: POST
    body:
      type: form
      data:
        name: World
        age: 4.543 billion years

Multi-part Form

If you have files you want to send, you'll probably want to use the multipart format. It works similar to the From but allows you to specify each field's type, You use the "multipart" type and it will POST a multi-part message. An example of this:

requests:
  new-post:
    tags: [post]
    description: an example post using the multipart type
    url: "${base_url}/posts"
    method: POST
    body:
      type: multipart
      data:
        name:
          type: text
          data: World
        age:
          type: text
          data: 4.543 billion years
        avatar:
          type: file
          path: ./avatar.png

The "file" type will expect a file at the given path and put it's contents in the form submission.

Raw

If you just want to submit a raw body, use the "raw" type. The data can come from text or a file and will send the contents as the body. An example of using text:

requests:
  new-post:
    tags: [post]
    description: an example post using the raw type
    url: "${base_url}/posts"
    method: POST
    body:
      type: raw
      from:
        type: text
        data: |
          {
            "userId": 1,
            "title": "test post",
            "body": "This is a test post to the json server."
          }

And an example of using a file:

requests:
  new-post:
    tags: [post]
    description: an example post using the raw type
    url: "${base_url}/posts"
    method: POST
    body:
      type: raw
      from:
        type: file
        path: ./new-post-body.json

Dependencies

~15–30MB
~454K SLoC