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
A simple program to display current playing from Spotify app on your desktop

WallSpot A simple program to display current playing from Spotify app on your desktop How to Use: Linux: Currently Supports GNOME and KDE. If you want

Nannan 4 Feb 19, 2022
Force-Subscribe-Bot - A Telegram Bot to force users to join a specific channel before sending messages in a group

Introduction A Telegram Bot to force users to join a specific channel before sen

LG Bot Updates 0 Jan 16, 2022
Discord bot built using Python. through this you can get information about the upcoming matches, scoreboard, live score

IPL-bot This is a Discord bot built using Python. through this you can get information about the upcoming matches, scoreboard, live score, and many mo

0 Dec 23, 2021
Python functions for opentargets.org API

What is opy_Targets? Opentargets.org uses GraphQL API to explore it's content via coding. This ensemble of functions aim is to make it easy to use the

1 Jan 10, 2022
Monitor your Binance portfolio

Binance Report Bot The intent of this bot is to take a snapshot of your binance wallet, e.g. the current balances and store it for further plotting. I

37 Oct 29, 2022
Download song lyrics and metadata from Genius.com 🎶🎤

LyricsGenius: a Python client for the Genius.com API lyricsgenius provides a simple interface to the song, artist, and lyrics data stored on Genius.co

John W. Miller 738 Jan 04, 2023
A Telegram Video Watermark Adder Bot

Watermark-Bot A Telegram Video Watermark Adder Bot by @VideosWaterMarkRobot Features: Save Custom Watermark Image. Auto Resize Watermark According to

5 Jun 17, 2022
veez music bot is a telegram music bot project, allow you to play music on voice chat group telegram.

🎶 Veez Music Bot Music bot for playing music on telegram voice chat group. Requirements 📝 FFmpeg NodeJS nodesource.com Python 3.7+ PyTgCalls 🧪 Get

levina 143 Jun 19, 2022
Twitter bot that turns comment chains into ace attorney scenes. Inspired by and using https://github.com/micah5/ace-attorney-reddit-bot

Ace Attorney twitter Bot Twitter bot that turns comment chains into ace attorney scenes. Inspired by and using https://github.com/micah5/ace-attorney-

Luis Mayo Valbuena 542 Dec 17, 2022
A github actions + python code to extract URLs to code repositories to put into standard form, starting with github

A github actions + python code to extract URLs to code repositories to put into standard form, starting with github ---- NOTE: JUS

Justin Gosses 2 Nov 15, 2021
iso6.9 is a Discord bot written in Python and is used to make your Discord experience better

iso6.9-2.6stable (debloated) iso.bot is originally made by notsniped#4573. This is a remix of iso.bot by αrchιshα#5518. iso6.9 is a Discord bot writte

Kamilla Youver 2 Jun 10, 2022
This is a scalable system that reads messages from public Telegram channels using Telethon and stores the data in a PostgreSQL database.

This is a scalable system that reads messages from public Telegram channels using Telethon and stores the data in a PostgreSQL database. Its original intention is to monitor cryptocurrency related ch

Greg 3 Jun 07, 2022
A simple test repo created following docker docs.

docker_sampleRepo A simple test repo created following docker docs. Link to docs: https://docs.docker.com/language/python/develop/ Other links: https:

Suraj Verma 2 Sep 16, 2022
A youtube search telegram bot.

YouTube-Search-Bot A youtube search telegram bot. Made with Python3 (C) @FayasNoushad Copyright permission under MIT License License - https://github

Fayas Noushad 22 Nov 12, 2022
Image-Bot-Discord - This Is a discord bot that shows the specific image you search from Google

Advanced Discord.py Image Bot CREDITS Made by RLX and Mathiscool README by Milrato Installation Guide in .env Adjust the TOKEN python main.py to start

RLX 3 Jan 16, 2022
Buy early bsc gems with custom gas fee, slippage, amount. Auto approve token after buy

Buy early bsc gems with custom gas fee, slippage, amount. Auto approve token after buy. Sell buyed token with custom gas fee, slippage, amount. And more.

Jesus Crypto 206 May 01, 2022
Unofficial instagram API, give you access to ALL instagram features (like, follow, upload photo and video and etc)! Write on python.

Instagram-API-python Unofficial Instagram API to give you access to ALL Instagram features (like, follow, upload photo and video, etc)! Written in Pyt

Vladimir Bezrukov 1 Nov 19, 2021
NiceHash Python Library and Command Line Rest API

NiceHash Python Library and Command Line Rest API Requirements / Modules pip install requests Required data and where to get it Following data is nee

Ashlin Darius Govindasamy 2 Jan 02, 2022
vk Bot because of which everyone will lag

VK-crash-bot open cmd and write: "pip install vk-api" To configure the bot, you need to open main.py and set the value to such variables as "token" an

NotQuki 0 Jun 05, 2022
search different Streaming Platforms for movie titles.

Install git clone and cd to directory install Selenium download chromedriver.exe to same directory First Run Use --setup True for the first run. Platf

34 Dec 25, 2022