REST

oTree有一个REST API使得外部程序(如其他网站)可与oTree通信。

REST API是一个在你的服务器上被设计用来被其他程序使用的URL,而不是用于在浏览器中手动打开的。

一个使用了很多REST API的项目是 oTree HR

开始

注解

“这些代码应当放在哪里”

这些代码无需包含在你的oTree项目文件夹中。由于REST API的关键就在于使得外部程序和服务器可以与oTree通过网络通信,你应当将这些代码放在其他程序中。这意味着你可以使用在其他服务器上适用的任何语言来编写程序。本页面上的例子使用的是Python,但是使用其他编程语言进行HTTP请求也很简单,如webhooks工具或者cURL。

import requests  # pip3 install requests
from pprint import pprint


GET = requests.get
POST = requests.post

# if using Heroku, change this to https://YOURAPP.herokuapp.com
SERVER_URL = 'http://localhost:8000'
REST_KEY = ''  # fill this later

def call_api(method, *path_parts, **params) -> dict:
    path_parts = '/'.join(path_parts)
    url = f'{SERVER_URL}/api/{path_parts}/'
    resp = method(url, json=params, headers={'otree-rest-key': REST_KEY})
    if not resp.ok:
        msg = (
            f'Request to "{url}" failed '
            f'with status code {resp.status_code}: {resp.text}'
        )
        raise Exception(msg)
    return resp.json()

“oTree version” endpoint

注解

在2021年3月新引入的beta特性。

GET URL: /api/otree_version/

例子

data = call_api(GET, 'otree_version')
# returns: {'version': '5.0.0'}

“Session configs” endpoint

注解

在2021年3月新引入的beta特性。

GET URL: /api/session_configs/

返回所有session config组成的列表,使用字典存储它们的所有属性。

例子

data = call_api(GET, 'session_configs')
pprint(data)

“Rooms” endpoint

注解

在2021年3月新引入的beta特性。

GET URL: /api/rooms/

例子

data = call_api(GET, 'rooms')
pprint(data)

示例输出(注意它包含了 session_code,如果房间中当前存在一个会话的话):

[{'name': 'my_room',
  'session_code': 'lq3cxfn2',
  'url': 'http://localhost:8000/room/my_room'},
 {'name': 'live_demo',
  'session_code': None,
  'url': 'http://localhost:8000/room/live_demo'}]

“Create sessions” endpoint

POST URL: /api/sessions/

下面是一些”create sessions”路径应当如何使用的例子:

  • 其他网站可自动创建oTree会话
  • 你可以自己创造一个更好看的oTree 配置会话 界面(例如加上侧边栏和控件)
  • 在某些固定时刻创建oTree会话的进程
  • 创建自定义会话的命令行脚本(如果 otree create_session 不够用的话)

例子

data = call_api(
    POST,
    'sessions',
    session_config_name='trust',
    room_name='econ101',
    num_participants=4,
    modified_session_config_fields=dict(num_apples=10, abc=[1, 2, 3]),
)
pprint(data)

参数

  • session_config_name (必要)
  • num_participants (必要)
  • modified_session_config_fields: 一个可选的包含session config参数的字典,详见 配置会话
  • room_name 如果你想在房间中创建session。

“Get session data” endpoint

注解

2021年3月引入的新特性。将处于测试阶段直到获取足够的用户反馈。

GET URL: /api/sessions/{code}

此API将取回关于会话及其参与人的数据。如果略去 participant_labels,那么将返回所有参与人的数据。

例子

data = call_api(GET, 'sessions', 'vfyqlw1q', participant_labels=['Alice'])
pprint(data)

“Session vars” endpoint

注解

在2021年4月,这一路径要求你传入会话代码作为路径参数。如果会话在房间中的话,你可以通过 rooms 路径获得会话代码。

POST URL: /api/session_vars/{session_code}

这一路径使你可以设置 session.vars。一种用途是实验输入。举例来说,如果实验中有一次抽奖,就可以通过运行下面的脚本来输入结果。

例子

call_api(POST, 'session_vars', 'vfyqlw1q', vars=dict(dice_roll=4))

“Participant vars” endpoint

POST URL: /api/participant_vars/{participant_code}

通过 web services / webhooks 将参与人的信息传递给oTree。

例子

call_api(POST, 'participant_vars', 'vfyqlw1q', vars=dict(birth_year='1995', gender='F'))

“Participant vars for room” endpoint

POST URL: /api/participant_vars/

类似于”participant vars”路径,但这一API可在你不知道参与人代码时使用。你可以通过房间的名字以及参与人标签来指定参与人。

例子

call_api(
    POST,
    'participant_vars',
    room_name='qualtrics_study',
    participant_label='albert_e',
    vars=dict(age=25, is_male=True, x=[3, 6, 9]),
)

参数

  • room_name (必要)
  • participant_label (必要)
  • vars (必要): 用于加入participant vars的字典, 其中值必须是可被JSON序列化的数据类型, 甚至可以是嵌套的字典/列表。

你需要给参与人一个带 participant_label 的链接,尽管它不必包含在 participant_label_file 中。

认证

如果你将你的验证等级从DEMO改为STUDY,你必须验证你的REST API请求。

在服务器上创建一个环境变量(即 Heroku config var) OTREE_REST_KEY 。将其设置为某个秘密值。

在发送请求时,在HTTP header里将其添加为 otree-rest-key。如果按照上面的 例子 ,你应当设置 REST_KEY 变量。

演示 & 测试

为在开发时更便利,你可以在一个真实的会话中生成假的vars来模拟从REST API获得的数据。

在你的session config中,添加参数 mock_exogenous_data=True (称其为 exogenous(外源性) 数据是因为其是在oTree外部生成的。)

然后在你的项目的shared_out.py中(如果你使用的是文本编辑器,你可能需要创建此文件)定义一个同名函数(mock_exogenous_data)。

下面是一个例子:

def mock_exogenous_data(session):
    participants = session.get_participants()
    for pp in participants:
        pp.vars.update(age=20, is_male=True) # or make it random

你也可以在此处设置参与人标签。

当你的会话运行在demo模式下,或者使用bot, mock_exogenous_data() 会在 creating_session 之后自动运行。然而,如果是在房间里创建的会话则不会运行。

如果你有多个session config需要不同的外源性数据,你可以像下面这样区分它们:

def mock_exogenous_data(session):
    if session.config['name'] == 'whatever':
        ...
    if 'xyz' in session.config['app_sequence']:
        ...