Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LILT-API header is not used #22

Open
maharg101 opened this issue Nov 10, 2020 · 6 comments
Open

LILT-API header is not used #22

maharg101 opened this issue Nov 10, 2020 · 6 comments

Comments

@maharg101
Copy link

It seems that the LILT-API header is not used. Instead individual values, such as project_id are sent in their own headers.

The only references to LILT-API appear to be in the commentary / documentation. A search confirms this: https://github.com/lilt/lilt-python/search?q=LILT-API

I have traced the headers including project_id through to the urllib3.request() method, and they are not passed as a JSON object with the header field LILT-API.

Consequently, a call to the upload_document endpoint results in a bad request HTTP response body: {"message":"Invalid request: missing project_id header"}

@maharg101
Copy link
Author

Checked using local python server to dump headers:

Accept-Encoding: identity
Content-Length: 89104
name: some.docx
project_id: 4
pretranslate: tm+mt
Accept: application/json
Content-Type: application/octet-stream
User-Agent: OpenAPI-Generator/0.5.2/python

@tgallant
Copy link
Collaborator

Hi @maharg101 thanks for raising this issue. Could you share an example of the code that you're using?

Did you create the project beforehand as well? The project_id value needs to be a valid Lilt Project ID.

You are correct that this library doesn't use the LILT-API header as is described in the API docs. Passing each parameter in its own header value is also a supported way to specify these options.

I'm not running into any issues with document uploads using this library. Here is a working example snippet (be sure to set the correct API_KEY and PROJECT_ID values).

from lilt import Configuration, ApiClient, DocumentsApi


def main():
    API_KEY = 'example_key'
    PROJECT_ID = 5555
    configuration = Configuration(
        api_key={'key': API_KEY}
    )
    api_client = ApiClient(configuration)
    documents_api = DocumentsApi(api_client)
    with open('test.docx', 'rb') as f:
        body = f.read()
        documents_api.upload_document('test.docx', PROJECT_ID, body)


if __name__ == '__main__':
    main()

@maharg101
Copy link
Author

Hi @tgallant

Yes, the project exists, and works with curl examples using the LILT-API header with JSON object.

The code I am using (invoked by the main script):

import lilt
import os

from .logs import get_logger

from lilt.rest import ApiException

LILT_HOST = os.environ.get("LILT_HOST", None)
LILT_API_KEY = os.environ.get("LILT_API_KEY", None)


class Uploader(object):

    def __init__(self, project_id):
        """
        Construct an uploader object
        :param project_id: a unique project identifier
        """
        self.configuration = lilt.Configuration(
            host=LILT_HOST,
            api_key={"key": LILT_API_KEY}
        )
        self.project_id = project_id
        self.logger = get_logger('uploader')
        with lilt.ApiClient(self.configuration) as api_client:
            self.api_instance = lilt.DocumentsApi(api_client)

    def upload_files(self, body_contents, job_id):
        """
        Upload files to lilt
        :param body_contents: an iterable of body contents
        :param job_id: a unique ID to be used for this batch of files
        """
        self.logger.info(f"starting upload for job_id {job_id} to project {self.project_id}")
        for idx, body in enumerate(body_contents):
            self.upload_file(f"{job_id}_{idx}.docx", body)
        self.logger.info(f"completed upload for job_id {job_id} to project {self.project_id}")

    def upload_file(self, name, body, pretranslate="tm+mt",  **kwargs):
        """
        Upload a file to lilt
        See https://github.com/lilt/lilt-python/blob/master/docs/DocumentsApi.md#upload_document for more information
        on the available parameters.
        :param name: a file name
        :param body: the file contents to be uploaded
        :param pretranslate: if and how the document will be pretranslated - `null`, `tm`, or `tm+mt` (optional)
        """
        try:
            self.logger.info(f"uploading {name} to project {self.project_id}")
            api_response = self.api_instance.upload_document(
                name=name,
                project_id=self.project_id,
                body=body,
                pretranslate=pretranslate,
                **kwargs
            )
            self.logger.info(api_response)
        except ApiException as e:
            self.logger.error(f"Exception when calling DocumentsApi->upload_document for {name}: {e}\n")

I am working against a private instance. I was not involved in deploying it, but could find out some details. It is possible therefore that the installation is not forwarding the relevant headers to the API.

@tgallant
Copy link
Collaborator

Hi @maharg101 thanks for the note

It is possible therefore that the installation is not forwarding the relevant headers to the API.

That sounds like something worth investigating. Maybe there is some proxy server that is stripping certain headers.

As a workaround you can construct a request that uses the LILT-API header using the ApiClient.call_api method directly. Here is a working example of that.

import json
from lilt import Configuration, ApiClient, DocumentsApi


def main():
    API_KEY = 'example_key'
    PROJECT_ID = 5555
    configuration = Configuration(
        api_key={'key': API_KEY}
    )
    api_client = ApiClient(configuration)
    documents_api = DocumentsApi(api_client)
    upload_opts = {
        'name': 'test.docx',
        'project_id': PROJECT_ID,
        'pretranslate': 'tm+mt'
    }
    headers = {
        'LILT-API': json.dumps(upload_opts),
        'Content-Type': 'application/octet-stream'
    }
    with open('test.docx', 'rb') as t:
        body = t.read()
        # self.api_instance.api_client.call_api() in your case
        res = documents_api.api_client.call_api(
            '/documents/files',
            'POST',
            body=body,
            header_params=headers,
            query_params=[],
            auth_settings=['ApiKeyAuth', 'BasicAuth'],
            response_type='DocumentWithoutSegments',
            _return_http_data_only=True
        )
        print(res.id)


if __name__ == '__main__':
    main()

Let me know if that's a suitable workaround or if you have further questions.

@maharg101
Copy link
Author

Thanks @tgallant - that works well. Are there any plans to have this library use the LILT-API header ?

@tgallant
Copy link
Collaborator

@maharg101

Are there any plans to have this library use the LILT-API header ?

The main complication is that this library is being generated from an API specification using openapi-generator. The OpenAPI standard doesn't have a mechanism for serializing/stringifying a JSON object inside of a header parameter. Instead we've opted to support passing in each parameter as a separate header value.

Here is the documentation for how different types of parameters are serialized in OpenAPI: https://swagger.io/docs/specification/serialization/

It looks like OpenAPI supports serializing complex objects into a single header parameter like so

X-MyHeader: role=admin,firstName=Alex

We would have to add support for handling parameters sent in this format on the server side in order to enable this in the client library. Let me discuss this internally with the team.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants