Implementing client-side caching for ESI (python)

Hello all,

First of all, I’m mostly focused on python here, so I didn’t check other languages.

I kinda shocked that there’s no example of implementation of a caching mechanism on the client side for the ESI, using swagger_client. So to be nice on ESI servers (and my own) I’ve started this quest and ended up with this (cache actually not in the example code for the sake of simplicity):

import swagger_client as esi_client

class RESTClientObjectCached(esi_client.rest.RESTClientObject):
    def __init__(self, pools_size=4):
        super().__init__(pools_size=pools_size)

    def request(self, method, url, query_params=None, headers=None,
                body=None, post_params=None):
        logger.debug('Cached request')
        r = super().request(method=method, url=url, query_params=query_params,
                headers=headers, body=body, post_params=post_params)
        return r


class ApiClientCached(esi_client.ApiClient):
    def __init__(self, host=None, header_name=None, header_value=None, cookie=None):
        super().__init__(host=host, header_name=header_name, header_value=header_value, cookie=cookie)
        self.rest_client = RESTClientObjectCached()

Which works, but I must admit that I didn’t like having to copy&paste function signatures (so I still have some sort of validation in my IDE). I will work with the diskcache python module and consider posting here my progress.

On the meanwhile (I’m not a pro in the swagger specs, so correct me if I’m wrong), wouldn’t be nicer if the ApiClient class constructor would be like:
def __init__(self, rest_client=RESTClientObject(), host=None, header_name=None, header_value=None, cookie=None)

Is it possible to use swagger-codegen for this or is it something that (if CCP willing to) needs to be changed in the spec?

Cheers

Don’t know about others (if there are any) but at least EsiPy has caching mechanism inside it, but it’s not swagger-codegen but dynamic codegen using swagger.json. Btw, cache invalidation is (and should be) managed by cache objects, not by the client.

For generated client (using swagger-gen) I don’t think there’s any public lib / caching mechanism. Can’t help more with this, since I don’t use it :confused:

I have seen it before starting my project. I had issues with the dynamic codegens (for example, last time i’ve tried the swagger spec with the online generator on swagger.io it was complaining about not being able to generate something under Assets; on another online generator, the python code for validating the character type (from get_characters_character_id) was testing “if security_status” instead of “if security_status is not None”, which failed when sec status was 0.0). Being weary of them was what threw me off from EsiPy before trying it.

But I didn’t expected a reply from its author :+1:. I will give it a try.

I agree. My intention was to be able to supply my own RESTClientObject to the swagger_client which would make use of a cache object.
In the end it didn’t work as I’ve intended since RESTClientObject returns (among other stuff) a urllib3.HTTPResponse, which does not serialize :frowning:

I’ve implemented a variation of swagger_client.ApiClient which is cache aware (it just overloads the call_api and makes use of a cache class) respecting the headers sent from ESI.

I will give a shot to EsiPy and compare how easy is to write a simple project compared with the swagger-codegen generated code.

Just as a side note, as I’ve read a bit of EsiPy source and you are also using diskcache: I was not too found of it using pickle. If you use an external DB and don’t secure it properly, it is possible to inject arbitrary code “pickled” in the DB to be executed by your app. I’ve tried to store my cache in json but it made my life miserable.

My intent on providing a cache class to such “low level” in the api client was to attempt to cache the raw responses from ESI before they get parsed by the client, so I don’t get into serialization issues but in the end (to accomplish this) might be easier to just write/use a HTTP proxy instead.

Don’t hesitate to ping me on slack / make issues on github if you have any problem with it :slight_smile:

Tbh, I only added FileCache as it existed in PyCrest when I started this project to keep some sort of “cache equivalence” between both (for those who might migrate from one to another using that cache). But it used pickle and did everything, so, as I am lazy, I just took the first lib that seemed to do the job correctly :smiley:
As for the security issue of Pickle, true (very true indeed), but as you know the sources of the data (esi) and how you load it, it “”" shouldn’t “”" be an issue (still it is possible).

As for the cache content, I don’t parse it or alter it before caching actually: I take the response from ESI as is and I put it in a namedtuple (for the ease of using it elsewhere)

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.