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 discord bot written in python which can surf subreddits, send a random meme, jokes and also weather of a given place

A simple Discord Bot A simple discord bot written in python which can surf subreddits, send a random meme, jokes and also weather of a given place. We

1 Jan 24, 2022
A robust, low-level connector for the Discord API

Bauxite Bauxite is a robust, low-level connector for the Discord API. What is Bauxite for? Bauxite is made for two main purposes: Creating higher-leve

1 Dec 04, 2021
Twitter FakeNFT With Python

This project is a server that fetches your Twitter profile picture and applies the hexagonal transparency mask displayed on the profiles of users who have an NFT profile picture.

Mathis HAMMEL 29 Apr 23, 2022
Easy to use Google Pub/Sub

Relé makes integration with Google PubSub straightforward and easy. Motivation and Features The Publish-Subscribe pattern and specifically the Google

Mercadona 188 Jan 06, 2023
Neubot client

Neubot, the network neutrality bot Neubot is a research project on network neutrality of the Nexa Center for Internet & Society at Politecnico di Tori

Neubot 57 Nov 02, 2021
A python script for hitting the kik API to enumerate people based on a username/userlist

kick3d Recon script for enumerating users off of the Kik API. This script has the ability to check single usernames or run through a userlist of usern

Sakura Samurai 19 Oct 04, 2021
Generate discord nitro codes and check them

Discord Nitro Generator and Checker A discord nitro generator and checker for all your nitro needs Explore the docs » Report Bug · Request Feature · J

509 Jan 02, 2023
Python bindings for BigML.io

BigML Python Bindings BigML makes machine learning easy by taking care of the details required to add data-driven decisions and predictive power to yo

BigML Inc, Machine Learning made easy 271 Dec 27, 2022
A Telegram Bin Checker Bot made with python for check Bin valid or Invalid. 💳

Bin Checker Bot A Telegram Bin Checker Bot made with python for check Bin valid or Invalid. 📌 Deploy On Heroku 🏷 Environment Variables API_ID - Your

Chamindu Denuwan 20 Dec 10, 2022
The worst but simplest webhook bot for GitHub and Matrix.

gh-bot gh-bot is maybe the worst (but simplest) Matrix webhook bot for Github. Example of commits: Example of workflow finished: Setting up Server You

Jae Lo Presti 4 Aug 18, 2022
Python interface to the World Bank Indicators and Climate APIs

wbpy A Python interface to the World Bank Indicators and Climate APIs. Readthedocs Github source World Bank API docs The Indicators API lets you acces

Matt Duck 47 Oct 31, 2022
A simple Python wrapper for the archive.is capturing service

archiveis A simple Python wrapper for the archive.is capturing service. Installation pipenv install archiveis Python Usage Import it. import archi

Ben Welsh 157 Dec 28, 2022
Discord bots that update their status to the price of any coin listed on x.vite.net

Discord bots that update their status to the price of any coin listed on x.vite.net

5am 3 Nov 27, 2022
An NFTGenerator to generate NFTs and send them to nft.storage

NFTGenerator Table of Contents Overview Installation Introduction Features Reflection Issues & bug reports Show your support Credits Overview The NFTG

3 Mar 14, 2022
⚡ ʑɠ ცơɬ Is One Of The Fastest & Smoothest Bot On Telegram Based on Telethon ⚡

『ʑɠ ცơɬ』 ⚡ ʑɠ ცơɬ Is One Of The Fastest & Smoothest Bot On Telegram Based on Telethon ⚡ Status Of Bot Telegram 🏪 Dєρℓογ το нєяοκυ Variables APP_ID =

ʑɑʑɓɦɑɪ 0 Feb 12, 2022
This repository are used to give class about AWS

AWSTraining This repository are used to give class about AWS by Marco Antonio Pereira Linkedin: https://www.linkedin.com/in/marcoap To see the types o

Marco Antonio Pereira 6 Nov 23, 2022
EZPZ-PGP: This is a simple and easy to use PGP tool.

EZPZ-PGP This is a simple and easy to use PGP tool. Features [X] Create new PGP Keypairs, able to choose between 4096 and 8192 bit keys.\n [X] Import

6 Dec 30, 2022
A tool for creating credentials for accessing S3 buckets

s3-credentials A tool for creating credentials for accessing S3 buckets For project background, see s3-credentials: a tool for creating credentials fo

Simon Willison 138 Jan 06, 2023
A Python module for communicating with the Twilio API and generating TwiML.

twilio-python The default branch name for this repository has been changed to main as of 07/27/2020. Documentation The documentation for the Twilio AP

Twilio 1.6k Jan 05, 2023
An instagram bot developed in Python with Selenium that helps you get more Instagram followers.

instabot An instagram bot developed in Python with Selenium that helps you get more Instagram followers. Install You’ll need to have: Python Selenium

65 Nov 22, 2022