Skip to content

feat: Add Client for Systems State Service APIs#89

Closed
Shri2109 wants to merge 2 commits intoni:masterfrom
Shri2109:users/shriram/systems-state-service-client
Closed

feat: Add Client for Systems State Service APIs#89
Shri2109 wants to merge 2 commits intoni:masterfrom
Shri2109:users/shriram/systems-state-service-client

Conversation

@Shri2109
Copy link
Contributor

@Shri2109 Shri2109 commented Jan 8, 2025

What does this Pull Request accomplish?

This PR adds API Client Module for States microservice in the Systems State Service.

Why should this Pull Request be merged?

The SystemsStateClient makes it easier for users to interact with the endpoints of Systems State Service by just creating an instance of it.

What testing has been done?

Automated integration tests are included.

API Link: Swagger Link

@santhoshramaraj santhoshramaraj added the enhancement New feature or request label Jan 8, 2025
Copy link
Member

@santhoshramaraj santhoshramaraj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pending tests review

@pytest.fixture
def default_work_space() -> str:
"""Fixture that returns the default workspace id"""
return "846e294a-a007-47ac-9fc2-fac07eab240e"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests should be agnostic of the SLE instance and equipped to work with a fresh deployment by taking care of creating/deleting any necessary entities or mock them in the requests response.

Suggested change
return "846e294a-a007-47ac-9fc2-fac07eab240e"
return ""

@Shri2109 Shri2109 closed this Feb 19, 2025
@Shri2109 Shri2109 deleted the users/shriram/systems-state-service-client branch February 19, 2025 08:43
@Shri2109 Shri2109 restored the users/shriram/systems-state-service-client branch March 1, 2025 16:28
@Shri2109 Shri2109 reopened this Mar 1, 2025
@Shri2109 Shri2109 requested a review from rbell517 as a code owner March 1, 2025 16:30
@Shri2109
Copy link
Contributor Author

Shri2109 commented Mar 1, 2025

@santhoshramaraj

I'm yet to update the changes that I made for resolving the previous comments. Awaiting your reply on the privilege issue (test tier for my role) for creating or updating states, to test the modified client code. However, I have few doubts.

@Shri2109
Copy link
Contributor Author

Shri2109 commented Mar 1, 2025

@santhoshramaraj

In the functions involving multipart-form-data as expected request body, in the uplink documentation, it is suggested to use the @multipart decorator. But while referring the feeds client, I couldn't find such a decorator. Can we avoid that?

If I make use of the decorator, the response is not inferring the expected type properly. Also, the function signature in the documentation is displayed as (method) import_state: multipart, instead of showing the proper docstring.

@Shri2109
Copy link
Contributor Author

Shri2109 commented Mar 1, 2025

@santhoshramaraj

In the swagger docs for updating a state, A dictionary which contains key-value pairs as such: the key is the state property to be updated (e.g. "name") and the value is the new/updated value of the property (e.g. "A nice state") this is kind of what it is expected, so in the client function, I had just given as patch_updates: Dict[str, Any] as of now.

But can we explicitly define a proper model in our client package, for updating a state?

@Shri2109
Copy link
Contributor Author

Shri2109 commented Mar 1, 2025

@santhoshramaraj

stateID: Optional[str] = None How do the snake case and camel case conversion would be happening for this field? Consider we are defining it as state_id in our model, then the camel case conversion would be stateId right! Just a small confusion that, wouldn't there be any problem with this! Because, in the swagger docs it is expected to be stateID.

@santhoshramaraj
Copy link
Member

@santhoshramaraj

In the functions involving multipart-form-data as expected request body, in the uplink documentation, it is suggested to use the @multipart decorator. But while referring the feeds client, I couldn't find such a decorator. Can we avoid that?

If I make use of the decorator, the response is not inferring the expected type properly. Also, the function signature in the documentation is displayed as (method) import_state: multipart, instead of showing the proper docstring.

Please refer to upload_file method at

to use multi-part with Uplink.

...

@post("export-state", args=[Body])
def export_state(self, query: models.ExportStateRequest) -> str:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your type hint for the response is a string, but this will return a file download. This should instead be an IteratorFileLike and you should decorate the function with @response_handler(file_like_response_handler).

The same applies for export_state_from_system


@patch("states/{stateId}", args=[Path("stateId"), Body])
def update_state(
self, id: str, patch_updates: Dict[str, Any]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd really prefer a proper class to this patch_updates dictionary. Its cases like this that pushed us to hand create these clients rather than just generating them from the OpenAPI yaml.

The actual strings and values we expect to allow in this dictionary are known and we can build a proper update object that maps to the dictionary the API takes. See the ModelConverter class and the StateConstants.Update* fields for the keys. The update model should be a fully optional version of the StateUpdate class

Part(name="File", type=str),
],
)
def replace_state_content(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use BinaryIO instead of io.BytesIO. Its basically just a more flexible alias.

architecture: str,
properties: str,
workspace: str,
file: BytesIO,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly here use BinaryIO from typing instead of BytesIO

description: str,
distribution: models.Distribution,
architecture: models.Architecture,
properties: str,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

properties should be a string-string dictionary. The API expects serialized JSON, so I expect you'll need to convert it to json yourself. I bet there is a way to get uplink to convert the dictionary to a json string for you, if you want to dig into it.

"""Basic State entities that can be extended further"""

name: Optional[str] = None
"""Gets or sets the name of the state."""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These "gets or sets" doc strings are not great. I get this is copied from the swagger, but really these should just be what comes after, "The name of the state" in this case.

)


class StateDescriptionListResponse(JsonModel):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what the type is called in the swagger but I'm not a fan. How about StateMetadataList instead

class StateResponse(StateMetaData, AdditionalStateInformation):
"""Model for system state object."""

error: Optional[ApiError] = None
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this error object. The routes that will return StateResponse will return either the error or the proper State object, not both. When the error is the response it will always be with a 4xx error code, which is automatically raised as a ApiException in the base client, which then provides access to the error body. This means we should be able to fully replace this StateResponse with State as the returned type from the client functions.

The same applies to StateDescriptionListResponse

"""


class StateMetaData(State):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be StateMetadata (no capital D) and it would make more sense to invert this relationship. State is the complete object and it should inherit from StateMetadata, the incomplete object. State should additionally get feeds, packages, systemImage, and containsExtraOperations


Create, query, update, and delete states

.. literalinclude:: ../examples/systemsstate/systemsstate.py
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file doesn't exist, did you forget to commit it?

@Shri2109 Shri2109 closed this by deleting the head repository Jul 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants