Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright 2025 Malte Mindedal

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
92 changes: 65 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
# HTTP CLI
# PyFetch: A Lightweight HTTP CLI

A lightweight command-line interface for making HTTP requests. Built with Python,
this tool provides an easy way to make GET, POST, PUT, PATCH and DELETE requests with support for JSON data and customizable timeouts.
this tool provides an easy way to make GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS requests with support for JSON data, customizable timeouts, automatic retries on failures, and a verbose mode for detailed logging.

## Features

- Simple command-line interface
- Case-insensitive commands (GET/get, POST/post etc.)
- Support for GET, PUT, POST, PATCH and DELETE requests
- Support for GET, PUT, POST, PATCH, DELETE, HEAD, and OPTIONS requests
- JSON data handling for POST requests
- Customizable timeout settings
- Customizable timeout settings and automatic retries on failures
- Verbose mode for debugging: logs requests and responses
- Detailed response output
- Status code
- Response headers
- Response body
- Status code
- Response headers
- Response body (pretty-printed if JSON)
- Comprehensive error handling
- Built-in help system

Expand All @@ -23,7 +24,7 @@ this tool provides an easy way to make GET, POST, PUT, PATCH and DELETE requests

- Python 3.7 or higher
- pip (Python package installer)
- virtualenv *(recommended)*
- virtualenv _(recommended)_

### Setup

Expand All @@ -34,7 +35,7 @@ git clone https://github.com/yourusername/http-cli.git
cd http-cli
```

2. Create and activate a virtual environment *(recommended)*:
2. Create and activate a virtual environment _(recommended)_:

```bash
# Windows
Expand All @@ -58,22 +59,28 @@ pip install -e .

```bash
# Make a GET request
http_cli GET https://api.example.com
pyfetch GET https://api.example.com

# Make a POST request with JSON data
http_cli POST https://api.example.com -d '{"key": "value"}'
pyfetch POST https://api.example.com -d '{"key": "value"}'

# Update a resource with PUT
http_cli PUT https://api.example.com/users/1 -d '{"name": "John"}'
pyfetch PUT https://api.example.com/users/1 -d '{"name": "John"}'

# Partially update with PATCH
http_cli PATCH https://api.example.com/users/1 -d '{"email": "john@example.com"}'
pyfetch PATCH https://api.example.com/users/1 -d '{"email": "john@example.com"}'

# Delete a resource
http_cli DELETE https://api.example.com/users/1
pyfetch DELETE https://api.example.com/users/1

# Make a HEAD request (fetch headers only)
pyfetch HEAD https://api.example.com

# Make an OPTIONS request (see allowed methods)
pyfetch OPTIONS https://api.example.com

# Show help message
http_cli HELP
pyfetch HELP
```

## Testing
Expand All @@ -96,6 +103,7 @@ python setup.py test
### Test Coverage

The test suite covers:

- HTTP client functionality
- CLI commands and arguments
- Error handling and exceptions
Expand All @@ -105,11 +113,13 @@ The test suite covers:
### Writing Tests

Tests are organized in three main files:

- `tests/test_cli.py` - Command-line interface tests
- `tests/test_http_client.py` - HTTP client functionality tests
- `tests/test_exceptions.py` - Exception handling tests

To add new tests:

1. Choose the appropriate test file based on functionality
2. Create a new test method in the relevant test class
3. Use unittest assertions to verify behavior
Expand All @@ -120,7 +130,7 @@ To add new tests:
### GET Request

```
usage: http_cli GET [-h] [-t TIMEOUT] url
usage: pyfetch GET [-h] [-t TIMEOUT] url

positional arguments:
url Target URL
Expand All @@ -134,7 +144,7 @@ options:
### POST Request

```
usage: http_cli POST [-h] [-t TIMEOUT] [-d DATA] url
usage: pyfetch POST [-h] [-t TIMEOUT] [-d DATA] url

positional arguments:
url Target URL
Expand All @@ -149,7 +159,7 @@ options:
### PUT Request

```
usage: http_cli PUT [-h] [-t TIMEOUT] [-d DATA] url
usage: pyfetch PUT [-h] [-t TIMEOUT] [-d DATA] url

positional arguments:
url Target URL
Expand All @@ -164,7 +174,7 @@ options:
### PATCH Request

```
usage: http_cli PATCH [-h] [-t TIMEOUT] [-d DATA] url
usage: pyfetch PATCH [-h] [-t TIMEOUT] [-d DATA] url

positional arguments:
url Target URL
Expand All @@ -179,7 +189,35 @@ options:
### DELETE Request

```
usage: http_cli DELETE [-h] [-t TIMEOUT] url
usage: pyfetch DELETE [-h] [-t TIMEOUT] url

positional arguments:
url Target URL

options:
-h, --help show this help message and exit
-t TIMEOUT, --timeout TIMEOUT
Request timeout in seconds (default: 30)
```

### HEAD Request

```
usage: pyfetch HEAD [-h] [-t TIMEOUT] url

positional arguments:
url Target URL

options:
-h, --help show this help message and exit
-t TIMEOUT, --timeout TIMEOUT
Request timeout in seconds (default: 30)
```

### OPTIONS Request

```
usage: pyfetch OPTIONS [-h] [-t TIMEOUT] url

positional arguments:
url Target URL
Expand Down Expand Up @@ -233,15 +271,15 @@ All errors are displayed with descriptive messages to help diagnose the issue.
### Common Issues

1. Command not found:
- Make sure the package is installed (```pip list | findstr http-cli```)
- Ensure your virtual environment is activated
- Make sure the package is installed (`pip list | findstr http-cli`)
- Ensure your virtual environment is activated
2. Import errors:
- Try reinstalling the package: ```pip install -e .```
- Make sure you're using the correct Python environment
- Try reinstalling the package: `pip install -e .`
- Make sure you're using the correct Python environment
3. JSON errors:
- Verify your JSON data is properly formatted
- Use single quotes around the entire JSON string and double quotes inside
- Verify your JSON data is properly formatted
- Use single quotes around the entire JSON string and double quotes inside

## License

This project is licensed under the Apache License, Version 2.0 - see the LICENSE file for details.
This project is licensed under the Apache License, Version 2.0 - see the LICENSE file for details.
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
from setuptools import find_packages, setup

setup(
name="http-cli",
version="0.1.0",
name="PyFetch", # Changed from http-cli
version="1.0.0",
packages=find_packages(where="src"),
package_dir={"": "src"},
install_requires=[
"requests>=2.25.1",
],
entry_points={
"console_scripts": [
"http_cli=http_cli.cli:main",
"pyfetch=http_cli.cli:main", # Changed from http_cli=http_cli.cli:main
],
},
author="Malte Mindedal",
Expand Down
49 changes: 45 additions & 4 deletions src/http_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ def add_common_arguments(parser):
default=30,
help="Request timeout in seconds (default: 30)",
)
parser.add_argument(
"-H",
"--header",
action="append",
help="HTTP header in 'Key: Value' format. Can be used multiple times.",
)
parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="Enable verbose logging for debugging.",
)


def create_parser():
Expand All @@ -60,7 +72,7 @@ def _split_lines(self, text, width):
return super()._split_lines(text, width)

parser = argparse.ArgumentParser(
description="HTTP CLI client supporting GET, POST, PUT, PATCH, and DELETE methods",
description="HTTP CLI client supporting GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS methods",
formatter_class=CustomFormatter,
add_help=True,
)
Expand Down Expand Up @@ -117,6 +129,18 @@ def _split_lines(self, text, width):
)
add_common_arguments(delete_parser)

# HEAD command
head_parser = subparsers.add_parser(
"HEAD", help="Make a HEAD request", aliases=["head"]
)
add_common_arguments(head_parser)

# OPTIONS command
options_parser = subparsers.add_parser(
"OPTIONS", help="Make an OPTIONS request", aliases=["options"]
)
add_common_arguments(options_parser)

return parser


Expand All @@ -134,13 +158,22 @@ def main(suppress_output=False):
show_examples(suppress_output)
return

client = HTTPClient(timeout=args.timeout)
client = HTTPClient(timeout=args.timeout, verbose=args.verbose)

try:
# Prepare request kwargs
kwargs = {}
if hasattr(args, "data") and args.data:
kwargs["json"] = json.loads(args.data)
# Parse headers if provided
if hasattr(args, "header") and args.header:
headers = {}
for item in args.header:
if ":" in item:
key, value = item.split(":", 1)
headers[key.strip()] = value.strip()
if headers:
kwargs["headers"] = headers

# Make the request based on the command
response = getattr(client, command.lower())(args.url, **kwargs)
Expand All @@ -150,8 +183,16 @@ def main(suppress_output=False):
print("\nHeaders:")
for key, value in response.headers.items():
print(f"{key}: {value}")
print("\nResponse Body:")
print(response.text)

# Only print Response Body if there is content
if response.text.strip():
print("\nResponse Body:")
try:
json_data = json.loads(response.text)
pretty_response = json.dumps(json_data, indent=4)
print(pretty_response)
except ValueError:
print(response.text)

except json.JSONDecodeError:
print("Error: Invalid JSON data")
Expand Down
Loading