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
Elemeno.ai standard development kit in Python

Overview A set of glue code and utilities to make using elemeno AI platform a smooth experience Free software: Apache Software License 2.0 Installatio

Elemeno AI 3 Dec 14, 2022
ВКонтакте бот для управления Sugar кошельком

Sugarchain VK ВКонтакте бот для управления Sugar кошельком Установка Установить зависимости можно командой: pip install -r requirements.txt Запуск (из

Vladimir 4 Jun 06, 2021
API Basica per a synologys Active Backup For Buissiness

Synology Active Backup for Business API-NPP Informació Per executar el programa

Nil Pujol 0 May 13, 2022
OpenQuake's Engine for Seismic Hazard and Risk Analysis

OpenQuake Engine The OpenQuake Engine is an open source application that allows users to compute seismic hazard and seismic risk of earthquakes on a g

Global Earthquake Model 281 Dec 21, 2022
自用直播源集合,附带检测与分类功能。

myiptv 自用直播源集合,附带检测与分类功能。 为啥搞 TLDR: 太闲了。 自己有收集直播源的爱好,和录制直播源的需求。 一些软件自带的直播源太过难用。 网上现有的直播源太杂,且缺乏检测。 一些大源缺乏持续更新,如 iptv-org。 使用指南与 TODO 每次进行大更新后都会进行一次 rel

abc1763613206 171 Dec 11, 2022
Lambda-function - Python codes that allow notification of changes made to some services using the AWS Lambda Function

AWS Lambda Function This repository contains python codes that allow notificatio

Elif Apaydın 3 Feb 11, 2022
a simple python script that monitors the binance hotwallet and refunds the withdrawal fee to encourage people to withdraw their Nano and help decentralisation

Nano_Binance_Refund_Bot a simple python script that monitors the binance hotwallet and refunds the withdrawal fee to encourage people to withdraw thei

James Coxon 5 Apr 07, 2022
A Pythonic client for the official https://data.gov.gr API.

pydatagovgr An unofficial Pythonic client for the official data.gov.gr API. Aims to be an easy, intuitive and out-of-the-box way to: find data publish

Ilias Antonopoulos 40 Nov 10, 2022
Leveraged grid-trading bot using CCXT/CCXT Pro library in FTX exchange.

Leveraged-grid-trading-bot The code is designed to perform infinity grid trading strategy in FTX exchange. The basic trader named Gridtrader.py contro

Hao-Liang Wen 25 Oct 07, 2021
Python API for working with RESQML models

resqpy: Python API for working with RESQML models Introduction resqpy is a pure python package which provides a programming interface (API) for readin

BP 44 Dec 14, 2022
Instagram bot for promoting ROKA trainee soldier(just like me)'s consolation letters.

Instagram_bot (필자를 포함한) 모든 대한민국 훈련병들을 위한 인스타그램 인편지기입니다. Instagram bot for promoting ROKA trainee soldier(just like me)'s consolation letters. 들어가기 (Ge

Lee, Jongjun 2 Nov 21, 2021
Recommended AWS CDK project structure for Python applications

Recommended AWS CDK project structure for Python applications The project implements a user management backend component that uses Amazon API Gateway,

AWS Samples 110 Jan 06, 2023
A Collection Manager for the objkt.com Minting Factory

Objkt Collection Manager A Collection Manager for the objkt.com Minting Factory. This contract can create a collection on objkt.com and mint into it.

Asbjorn Enge 5 Nov 22, 2022
A code to match you with the perfect Taylor Swift song for your mood and relationship status.

taylorswift A package for matching your current mood and relationship status to a suitable Taylor Swift song. Requirements: Python 2 or 3, and the num

Megan Mansfield 82 Dec 09, 2022
My beancount practice as a template

my-beancount-template 个人 Beancount 方案的模板仓库 相关博客 复式记账指北(一):What and Why? 复式记账指北(二):做账方法论 复式记账指北(三):如何打造不半途而废的记账方案 配置 详细配置请参考博客三。必须修改的配置有: Bot功能:data/be

KAAAsS 29 Nov 29, 2022
Backend for Indipe client

Betsushi Betsu (別), the japanese word meaning "another" and Shiharai (支払い) meaning "payment". Hence the name Betsushi was derived. Introduction This i

Sudodevs 3 Feb 09, 2022
Python Library to Extract youtube video Tags without Youtube API

YoutubeTags Python Library to Extract youtube video Tags without Youtube API Installation pip install YoutubeTags Example import YoutubeTags from Yout

Nuhman Pk 17 Nov 12, 2022
Python CMR is an easy to use wrapper to the NASA EOSDIS Common Metadata Repository API.

This repository is a copy of jddeal/python_cmr which is no longer maintained. It has been copied here with the permission of the original author for t

NASA 9 Nov 16, 2022
This is telegram bot to generate string session for using user bots. You can see live bot in https://telegram.dog/string_session_Nsbot

TG String Session Generate Pyrogram String Session Using this bot. Demo Bot: Configs: API_HASH Get from Here. API_ID Get from Here. BOT_TOKEN Telegram

Anonymous 27 Oct 28, 2022
Archive tweets and make them searchable

Tweeter Archive and search your tweets and liked tweets using AWS Lambda, DynamoDB and Elasticsearch. Note: this project is primarily being used a tes

Kamil Sindi 8 Nov 18, 2022