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

feat: Adding "CORS" policy to opentrons APP #7599

Closed
beniroquai opened this issue Apr 7, 2021 · 2 comments · Fixed by #7632
Closed

feat: Adding "CORS" policy to opentrons APP #7599

beniroquai opened this issue Apr 7, 2021 · 2 comments · Fixed by #7632
Labels
feature-request A request for a new feature or a change that isn't a bug. May require further triage or scoping. robot-svcs Falls under the purview of the Robot Services squad (formerly CPX, Core Platform Experience).

Comments

@beniroquai
Copy link

beniroquai commented Apr 7, 2021

Overview

We are trying to interact with the opentrons API remotely and were already very successful with sending requests through python. Now we would like to integrate the API into the openflexure server system using the imjoy.io plugin environment. Wei, the creator of ImJoy and I tried creating a simple toggle-button plugin:

image

to remote control the opentrons within the plugin. The relevant code snippet is this here (a javascript post request as a ImJoy plugin):

<docs lang="markdown">
[TODO: write documentation for this plugin.]
</docs>
<config lang="json">
{
  "name": "OpentronsDemo",
  "type": "window",
  "tags": [],
  "ui": "",
  "version": "0.1.2",
  "api_version": "0.1.5",
  "description": "This is a backbone plugin for using Vue.js in ImJoy",
  "icon": "extension",
  "inputs": null,
  "outputs": null,
  "env": "",
  "requirements": [
      "https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.min.js",
      "https://static.imjoy.io/spectre.css/spectre.min.css",
      "https://static.imjoy.io/spectre.css/spectre-exp.min.css",
      "https://static.imjoy.io/spectre.css/spectre-icons.min.css"
  ],
  "dependencies": [],
  "defaults": {"w": 20, "h": 10},
  "runnable": true,
  "base_frame": "http://21.3.2.3:5000/baseframe.html"
}
</config>
<script lang="javascript">
const app = new Vue({
  el: '#app',
  data: {
    title: 'Opentrons Demo'
  },
  methods: {
    async toggleLight(){
      const payload = {'on': 'true' }
      const response = await fetch(
        'http://21.3.2.11:31950/robot/lights', 
        { method: 'POST',
          headers: {'opentrons-version': '*'},
          body: JSON.stringify(payload)
        })
      const data = await response.json()
      console.log(data)
    }
  }
})
class ImJoyPlugin {
  async setup() {
  }
  async run(my) {
  }
}
api.export(new ImJoyPlugin())
</script>
<window lang="html">
  <div style="text-align: center;" id="app">
    <h1>{{title}}</h1>
    <button class="btn" @click="toggleLight()">Toggle Light</button>
  </div>
</window>
<style lang="css">
</style>

When executing the plugin and sending the POST, we get the following error:

baseframe.html:1 Access to fetch at 'http://21.3.2.11:31950/robot/lights' from origin 'http://21.3.2.3:5000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Implementation details

Wei suggested to implement the following fix inside the app.py (opentrons/robot-server/robot_server/service/app.py):

import logging
import traceback

from fastapi.middleware.cors import CORSMiddleware
from opentrons import __version__
from fastapi import FastAPI, APIRouter, Depends
from fastapi.exceptions import RequestValidationError
from starlette.responses import Response, JSONResponse
from starlette.requests import Request
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.status import (
    HTTP_422_UNPROCESSABLE_ENTITY
)

from .logging import initialize_logging
from robot_server.service.legacy.models import V1BasicResponse
from .errors import V1HandlerError, \
    transform_http_exception_to_json_api_errors, \
    transform_validation_error_to_json_api_errors, \
    consolidate_fastapi_response, BaseRobotServerError, ErrorResponse, \
    build_unhandled_exception_response
from .dependencies import (
    get_rpc_server, get_protocol_manager, get_hardware_wrapper,
    verify_hardware, get_session_manager, check_version_header)
from robot_server import constants
from robot_server.service.legacy.routers import legacy_routes
from robot_server.service.session.router import router as session_router
from robot_server.service.pipette_offset.router import router as pip_os_router
from robot_server.service.labware.router import router as labware_router
from robot_server.service.protocol.router import router as protocol_router
from robot_server.service.system.router import router as system_router
from robot_server.service.tip_length.router import router as tl_router
from robot_server.service.notifications.router import router as \
    notifications_router




log = logging.getLogger(__name__)


app = FastAPI(
    title="Opentrons OT-2 HTTP API Spec",
    description="This OpenAPI spec describes the HTTP API of the Opentrons "
                "OT-2. It may be retrieved from a robot on port 31950 at "
                "/openapi. Some schemas used in requests and responses use "
                "the `x-patternProperties` key to mean the JSON Schema "
                "`patternProperties` behavior.",
    version=__version__,
)

# disable CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "https://lib.imjoy.io",
        "http://21.3.2.3:5000",
    ],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["Content-Type", "Authorization"],
)

in order to disable CORS.

Do you think this is possible? Or is this a very user-specific case?

Design

Acceptance criteria

Solved, if we can remote control the opentrons through an ImJoy plugin.

@beniroquai beniroquai added the feature-request A request for a new feature or a change that isn't a bug. May require further triage or scoping. label Apr 7, 2021
@SyntaxColoring SyntaxColoring added the robot-svcs Falls under the purview of the Robot Services squad (formerly CPX, Core Platform Experience). label Apr 12, 2021
@mcous
Copy link
Contributor

mcous commented Apr 16, 2021

@beniroquai I think you noticed this issue right at the same time we noticed! We believe HTTP API should be interactable from any origin; the lack of CORS middleware was on oversight.

#7632 includes your requested change with an allow_origins value of *. We may be able to get this into the upcoming 4.3 release unfortunately missed the window on 4.3, but it'll certainly by 4.4

@beniroquai
Copy link
Author

One more update on this issue (just for brevity).
We were able to use ImJoy inside the Opentrons Jupyter notebook:

image

With this you can use all kinds of machine learning plugins :-)

Closing the issue for now (or was already closed..nice!:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request A request for a new feature or a change that isn't a bug. May require further triage or scoping. robot-svcs Falls under the purview of the Robot Services squad (formerly CPX, Core Platform Experience).
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants