Brand new way to test your API
Project description
apitist
Brand new way to test your API
Main features:
- Adding hooks for requests library
- Default hooks for:
- Logging
- Structuring/Unstructuring data
Installation
Run the following command in your command line::
pip install apitist
If you want to use predefined random types please install additional requirements:
pip install -e apitist[random]
Session and client creation
Session can take base_url
parameter which will be used to prepend before requesting path.
from apitist.requests import session
session = session("https://httpbin.org/v1")
session.get("/get") # Here request will be made to `https://httpbin.org/v1/get`
You can safely pass path
and base_url
with leading/forwarding slash:
from apitist.requests import session
session("https://httpbin.org/v1").get("/get")
session("https://httpbin.org/v1/").get("/get")
session("https://httpbin.org/v1/").get("get")
session("https://httpbin.org/v1").get("get")
In all examples above requests would be made to https://httpbin.org/v1/get
.
Request decorators
Apitist offers all default requests types as a class method decorator, but there are some requirements for that:
- Class, where you use decorators, should contain session parameter, with
Session
object - Function, which is decorated, must return
None
ordict
with parameters, that will be passed torequest
function ofSession
object, like:headers
,data
,json
and so on. - You can use format placeholders in decorators
url
parameter, but you should remember that parameters from method will be passed toformat
method AS IS - args to args, kwargs to kwargs. As a result this code won't work:class ExampleClient: ... @delete("/users/{id}?method={method}") def delete_user(self, id, method): ...
Example client class:
from apitist import session
from apitist.decorators import get, post, put, delete
class ExampleClient:
session = session("http://example.com/v1")
@get("/users")
def get_user(self): ...
@get("/users/{}")
def get_user(self, id): ...
@post("/users")
def create_user(self, data):
return {"json": data}
@put("/users/{}")
def update_user(self, id, data):
return {"json": data}
@delete("/users/{}?method={method}")
def delete_user(self, id, method="hide"): ...
Shared Session
Shared Session class can be used to share cookies between different sessions.
from apitist import session, SharedSession
s1 = session("https://google.com")
s2 = session("https://yandex.ru")
ss = SharedSession(s1, s2)
s2.get("/?q=2113")
assert s1.cookies == s2.cookies
s1.get("/?q=124")
assert s1.cookies == s2.cookies
Default hooks
- RequestDebugLoggingHook - logs request content with level DEBUG
- RequestInfoLoggingHook - logs request content with level INFO
- PrepRequestDebugLoggingHook - logs prepared request content (e.g. you will see query parameters in URL) with level DEBUG
- PrepRequestInfoLoggingHook - logs prepared request content with level INFO
- ResponseDebugLoggingHook - logs response content with level DEBUG
- ResponseInfoLoggingHook - logs response content with level INFO
- RequestAttrsConverterHook - converts attrs class in
data
field into json - RequestDataclassConverterHook - converts dataclass class in
data
field into json - ResponseAttrsConverterHook - adds
structure(type)
function torequests.Response
class, which will structure response according to attrs class given to it - ResponseDataclassConverterHook - adds
structure(type)
function torequests.Response
class, which will structure response according to dataclass class given to it
Example usage
from apitist import PrepRequestInfoLoggingHook, ResponseInfoLoggingHook
from apitist import session
s = session()
PrepRequestInfoLoggingHook.formatter = "Best formatter {req.method} {req.url}"
s.add_prep_request_hook(PrepRequestInfoLoggingHook)
s.add_response_hook(ResponseInfoLoggingHook)
s.post("https://httpbin.org/post", params={"q": "test"})
Custom Hooks
from requests import Request, PreparedRequest, Response
from apitist import session, RequestHook, PreparedRequestHook, ResponseHook
s = session()
class ReqHook(RequestHook):
def run(self, request: Request) -> Request:
print(request.url)
return request
class PrepReqHook(PreparedRequestHook):
def run(self, request: PreparedRequest) -> PreparedRequest:
print(request.url)
return request
class RespHook(ResponseHook):
def run(self, response: Response) -> Response:
print(response.url)
return response
s.add_request_hook(ReqHook)
s.add_prep_request_hook(PrepReqHook)
s.add_response_hook(RespHook)
s.get("https://ya.ru", params={"q": "test"})
Working with constructor
import attr
import typing
from apitist import (
converter,
RequestConverterHook,
ResponseConverterHook,
session,
)
class ExampleType:
test = None
@attr.s
class ExampleStructure:
test: ExampleType = attr.ib()
@attr.s
class TestResponse:
args: typing.Dict = attr.ib()
data: str = attr.ib()
files: typing.Dict = attr.ib()
form: typing.Dict = attr.ib()
headers: typing.Dict = attr.ib()
json: ExampleStructure = attr.ib()
origin: str = attr.ib()
url: str = attr.ib()
s = session()
s.add_hook(RequestConverterHook)
s.add_hook(ResponseConverterHook)
def structure_example_type(data, type_):
example = ExampleType()
example.test = data
return example
def unstructure_example_type(data):
return data.test
converter.register_hooks(
ExampleType, structure_example_type, unstructure_example_type
)
t = ExampleType()
t.test = "test"
struc = ExampleStructure(t)
res = s.post("https://httpbin.org/post", data=struc).structure(TestResponse)
print(res.structured.json.test.test) # test
Using random data generator
First of all create an instance of random class:
from apitist import Randomer
rand = Randomer()
Now, you can add custom hooks for different types:
rand.add_type(str, lambda: str(random.random()))
rand.add_type(float, lambda: random.random())
Or using add_types
:
types = {
str: lambda: str(random.random()),
float: lambda: random.random()
}
rand.add_types(types)
Now you can create random object for given type or any attrs class with defined types:
import attr
import dataclasses
import typing
rand.object(str) # '0.6147789314561384'
rand.object(float) # 0.4664297665239271
@attr.s
class Data:
value1: str = attr.ib()
value2: typing.List[str] = attr.ib()
value3: typing.Tuple[float] = attr.ib()
@dataclasses.dataclass
class Dataclass:
value1: str
value2: typing.List[str]
value3: typing.Tuple[float]
print(rand.object(Data))
# Data(
# value1='0.491058956716827',
# value2=['0.6568036485871975'],
# value3=(0.8603579349502298,)
# )
# Also works for dataclasses
print(rand.object(Dataclass))
# Data(
# value1='0.491058956716827',
# value2=['0.6568036485871975'],
# value3=(0.8603579349502298,)
# )
It is better to use it with Faker.
Just define different subclasses for str
and add different hooks for them.
By this you could create different data for different str
fields.
Also, using with RequestConverterHook
and ResponseConverterHook
you could easily create random json objects which would be send to server.
Predefined random types
from apitist import Randomer
from apitist.random import Username, FirstName, LastName, Date
from dataclasses import dataclass
@dataclass
class LoginModel:
username: Username
password: str
@dataclass
class BookingDates:
checkin: Date
checkout: Date
@dataclass
class BookingModel:
firstname: FirstName
lastname: LastName
totalprice: int
depositpaid: bool
bookingdates: BookingDates
additionalneeds: str
rand = Randomer()
rand.add_predefined(locale="es-ES")
rand.object(LoginModel)
# LoginModel(
# username='wfeliu',
# password='VjHoHtLSjdoxXhtitaXU'
# )
rand.object(BookingModel)
# BookingModel(
# firstname='Pedro',
# lastname='Luz',
# totalprice=931,
# depositpaid=True,
# bookingdates=BookingDates(checkin='1972-08-29', checkout='1971-05-19'),
# additionalneeds='EFggHSpnzRSJATKtUmOm'
# )
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file apitist-4.3.0.tar.gz
.
File metadata
- Download URL: apitist-4.3.0.tar.gz
- Upload date:
- Size: 46.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.0 CPython/3.7.11
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3c47d63ca4d4eacae53650664ee58d4e2a6ff4b2b8b07847e3ff72ec122bc11d |
|
MD5 | 3b68c0d207c3b842cc211074e75daecd |
|
BLAKE2b-256 | b0b891e4404c27355c9aec7c21a7904cab4f94fb5285a14993c92654e8ae9c91 |
File details
Details for the file apitist-4.3.0-py2.py3-none-any.whl
.
File metadata
- Download URL: apitist-4.3.0-py2.py3-none-any.whl
- Upload date:
- Size: 28.1 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.0 CPython/3.7.11
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5d6fefa3d1811dc4aa3b90841fc89189923abe31f5796b951bc15b809355d480 |
|
MD5 | 22916d59a28103f19e96bf547ec9dafb |
|
BLAKE2b-256 | f1c3547af5134598e2af36f4913e9dcfb0a0964843a5b2c51185861f5f6cd737 |