Applaudgen
parses App Store Connect specification file and generates client library for accessing App Store Connect API.
For the generated Python client library, navigate to Applaud.
At Codinn, we have two apps distribute on App Store – Core Shell and Core Tunnel. We wrote a bunch of scripts to automate the build, package and upload processes, we benefit from the automation scripts and it saves a lot of time.
For the app information (localized descriptions, versions, changelogs and other meta data) in App Store, we maintained it manually for a very long time. But this can easily go wrong, we made a few horrible mistakes while updating the information, e.g., pasted the description of Core Shell to Core Tunnel, using Spanish changelog for English localization, forgot update site links.
We decided to adopt App Store Connect API to automate app information updating process as well, but soon discovered that it lacks client support. Most client libraries implement a very small portion of the API, provide very limited operations.
We surprisingly found that App Store Connect API uses and conforms to OpenAPI specification, it shouldn't be too hard to generate client code from the specification. So we create project Applaudgen
for this purpose, and its masterpiece – project Applaud.
This project is written in Python, and uses Poetry for packaging and dependency management. You should have Poetry installed if you want to contribute to the Python code in this repository.
The applaudgen
command:
usage: applaudgen.py [-h] [-s SPEC_FILE] [-o OUTPUT_DIR]
Generate Python SDK code for the App Store Connect API.
optional arguments:
-h, --help show this help message and exit
-s SPEC_FILE, --spec SPEC_FILE
Path to the App Store Connect API specification file.
-o OUTPUT_DIR, --output OUTPUT_DIR
Path to the package output directory.
SPEC_FILE
defaults to app_store_connect_api.json
under project root, which is the latest supported version (1.6 at present) of App Store Connect specification file.
OUTPUT_DIR
defaults to ./PythonPackage
.
Code generated by most OpenAPI client generators are not as elegant as by Applaudgen
.
For example, App Store Connect API has tons of inner schemas like UserUpdateRequest.Data.Attributes
and AppInfoLocalizationCreateRequest.Data.Relationships.AppInfo.Data
. datamodel-code-generator creates numerous schema classes Data1
, Data2
… for each inner Data
schema.
On the contrary, Applaudgen
creates inner classes to align with App Store Connect API documentation perfectly:
class UserUpdateRequest(ApplaudModel):
class Data(ApplaudModel):
class Attributes(ApplaudModel):
roles: Optional[list[UserRole]]
all_apps_visible: Optional[bool]
provisioning_allowed: Optional[bool]
class Relationships(ApplaudModel):
class VisibleApps(ApplaudModel):
class Data(ApplaudModel):
id: str
type: Literal["apps"] = "apps"
data: Optional[list[Data]]
visible_apps: Optional[VisibleApps]
id: str
type: Literal["users"] = "users"
attributes: Optional[Attributes]
relationships: Optional[Relationships]
data: Data
A common pitfall of generic OpenAPI client generators is rigid, inflexible. Take an example, ErrorResponse
is a schema of course, Applaudgen
wraps it into an exception for you without write extra code:
from applaud.connection import Connection
connection = Connection(APPSTORE_ISSUER_ID, APPSTORE_KEY_ID, APPSTORE_PRIVATE_KEY)
try:
response = connection.beta_tester_invitations().create(…)
except EndpointException as err:
already_accepted_error = False
for e in err.errors:
if e.code == 'STATE_ERROR.TESTER_INVITE.ALREADY_ACCEPTED':
# silent this error
already_accepted_error = True
break
if not already_accepted_error:
raise err
You always get a correct response on success, or an exception otherwise.
Further more, Applaudgen
provides full function yet simple interfaces to perform tasks on App Store Connect:
from applaud.connection import Connection
connection = Connection(APPSTORE_ISSUER_ID, APPSTORE_KEY_ID, APPSTORE_PRIVATE_KEY)
response = connection.beta_groups().filter(app=[app_id1, app_id2], name="Example Tester Group", is_internal_group=False).include(BetaGroupsEndpoint.Include.APP).get()
for group in beta_groups.data:
print(group.id, group.attributes.created_date, group.relationships.app.data.id)
Above code lists all external beta groups that named Example Tester Group
in apps with id
s app_id1
and app_id2
, and the response includes related corresponding id of the owner app.
- Generates Swift client library
- Python syntactic sugar to simplify the initialization of deep inner classes