Skip to content

Commit

Permalink
Merge pull request #138 from mrzarquon/feat/restapi
Browse files Browse the repository at this point in the history
Rename v3 to rest
  • Loading branch information
garethr authored Mar 16, 2022
2 parents 35525ef + 6ef4a72 commit 267c45d
Show file tree
Hide file tree
Showing 9 changed files with 521 additions and 64 deletions.
36 changes: 19 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,59 +211,61 @@ client.post("<path>", <data>)

Most of the time you shouldn't need to use these. They are mainly useful if new methods are added to the API which are not yet supported in the client. This can also be useful if you want to pass very specific parameters, or to parse the raw JSON output from the API.

## Experimental v3 low-level client
## Experimental rest low-level client

pysnyk >= 0.9.0 now includes support for basic v3 compatibility. To switch to use a v3 client, pass the v3 API url and version when initializing a client. Right now it supports the `GET` method. Refer to the [v3 API docs](https://apidocs.snyk.io/) for more information and examples.
pysnyk >= 0.9.0 now includes support for basic rest (formerly referred to as v3) compatibility. To switch to use a rest client, pass the rest API url and version when initializing a client. Right now it supports the `GET` method. Refer to the [rest API docs](https://apidocs.snyk.io/) for more information and examples.

Getting the v3 information of an organization:
Getting the rest information of an organization:

```python
# To get this value, get it from a Snyk organizations settings page
snyk_org = "df734bed-d75c-4f11-bb47-1d119913bcc7"

# to use the v3 endpoint you MUST include a version value and the url of the v3 api endpoint as shown below
v3client = SnykClient(snyk_token, version="2022-02-16~experimental", url="https://api.snyk.io/v3")
# to use the rest endpoint you MUST include a version value and the url of the v3 api endpoint as shown below
rest_client = SnykClient(snyk_token, version="2022-02-16~experimental", url="https://api.snyk.io/rest")

print(v3client.get(f"/orgs/{snyk_org}").json())
print(rest_client.get(f"/orgs/{snyk_org}").json())

# this supports overriding v3 versions for a specific GET requests:
user = v3client.get(f"orgs/{snyk_org}/users/{snyk_user}", version="2022-02-01~experimental").json()
# this supports overriding rest versions for a specific GET requests:
user = rest_client.get(f"orgs/{snyk_org}/users/{snyk_user}", version="2022-02-01~experimental").json()

# pass parameters such as how many results per page
params = {"limit": 10}

targets = v3client.get(f"orgs/{snyk_org}/targets", params=params)
targets = rest_client.get(f"orgs/{snyk_org}/targets", params=params)
```

V1 and v3 can work at the same time by instantiating two clients:
V1 and rest can work at the same time by instantiating two clients:

```python
snyk_org = "df734bed-d75c-4f11-bb47-1d119913bcc7"

v1client = SnykClient(snyk_token)

v3client = SnykClient(snyk_token, version="2022-02-16~experimental", url="https://api.snyk.io/v3")
rest_client = SnykClient(snyk_token, version="2022-02-16~experimental", url="https://api.snyk.io/rest")

v1_org = v1client.organizations.get(snyk_org)

v3_org = v3client.get(f"/orgs/{snyk_org}").json()
rest_org = rest_client.get(f"/orgs/{snyk_org}").json()
```

The v3 API introduces consistent pagination across all endpoints. The v3 client includes a helper method `.get_v3_pages` which collects the paginated responses and returns a single list combining the contents of the "data" key from all pages. It takes the same values as the get method.
The rest API introduces consistent pagination across all endpoints. The v3 client includes a helper method `.get_rest_pages` which collects the paginated responses and returns a single list combining the contents of the "data" key from all pages. It takes the same values as the get method.

```python
v3client = SnykClient(snyk_token, version="2022-02-16~experimental", url="https://api.snyk.io/v3")
rest_client = SnykClient(snyk_token, version="2022-02-16~experimental", url="https://api.snyk.io/rest")

params = {"limit": 10}

targets = v3client.get(f"orgs/{snyk_org}/targets", params=params).json()
targets = rest_client.get(f"orgs/{snyk_org}/targets", params=params).json()

print(len(targets["data"]))
# returns 10 targets

all_targets = v3client.get_v3_pages(f"orgs/{snyk_org}/targets", params=params)
all_targets = rest_client.get_rest_pages(f"orgs/{snyk_org}/targets", params=params)

print(len(all_targets))
# returns 33 targets, note we don't have to add .json() to the call or access the "data" key, get_v3_pages does that for us
# returns 33 targets, note we don't have to add .json() to the call or access the "data" key, get_rest_pages does that for us

```

For backwards compatibility the get_rest_pages method has an alternative name of get_v3_pages to not break code already rewritten replatformed to the 0.9.0 pysnyk module.
70 changes: 37 additions & 33 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pysnyk"
version = "0.9.0"
version = "0.9.1"
description = "A Python client for the Snyk API"
authors = [
"Gareth Rushgrove <[email protected]>",
Expand Down
21 changes: 13 additions & 8 deletions snyk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ def get(
self, path: str, params: dict = None, version: str = None
) -> requests.Response:
"""
V3 Compatible Snyk Client, assumes the presence of Version, either set in the client
or called in this method means that we're talking to a V3 endpoint and will ensure the
Rest (formerly v3) Compatible Snyk Client, assumes the presence of Version, either set in the client
or called in this method means that we're talking to a rest API endpoint and will ensure the
params are encoded properly with the version.
Since certain endpoints can exist only in certain versions, being able to override the
Expand All @@ -126,12 +126,12 @@ def get(
if not params:
params = {}

# we use the presence of version to determine if we are v3 or not
# we use the presence of version to determine if we are REST or not
if "version" not in params.keys() and self.version:
params["version"] = version or self.version

# Python Bools are True/False, JS Bools are true/false
# Snyk v3 API is strictly case sensitive at the moment
# Snyk REST API is strictly case sensitive at the moment

for k, v in params.items():
if isinstance(v, bool):
Expand Down Expand Up @@ -175,9 +175,9 @@ def delete(self, path: str) -> requests.Response:
raise SnykHTTPError(resp)
return resp

def get_v3_pages(self, path: str, params: dict = {}) -> List:
def get_rest_pages(self, path: str, params: dict = {}) -> List:
"""
Helper function to collect paginated responses from the V3 API into a single
Helper function to collect paginated responses from the rest API into a single
list.
This collects the "data" list from the first reponse and then appends the
Expand All @@ -196,7 +196,9 @@ def get_v3_pages(self, path: str, params: dict = {}) -> List:
data.extend(page["data"])

while "next" in page["links"].keys():
logger.debug(f"GET_V3_PAGES: Another link exists: {page['links']['next']}")
logger.debug(
f"GET_REST_PAGES: Another link exists: {page['links']['next']}"
)

next_url = urllib.parse.urlsplit(page["links"]["next"])
query = urllib.parse.parse_qs(next_url.query)
Expand All @@ -211,11 +213,14 @@ def get_v3_pages(self, path: str, params: dict = {}) -> List:
data.extend(page["data"])

logger.debug(
f"GET_V3_PAGES: Added another {len(page['data'])} items to the response"
f"GET_REST_PAGES: Added another {len(page['data'])} items to the response"
)

return data

# alias for backwards compatibility where V3 was the old name
get_v3_pages = get_rest_pages

@property
def organizations(self) -> Manager:
return Manager.factory(Organization, self)
Expand Down
Loading

0 comments on commit 267c45d

Please sign in to comment.