Skip to main content

A small REST client that refills your batteries

Project description

PowerNap

Deployed to PyPI GitHub Repository Continuous Integration Coverage MIT License Contributor Covenant

A small REST client that recharges your batteries

PowerNap is a simplistic JSON REST API client, a small wrapper around httpx that makes your code read slightly better.

Installation

$ pip install powernap

Usage

# You will need an httpx Client. Let's do a GitHub client!
httpx_client = httpx.Client(
    base_url="https://api.github.com/v3",
    headers={"Authorization": f"token {token}"}
)

# Instantiate the PowerNap client
github_client = powernap.PowerNap(httpx_client=httpx_client)

# PowerNap will help you build complex URLs in a pythonic-looking way:
repo = github_client.repos("ewjoachim/powernap").get()

# And access the json responses like objects
count_stars = repo.stargazers_count

# You can also easily send POST requests.
github_client.repos("ewjoachim/powernap").issues(42).comments.post(
    body=f"Wow look! This repo has {count_stars} stars!"
)

Build complex URLs

You can use client(something) or client.something, and chain calls. With the form client(something), you can pass multiple parameters, and they will be joined together

# The next calls are all identical and target:
#    {base_url}/repos/ewjoachim/powernap/stargazers
github_client.repos("ewjoachim/powernap").stargazers.get()
github_client.repos("ewjoachim").powernap("stargazers").get()
github_client.repos("ewjoachim", "powernap", "stargazers").get()
github_client.repos("ewjoachim", "powernap")("stargazers").get()
github_client("repos/ewjoachim/powernap/stargazers").get()

# The recommended way is to use client.something for static parts of the url and
# client(something) with a variable for dynamic parts.

# You can also target the base url directly
# {base_url}
github_client().get()

Access the json responses like objects

On the json responses, all objects (even nested) are configured so that you can get keys with the object.key syntax in addition to the classic object["key"].

# GET /nested_json -> {"a": {"b":{"c": "d"}}}
response = some_api_client.nested_json.get()

assert response == {"a": {"b":{"c": "d"}}}
assert response["a"]["b"]["c"] == "d"
# But also the magic form:
assert response.a.b.c == "d"

Arguments

The arguments in the .get/delete() calls are used as query parameters on the call.

The arguments in the .post/put/patch() calls are put together, and passed as the json payload for the call.

Response types

If the response comes with Content-Type: application/json, then you'll get the "magic" json response as described above. Otherwise, if the content type is text/*, you'll get a string, and otherwise, you'll get bytes.

Exceptions

If you want to avoid httpx exceptions to reach your code, so as to maintain a good abstraction layer, you may want to subclass Powernap and implement handle_exception(self, exc). You'll receive an httpx.HttpError and it's your responsibility to raise whatever exception you see fit. Not raising an exception in this context is considered as an error, though.

from typing import NoReturn

class ApiError(MyProjectError):
    pass

class ForbiddenError(ApiError):
    pass

class ApiClient(PowerNap):
    def handle_exception(self, exc: httpx.HttpError) -> NoReturn:
        if exc.response.status_code == 403:
            raise ForbiddenError
        raise ApiError

More control over input and output

This magic is nice and all, but sometimes, you may want more control. If you want to send additional headers or a non-JSON-dict payload, or if you want to read the headers on the response, it possible too.

Instead of calling .get(), use either .get.i(), .get.o() or .get.io() (it works with any method: get/post/put/patch/delete):

  • If you call with .get.i(...) (or .get.io(...)), you control the input. The method keyword arguments will be passed to the underlying httpx.Client().get(...) as-is.
  • If you call with .get.o(...) (or .get.io(...)), you get the original output. The function will return a httpx.Response object. (Note that in this case, we will still have called .raise_for_status())

If you regularly use get.io(), it's probably that PowerNap is probably not the project you need. Use httpx.Client directly, build something to help you craft URLs (you can steal copy the relevant code, don't forget to copy the license too)

Name

While looking for a name for this lib, I looked at all the synonyms for "small rest". It's amazing how many other projects have gone the same route. To name a few:

  • nap looks awesome! Unrelated lib but same goals as this one. Seems unmaintained but I'm not sure a lib like this needs a lot of maintenance.
  • catnap
  • respite
  • snooze is not taken but snooze-server is and I didn't want to create confusion.

Funnily enough, a consequent number of those projects have the same goals as this one, yet don't have the exact look and feel I'm trying to achieve.

Credits where due

This lib is heavily inspired from githubpy, which is under Apache license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

powernap-2.0.0.tar.gz (6.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

powernap-2.0.0-py3-none-any.whl (6.9 kB view details)

Uploaded Python 3

File details

Details for the file powernap-2.0.0.tar.gz.

File metadata

  • Download URL: powernap-2.0.0.tar.gz
  • Upload date:
  • Size: 6.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for powernap-2.0.0.tar.gz
Algorithm Hash digest
SHA256 1879bf74e68c2b821edf871a489322fc45c56c8caa766c421dea4a68d32abf59
MD5 b15a0f21edb1e5444bb32f358a5d9249
BLAKE2b-256 e89fa59df9ba47d48924fdf3d495be7e7ca60ad4a305674d697941a9a0b20694

See more details on using hashes here.

Provenance

The following attestation bundles were made for powernap-2.0.0.tar.gz:

Publisher: ci.yml on ewjoachim/powernap

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file powernap-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: powernap-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 6.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for powernap-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1edcd298ba70ac0dbd4e8141a4cb73d01cb468ff681d55365b50e7098d16a02a
MD5 a3d5ad05b279b827cbcc37b7139f4b12
BLAKE2b-256 4884f1085e316818fb8e5fd95643b15b449eda242a8a123808c142fd2ce21f9c

See more details on using hashes here.

Provenance

The following attestation bundles were made for powernap-2.0.0-py3-none-any.whl:

Publisher: ci.yml on ewjoachim/powernap

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page