Stop writing scripts to interact with your APIs. Call them as CLIs instead.

Overview

Zum

Stop writing scripts to interact with your APIs. Call them as CLIs instead.

PyPI - Version Tests Coverage Linters

Zum (German word roughly meaning "to the" or "to" depending on the context, pronounced /tsʊm/) is a tool that lets you describe a web API using a TOML file and then interact with that API using your command line. This means that the days of writing custom scripts to help you interact and develop each of your APIs are over. Just create a zum.toml, describe your API and forget about maintaining more code!

Why Zum?

While there are tools out there with goals similar to zum, the scopes are quite different. The common contenders are OpenAPI-based tools (like SwaggerUI) and cURL. To me, using an OpenAPI-based documentation tool is essential on any large enough API, but the description method is very verbose and quite complex, so often times it is added once the API has quite a few endpoints. On the other hand, cURL gets very verbose and tedious very fast when querying APIs, so I don't like to use it when developing my APIs. As a comparison, here's a curl command to query a local endpoint with a JSON body:

curl --header "Content-Type: application/json" \
    --request POST \
    --data '{"name": "Dani", "city": "Santiago"}' \
    http://localhost:8000/living-beings

And here is the zum command to achieve the same result:

zum create application/json Dani Santiago

Now, imagine having to run this command hundreads of times during API development changing only the values on the request body, for example. You can see how using cURL is not ideal.

The complete documentation is available on the official website.

Installation

Install using pip!

pip install zum

Usage

Basic Usage

The basic principle is simple:

  1. Describe your API using a zum.toml file.
  2. Use the zum CLI to interact with your API.

We get more in-depth with how to structure the zum.toml file and how to use the zum CLI on the complete documentation, but for now let's see a very basic example. Imagine that you are developing an API that gets the URL of a song on YouTube. This API, for now, has only 1 endpoint: GET /song (clearly a WIP). To describe your API, you would have to write a zum.toml file similar to this one:

[metadata]
server = "http://localhost:8000"

[endpoints.dada]
route = "/song"
method = "get"

Now, to get your song's URL, all you need to do is to run:

zum dada

Notice that, after the zum command, we passed an argument, that in this case was dada. This argument tells zum that it should interact with the endpoint described on the dada endpoint section, denoted by the header [endpoints.dada]. As a rule, to access an endpoint described by the header [endpoints.{my-endpoint-name}], you will call the zum command with the {my-endpoint-name} argument:

zum {my-endpoint-name}

params, headers and body

Beware! There are some nuances on these attribute definitions, so reading the complete documentation is highly recommended.

The params of an endpoint

On the previous example, the route was static, which means that zum will always query the same route. For some things, this might not be the best of ideas (for example, for querying entities on REST APIs), and you might want to interpolate a value on the route string. Let's say that there's a collection of songs, and you wanted to get the song with id 57. Your endpoint definition should look like the following:

[endpoints.get-song]
route = "/songs/{id}"
method = "get"
params = ["id"]

As you can see, the element inside params matches the element inside the brackets on the route. This means that whatever parameter you pass to the zum CLI, it will be replaced on the route on-demand:

zum get-song 57

Now, zum will send a GET HTTP request to http://localhost:8000/songs/57. Pretty cool!

The headers of an endpoint

The headers are defined exactly the same as the params. Let's see a small example to illustrate how to use them. Imagine that you have an API that requires JWT authorization to GET the songs of its catalog. Let's define that endpoint:

[endpoints.get-authorized-catalog]
route = "/catalog"
method = "get"
headers = ["Authorization"]

Now, to acquire the catalog, we would need to run:

zum get-authorized-catalog "Bearer super-secret-token"

::: warning Warning Notice that, for the first time, we surrounded something with quotes on the CLI. The reason we did this is that, without the quotes, the console has no way of knowing if you want to pass a parameter with a space in the middle or if you want to pass multiple parameters, so it defaults to receiving the words as multiple parameters. To stop this from happening, you can surround the string in quotes, and now the whole string will be interpreted as only one parameter with the space in the middle of the string. This will be handy on future examples, so keep it in mind. :::

This will send a GET request to http://localhost:8000/catalog with the following headers:

{
    "Authorization": "Bearer super-secret-token"
}

And now you have your authorization-protected music catalog!

The body of an endpoint

Just like params and headers, the body (the body of the request) gets defined as an array:

[endpoints.create-living-being]
route = "/living-beings"
method = "post"
body = ["name", "city"]

To run this endpoint, you just need to run:

zum create-living-being Dani Santiago

This will send a POST request to http://localhost:8000/living-beings with the following request body:

{
    "name": "Dani",
    "city": "Santiago"
}

Notice that you can also cast the parameters to different types. You can read more about this on the complete documentation's section about the request body

Combining params, headers and body

Of course, sometimes you need to use some params, some headers and a body. For example, if you wanted to create a song inside an authorization-protected album (a nested entity), you would need to use the album's id as a param, the "Authorization" key inside the headers to get the authorization and the new song's data as the body. For this example, the song has a name (which is a string) and a duration in seconds (which is an integer). Let's describe this situation!

[endpoints.create-song]
route = "/albums/{id}/songs"
method = "post"
params = ["id"]
headers = ["Authorization"]
body = [
    "name",
    { name = "duration", type = "integer" }
]

Now, you can call the endpoint using:

zum create-song 8 "Bearer super-secret-token" "Con Altura" 161

This will call POST /albums/8/songs with the following headers:

{
    "Authorization": "Bearer super-secret-token"
}

And the following request body:

{
    "name": "Con Altura",
    "duration": 161
}

As you can probably tell, zum receives the params first on the CLI, then the headers and then the body. In pythonic terms, what zum does is that it kind of unpacks the three arrays consecutively, something like the following:

arguments = [*params, *headers, *body]
zum(arguments)

Developing

Clone the repository:

git clone https://github.com/daleal/zum.git

cd zum

Recreate environment:

make get-poetry
make build-env

Run the linters:

make black flake8 isort mypy pylint

Run the tests:

make tests

Resources

Comments
  • Add 'number' as a body value type

    Add 'number' as a body value type

    Feature: Add 'number' as a body value type

    Description

    JSON does not define 'integer' and 'float' as valid data types, but rather merges them both into the 'number' data type. This PR includes 'number' as part of the data types, but does not remove 'integer' and 'float' for backward compatibility.

    I think that 'array' and 'object' should also be allowed (somehow).

    Requirements

    None.

    Additional changes

    None.

    feature wontfix 
    opened by ariel-m-s 2
  • Add type support to the body parameters

    Add type support to the body parameters

    Feature: Add type support to the body parameters

    Description

    Now, the request body parameters can be casted on request. To do that, you can specify the type to cast using the following syntax:

    body = [
        { name = "parameter1", type = "integer" },
        { name = "parameter2", type = "boolean" }
    ]
    

    The possible types can be found at zum/constants.py, on the variable REQUEST_BODY_VALUE_TYPES. Note that you can still declare only the name of the variable as a string instead of declaring the variable as an object. You can even declare the object without declaring its type. An example would be:

    body = [
        "parameter1",
        { name = "parameter2", type = "float" },
        { name = "parameter3" }
    ]
    

    On that example, parameter1 will be a string, parameter2 will be a float and parameter3 will also be a string.

    Closes #6.

    Requirements

    None.

    Additional changes

    None.

    feature 
    opened by daleal 1
  • Add a test battery

    Add a test battery

    Chore: Add a test battery

    Description

    This Pull Request adds quite a few tests to improve the coverage and assure some level of security over the functionalities. This tests mainly cover the configs and requests modules. The executor, engine and cli modules are still untested.

    Closes part of #7.

    Requirements

    None.

    Additional changes

    Some validations were added to the config validators.

    chore tests 
    opened by daleal 1
  • Fix `--version` command

    Fix `--version` command

    Bugfix: Fix --version command

    Description

    This Pull Request fixes the --version command by catching the config exceptions on the engine initialization and re-raising them on the engine execution. This allows the --version command to run, even if there is no config file.

    Closes #10.

    Requirements

    None.

    Additional changes

    None.

    bugfix 
    opened by daleal 1
  • Add documentation

    Add documentation

    Docs: Add documentation

    Description

    This Pull Request adds some documentation to the project, mainly about the zum.toml file.

    Requirements

    None.

    Additional changes

    Update Poetry's version on the Makefile.

    documentation 
    opened by daleal 1
  • Re-architect zum

    Re-architect zum

    Chore: Re-architect zum

    Description

    This Pull Request re-writes almost the whole codebase to be a bit more flexible. This is by no means a clean version of the library yet, but it is now quite a bit more structured compared to how it was written before.

    Requirements

    None.

    Additional changes

    Some classes were renamed (for example, Executor is now called Engine). Now the engine saves a state that can be retrieved, instead of directly printing the output to the console.

    chore design refactor 
    opened by daleal 1
  • Add support for URL parameters and JSON body (strings only)

    Add support for URL parameters and JSON body (strings only)

    Feature: Add support for URL parameters and JSON body (strings only)

    Description

    Now, zum can interpolate URL params directly and send a body with the request (for now, only strings are sent).

    Requirements

    None.

    Additional changes

    None.

    feature 
    opened by daleal 1
  • Fix punctuation typos

    Fix punctuation typos

    Chore: Fix minor typos in punctuation marks

    Description

    Add a missing period (.) to README.md and remove a period from CONTRIBUTING.md.

    Requirements

    None.

    Additional changes

    None.

    documentation 
    opened by ariel-m-s 0
  • Documentation changes

    Documentation changes

    Docs: Documentation changes

    Description

    Fix some README errors and add a CONTRIBUTING.md file to the repo.

    Requirements

    None.

    Additional changes

    None.

    documentation 
    opened by daleal 0
  • Add CLI param for config file

    Add CLI param for config file

    Feature: Add CLI param for config file

    Description

    This Pull Request adds the option for a filename to be passed through the CLI.

    Closes #39.

    Requirements

    None.

    Additional changes

    Some very small refactoring occured, and so some tests were moved.

    feature 
    opened by daleal 0
  • Fix a README inline code block

    Fix a README inline code block

    Docs: Fix an inline code block on the README

    Description

    There's a small typo on a GET. Should be GET and was GET

    Requirements

    None.

    Additional changes

    None.

    documentation 
    opened by naquiroz 0
  • JSONDecodeError upon empty response body

    JSONDecodeError upon empty response body

    A JSONDecodeError (from the built-in json library) is raised for HTTP responses with an empty body (which is, naturally, not a JSON). I don’t think this is the expected behavior.

    json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
    

    I guess the expected behavior should be to return an empty string.

    bug 
    opened by ariel-m-s 3
  • Add CLI default help message

    Add CLI default help message

    I think that showing a help message when using the CLI in a wrong way would be helpful. For instance, when typing zum (without any arguments), the CLI currently outputs an exception (as shown bellow). I find this to be a little aggresive for newcomers (like me) who are beginning to experiment with Zum.

    Traceback (most recent call last):
      File "/usr/local/bin/zum", line 8, in <module>
        sys.exit(dispatcher())
      File "/usr/local/lib/python3.9/site-packages/zum/cli.py", line 22, in dispatcher
        engine.execute(parsed_args.action[0], parsed_args.params)  # pragma: nocover
    AttributeError: 'Namespace' object has no attribute 'action'
    

    This help message should’t be as complete as the documentation, but should provide some practical information such as a list of commands and possible arguments.

    proposal 
    opened by ariel-m-s 2
  • Implement support for using a JSON file as request body.

    Implement support for using a JSON file as request body.

    [Feature]: Support for using files as request bodies. May resolve issue #8

    Description

    This pull request adds support for using the contents of a file as the JSON body of a request. This is currently done by providing a bodyPath variable in the zum.toml file. If the file path exists and contains a file, the contents of the file are read and parsed as JSON. The contents of the file are then sent with the request.

    If the user provides both a body and bodyPath variable like:

    [endpoints.test-post]
    route = "/test-post"
    method = "post"
    body = ["arg1", "arg2"]
    bodyPath = "/some/path/to/request_body_file"
    

    the contents of body are ignored and the file located at bodyPath is used instead.

    Requirements

    None.

    Additional changes

    Added tests for the new functionality.

    feature 
    opened by sehnsucht13 1
  • Expose request timeouts

    Expose request timeouts

    It would be nice to have control over the request timeouts. I think that a default metadata could be added and each endpoint could ovewrite it if specified.

    feature proposal 
    opened by daleal 0
Releases(0.3.0)
Owner
Daniel Leal
Software Engineer at NotCo and Computer Science Student
Daniel Leal
Telegram group manager moderen and simple.

Upin Robot A Advanced Powerful, Smart And Intelligent Group Management Bot With New And Powerful Features ... Written with Pyrogram and Telethon... If

Muhammad Nawawi 3 Dec 23, 2021
Bill is a bot capable to Chat with you, search everything on web to you, and send message to yours contacts for you.

Bill Bot The inteligent Bot Bill is a intelligent bot, it can chat, search and send messages to you. Chat with You Send messages on WhatsApp for you S

João Assalim 3 Sep 12, 2021
YuuScource - A Discord bot made with Pycord

Yuu A Discord bot made with Pycord Features Not much lol • Easy to use commands

kekda 9 Feb 17, 2022
Morpy Bot Linux - Morpy Bot Linux With Python

Morpy_Bot_Linux Guide to using the robot : 🔸 Lsmod = to identify admins and st

2 Jan 20, 2022
A minimalist file manager for those who want to use Linux mobile devices.

Portfolio A minimalist file manager for those who want to use Linux mobile devices. Usage Tap to activate and press to select, to browse, open, copy,

Martin Abente Lahaye 71 Nov 18, 2022
Riffdog Terraform scanner - finding 'things' in the Real World (aka AWS) which Terraform didn't put there.

riffdog Riffdog Terraform / Reality scanner - finding 'things' in the Real World which Terraform didn't put there. This project works by firstly loadi

Riffdog 4 Mar 23, 2020
Solves bombcrypto newest captcha

Solves Bombcrypto newest captcha A very compact implementation using just cv2 and ctypes, ready to be deployed to your own project. How does it work I

19 May 06, 2022
GitHub Actions Docker training

GitHub-Actions-Docker-training Training exercise repository for GitHub Actions using a docker base. This repository should be cloned and used for trai

GitHub School 1 Jan 21, 2022
Most Powerful Chatbot On Telegram Bot

About Hello, I am Lycia [リュキア], An Intelligent ChatBot. If You Are Feeling Lonely, You can Always Come to me and Chat With Me! How To Host The easiest

RedAura 8 May 26, 2021
Aria/qBittorrent Telegram mirror/leech bot.

Missneha Mirror Leech Bot Aria/qBittorrent Telegram mirror/leech bot. missneha Mirror Leech Bot is a multipurpose Telegram Bot written in Python for m

ACHAL 6 Sep 30, 2022
A simple Python script using Telethon to log all (or some) messages a user or bot account can see on Telegram.

telegram-logger A simple Python script using Telethon to log all (or some) messages a user or bot account can see on Telegram. Requirements Python 3.6

Richard 13 Oct 06, 2022
Best DDoS Attack Script Python3, Cyber Attack With 40 Methods

MXDDoS - DDoS Attack Script With 40 Methods (Code Lang - Python 3) Please Don't Attack '.gov' and '.ir' Websites :) Features And Methods 💣 Layer7 GET

7 Mar 07, 2022
Telegram bot to trim and download videos from youtube.

Inline-YouTube-Trim-Bot Telegram bot to trim and download youtube videos Deploy You can deploy this bot anywhere. Demo - YouTubeBot Required Variables

SUBIN 56 Dec 11, 2022
A simple Telegram bot that can add caption to any media on your channel

Channel Auto Caption This bot can add a caption for any media/document sent to a channel. Just deploy bot and add bot as admin to a channel. Deploy to

22 Nov 14, 2022
Elon Muschioso is a Telegram bot that you can use to manage your computer from the phone.

elon Elon Muschioso is a Telegram bot that you can use to manage your computer from the phone. what does it do? Elon Muschio makes a connection from y

4 Feb 28, 2022
An async-ready Python wrapper around FerrisChat's API.

FerrisWheel An async-ready Python wrapper around FerrisChat's API. Installation Instructions Linux: $ python3.9 -m pip install -U ferriswheel Python 3

FerrisChat 8 Feb 08, 2022
A modular dynamical-systems model of Ethereum's validator economics.

CADLabs Ethereum Economic Model A modular dynamical-systems model of Ethereum's validator economics, based on the open-source Python library radCAD, a

CADLabs 104 Jan 03, 2023
:evergreen_tree: Python module for communicating with the Taiga API

python-taiga A python wrapper for the Taiga REST API. Documentation: https://python-taiga.readthedocs.io/ Usage: : https://python-taiga.readthedocs.io

Nephila 87 Oct 12, 2022
2b2t Priority queue discord bot announcer

2b2t Priority queue discord bot announcer Commands !prioq - Checks the priority queue length and sends it. !start - Starts a loop that sends the sta

Gumi 5 Jun 06, 2022
A Sublime Text plugin that displays inline images for single-line comments formatted like `// ![](example.png)`.

Inline Images Sometimes ASCII art is not enough. Sometimes an image says more than a thousand words. This Sublime Text plugin can display images inlin

Andreas Haferburg 8 Jul 01, 2022