# **smyApps4.2authtime接口说明文档 V1.0** ## 1. RESTful API 设计规范与约定说明 ### 1.1 **路径规则(Endpoint rule)** 路径又称"终点"(endpoint),表示API的具体网址。 在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数。 举例来说,有一组API分别提供Document、表单、视图的信息,则它的路径应该设计成下面这样。 ``` - https://api.example.com/runtime/documents - https://api.example.com/runtime/forms - https://api.example.com/runtime/views ``` 以上路径规则是面向资源的,对于CRUD操作是非常友好的,但是面向一些“动作”或“行为”等一些不符合CRUD的服务请求(如操作按钮的运行执行前脚本),单纯的面向资源的路径构建规则就会让人困惑了。 这种情况我们可以以“子资源”来对待(资源后面加行为动词),例如:GitHub上,对一个gists加星操作: ``` PUT /gists/:id/star ``` 并且取消星操作: ``` DELETE /gists/:id/star ``` 举例来说,有一组API分别提供执行操作按钮的执行前、执行后脚本和业务处理行为,则它的路径应该设计成下面这样。 ``` - https://api.example.com/runtime/activitys/{id}/excute - https://api.example.com/runtime/activitys/{id}/beforactionscript - https://api.example.com/runtime/activitys/{id}/afteractionscript ``` ### 1.2 **HTTP动词 (Http method)** 对于资源的具体操作类型,由HTTP动词表示。 常用的HTTP动词有下面五个(括号里是对应的SQL命令)。 ``` - GET(SELECT):从服务器取出资源(一项或多项)。 - POST(CREATE):在服务器新建一个资源。 - PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。 - PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。 - DELETE(DELETE):从服务器删除资源。 ``` 下面是一些例子。 ``` - GET /runtime/documents:获取Document集合 - POST /runtime/documents:新建一个Document - GET /runtime/documents/{id}:获取由ID指定的Document - PUT /runtime/documents/{id}:更新由ID指定的Document(客户端提供全部信息,完整更新) - PATCH /runtime/documents/{id}:更新由ID指定的Document(客户端提供部分信息,局部更新) - DELETE /runtime/documents/{id}:删除由ID指定的Document ``` ### 1.3 **过滤信息(Filtering)** 如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。 下面是一些常见的参数。 ``` - ?_page=2&_page_lines=30:指定第几页,以及每页的记录数。 - ?_sortby=name&_order=asc:指定返回结果按照哪个属性排序,以及排序顺序。 - ?form_type =1:指定筛选条件。 ``` 参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如, ``` GET /runtime/documents/{id}/flowhis ``` 与 ``` GET /runtime/flowhis?doc_id={id} ``` 的含义是相同的。 ### 1.4 **状态码(Status codes)** ------ 服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。 下面是一些常见的状态码。 ``` - 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 - 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 - 202 Accepted - [\*]:表示一个请求已经进入后台排队(异步任务) - 204 NO CONTENT - [DELETE]:用户删除数据成功。 - 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 - 401 Unauthorized - [\*]:表示用户没有权限(令牌、用户名、密码错误)。 - 403 Forbidden - [\*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。 - 404 NOT FOUND - [\*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 - 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。 - 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。 - 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 - 500 INTERNAL SERVER ERROR - [\*]:服务器发生错误,用户将无法判断发出的请求是否成功。 - 4001 INTERNAL SERVER ERROR - [\*]:服务器校验错误 ``` ### 1.5 **错误处理(Error handling)** 就像html错误页面能够显示错误信息一样,API 也应该能返回可读的错误信息,它应该和一般的资源格式一致。 - API应该始终返回相应的状态码,以反映服务器或者请求的状态。 - API的错误码可以分为两部分,400系列和500系列,400系列表明客户端错误:如错误的请求格式等。500系列表示服务器错误。 - API应该至少将所有的400系列的错误以JSON形式返回。如果可能500系列的错误也应该如此。 - JSON格式的错误应该包含以下信息:一个有用的错误信息,一个唯一的错误码,以及任何可能的详细错误描述。如下: ``` { "errcode" : 40035, "errmsg" : "不合法的参数" } ``` - 对PUT,POST,PATCH的输入的校验也应该返回相应的详细错误信息,例如: ``` { "errcode" : 40035, "errmsg" : "Validation Failed", "errors" : [ { "errcode" : 1234, "field" : "first_name", "errmsg" : "First name cannot have fancy characters" }, { "errcode" : 1234, "field" : "password", "errmsg" : "Password cannot be blank" } ] } ``` ### 1.6 **数据结构(Data structure)** - 在POST,PUT,PATCH上使用JSON作为输入。 - 注意使用JSON传输的时候,要求请求头里面加入:Content-Type:applicatin/json.否则抛出415异常(unsupported media type)。 - 服务器返回的数据格式,统一使用JSON作为输出。 > 服务器返回的JSON数据结构统一如下: ``` { "errcode" : 0, "errmsg" : "some message", "data" : {}, "errors" : [] } ``` > 参数说明: | 参数 | 必须 | 说明 | | ------- | ---- | -------------------- | | errcode | 是 | 状态码/返回码 | | errmsg | 是 | 消息 | | data | 是 | 服务端返回的数据对象 | | errors | 否 | 详细错误信息 | ### 1.7 **其他** ------ 1. 客户端控制服务端是否需要返回数据、且返回哪些数据的约定 2. Urls命名规则统一使用蛇形命名法(下划线和小写) ## 1. **邮箱模块** ### 登录邮箱 **请求方式:** POST **请求地址:** /api/email/userLogin **请求包体:** ``` { "ownerid": "ownerid", "name": "name", "account": "account", "password": "password" "parentid": "value" } ``` **参数说明:** | **参数** | **必须** | **说明** | | -------- | -------- | -------- | | content | 是 | 请求包体 | **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok", "data": "登录成功" } ``` **参数说明:** | **参数** | **说明** | | -------- | ------------------------ | | errcode | 返回码(0=成功,1=失败) | | errmsg | 对返回码的文本描述内容 | ### 获取邮箱文件夹列表 **请求方式:** GET **请求地址:** /api/email/getFolderList **参数说明:** **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok", "data": [ { "id": "-1224431040", "ownerId": null, "name": "Junk", "displayName": "{*[core.email.folder.junk]*}", "createDate": null }, { "id": "1077161872", "ownerId": null, "name": "Sent Messages", "displayName": "{*[core.email.folder.sent]*}", "createDate": null }, { "id": "131906345", "ownerId": null, "name": "Deleted Messages", "displayName": "{*[core.email.folder.removed]*}", "createDate": null }, { "id": "-877551452", "ownerId": null, "name": "INBOX", "displayName": "{*[core.email.folder.inbox]*}", "createDate": null }, { "id": "-1130595004", "ownerId": null, "name": "Drafts", "displayName": "{*[core.email.folder.drafts]*}", "createDate": null } ] } ``` **参数说明:** | **参数** | **说明** | | -------- | ------------------------ | | errcode | 返回码(0=成功,1=失败) | | errmsg | 对返回码的文本描述内容 | ### 获取邮箱后缀 **请求方式:** GET **请求地址:** /api/email/getEmailSuffix **参数说明:** **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok", "data": "weioa365.com" } ``` **参数说明:** | **参数** | **说明** | | -------- | ------------------------ | | errcode | 返回码(0=成功,1=失败) | | errmsg | 对返回码的文本描述内容 | ### 获取邮箱文件夹中邮件列表 **请求方式:** GET **请求地址:** /api/email/getFolderEmails?folderId={folderId} **参数说明:** | **参数** | **必须** | **说明** | | ------------ | -------- | ---------------- | | folderId | 是 | 文件夹id | | unread | 否 | 已读、未读 | | departmentId | 否 | 发件人所在部门id | | smSubject | 否 | 主题 | | smFrom | 否 | 发件人 | | startDate | 否 | 开始日期 | | endDate | 否 | 结束日期 | | pageNo | 否 | 页码 | | linesPerPage | 否 | 每页显示数据数 | **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok", "data": { "rowCount": 777, "linesPerPage": 10, "pageNo": 1, "datas": [{ "id": "777", "emailBody": { "id": null, "subject": "2020/7/17工作进度跟踪情况(DailyReport2020/7/17)", "content": null, "from": "钟燕华", "to": "jarod", "cc": "gzcp, gzcp, gzxmy, gzxmw, gzxms", "bcc": null, "sendDate": "2020-07-18T12:30:33.000+0000", "attachments": [], "multipart": true, "fromdep": null }, "read": false, "emailFolder": { "id": "-877551452", "ownerId": null, "name": null, "displayName": null, "createDate": null }, "readDate": null, "emailId": 0, "reply": false, "forward": false, "emailUser": null, "msgLevel": 0 }, { "id": "776", "emailBody": { "id": null, "subject": "7月16日考勤", "content": null, "from": "vicky", "to": "teemlink, teemlink", "cc": "jarod", "bcc": null, "sendDate": "2020-07-17T07:22:50.000+0000", "attachments": [], "multipart": true, "fromdep": null }, "read": true, "emailFolder": { "id": "-877551452", "ownerId": null, "name": null, "displayName": null, "createDate": null }, "readDate": null, "emailId": 0, "reply": false, "forward": false, "emailUser": null, "msgLevel": 0 } ], "pageCount": 78 } } ``` **参数说明:** | **参数** | **说明** | | -------- | ------------------------ | | errcode | 返回码(0=成功,1=失败) | | errmsg | 对返回码的文本描述内容 | ### 获取邮件详情 **请求方式:** GET **请求地址:** /api/email/getEmail?folderId={folderId}&emailId={emailId} **参数说明:** | **参数** | **必须** | **说明** | | -------- | -------- | -------- | | folderId | 是 | 文件夹id | | emailId | 是 | 邮件id | **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok", "data": { "id": "776", "emailBody": { "id": null, "subject": "7月16日考勤", "content": "html标签", "from": "vicky ", "to": "teemlink , teemlink ", "cc": "jarod ", "bcc": null, "sendDate": "2020-07-17T07:22:50.000+0000", "attachments": [ { "id": null, "fileName": "7月考勤统计.xlsx", "realFileName": "7月考勤统计.xlsx", "fileText": null, "path": null, "createDate": null, "size": 64678, "content": null, "emailid": null } ], "multipart": true, "fromdep": null }, "read": true, "emailFolder": { "id": "-877551452", "ownerId": null, "name": "INBOX", "displayName": null, "createDate": null }, "readDate": null, "emailId": 0, "reply": false, "forward": false, "emailUser": null, "msgLevel": 0 } } ``` **参数说明:** | **参数** | **说明** | | -------- | ------------------------ | | errcode | 返回码(0=成功,1=失败) | | errmsg | 对返回码的文本描述内容 | ### 发送邮件 **请求方式:** POST **请求地址:** /api/email/sendEmail?folderId={folderId} **参数说明:** | **参数** | **必须** | **说明** | | -------- | -------- | -------- | | folderId | 是 | 文件夹id | | content | 是 | 请求包体 | **权限说明:** 无。 **请求包体:** ``` { "from":"from", "to":"to", "subject":"subject", "content“:”content“, "cc":"cc", "bcc":"bcc", "attids":["attid","attid"] } ``` **包体参数说明:** | **参数** | **说明** | | -------- | -------- | | from | 发件人 | | to | 收件人 | | subject | 主题 | | content | 内容 | | cc | 抄送 | | bcc | 密送 | | attids | 附件id | **返回结果:** ``` { "errcode": 0, "errmsg": "ok", "data": { "id": "17", "emailBody": { "id": null, "subject": "3333333", "content": "222222", "from": "肖专员-华北区(销售专员) ", "to": "肖专员-华北区(销售专员) ", "cc": null, "bcc": null, "sendDate": null, "attachments": [], "multipart": false, "fromdep": null }, "read": false, "emailFolder": { "id": "1077161872", "ownerId": null, "name": "Sent Messages", "displayName": "{*[core.email.folder.sent]*}", "createDate": null }, "readDate": null, "emailId": 0, "reply": false, "forward": false, "emailUser": null, "msgLevel": 0 } } ``` **参数说明:** | **参数** | **说明** | | -------- | ------------------------ | | errcode | 返回码(0=成功,1=失败) | | errmsg | 对返回码的文本描述内容 | ### 删除邮件(可批量) **请求方式:** DELETE **请求地址:** /api/email/removeEmail?folderId={folderId} **参数说明:** | **参数** | **必须** | **说明** | | -------- | -------- | ---------------- | | folderId | 是 | 文件夹id | | ids | 是 | 请求包体(邮件id) | **请求包体:** ``` [ "id1", "id2" ] ``` **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok" } ``` **参数说明:** | **参数** | **说明** | | -------- | ------------------------ | | errcode | 返回码(0=成功,1=失败) | | errmsg | 对返回码的文本描述内容 | ### 彻底删除邮件(可批量) **请求方式:** DELETE **请求地址:** /api/email/deleteEmail?folderId={folderId} **参数说明:** | **参数** | **必须** | **说明** | | -------- | -------- | ---------------- | | folderId | 是 | 文件夹id | | ids | 是 | 请求包体(邮件id) | **请求包体:** ``` [ "id1", "id2" ] ``` **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok" } ``` **参数说明:** | **参数** | **说明** | | -------- | ------------------------ | | errcode | 返回码(0=成功,1=失败) | | errmsg | 对返回码的文本描述内容 | ### 标记邮件(已读、未读) **请求方式:** POST **请求地址:** /api/email/markEmail?folderId={folderId}&mark={mark} **参数说明:** | **参数** | **必须** | **说明** | | -------- | -------- | ---------------------- | | folderId | 是 | 文件夹id | | mark | 是 | 标记(0--未读,1--已读) | | ids | 是 | 请求包体(邮件id) | **权限说明:** 无。 **请求包体:** ``` [ "id1", "id2" ] ``` **包体参数说明:** **返回结果:** ``` { "errcode": 0, "errmsg": "ok" } ``` **参数说明:** | **参数** | **说明** | | -------- | ------------------------ | | errcode | 返回码(0=成功,1=失败) | | errmsg | 对返回码的文本描述内容 | ### 删除邮件附件 **请求方式:** DELETE **请求地址:** /api/email/removeAttachment?id={id} **参数说明:** | **参数** | **必须** | **说明** | | -------- | -------- | -------- | | id | 是 | 附件id | **权限说明:** 无。 **包体参数说明:** **返回结果:** ``` { "errcode": 0, "errmsg": "ok" } ``` **参数说明:** | **参数** | **说明** | | -------- | ------------------------ | | errcode | 返回码(0=成功,1=失败) | | errmsg | 对返回码的文本描述内容 | ### 邮件附件上传 **请求方式:** POST **请求地址:** /api/email/uploadAttachment **参数说明:** | **参数** | **必须** | **说明** | | -------- | -------- | -------------- | | files | 是 | 上传文件二进制 | **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok" } ``` **参数说明:** | **参数** | **说明** | | | -------- | ------------------------ | ---- | | errcode | 返回码(0=成功,1=失败) | | | errmsg | 对返回码的文本描述内容 | | ### 下载邮件附件 **请求方式:** POST **请求地址:** /api/email/downloadAttachment?folderId={folderId}&emailId={emailId}&fileName={fileName} **参数说明:** | **参数** | **必须** | **说明** | | -------- | -------- | -------- | | folderId | 是 | 文件夹id | | emailId | 是 | 邮件id | | fileName | 是 | 文件名称 | **权限说明:** 无。 **返回结果:** ``` 无 ``` **参数说明:** | **参数** | **说明** | | | -------- | ------------------------ | ---- | | errcode | 返回码(0=成功,1=失败) | | | errmsg | 对返回码的文本描述内容 | | ## 2. **用户选择框模块** ### 获取以部门为树形结构的用户集合 根据客户端传递的父级部门id参数,服务器返回直属下级部门和用户的集合,以树形结构的方式描述数据。 **请求方式:** GET **请求地址:**/api/email/{applicationId}/users/selectbox/department?deptId={deptId} **参数说明:** | **参数** | **必须** | **说明** | | ------------- | -------- | -------------- | | applicationId | 是 | 软件id | | deptId | 是 | 父级部门id | | pageNum | 是 | 当前页 | | pageSize | 是 | 每页显示数据数 | **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok", "data": { "datas": [ { "avatar": "", "dept": "自动化测试用例系统企业域", "email": "", "id": "11e7-661d-31b9954a-8f1a-bfe936d3ae2a", "mobile": "13025478965", "mobile2": "", "name": "伟强", "type": 1 }, { "children": [], "id": "11e7-5f99-e70d1a49-917f-e799edecb417", "name": "测试部", "type": 2 } ], "pageCount": 1, "rowCount": 2, "pageNum": 1, "linesPerPage": 5 } } ``` **参数说明:** | **参数** | **说明** | | ------------ | ---------------------- | | errcode | 返回码 | | errmsg | 对返回码的文本描述内容 | | datas | 部门下用户 | | pageCount | 总页数 | | rowCount | 总行数 | | pageNum | 当前页 | | linesPerPage | 每页显示条数 | ### 获取以角色为树形结构的用户集合 ------------------------------ 根据客户端传递的角色id参数,服务器返回该角色下的用户的集合,以树形结构的方式描述数据。 **请求方式:** GET **请求地址:**/api/email/{applicationId}/users/selectbox/role?roleId={roleId}&pageSize={pageSize}&pageNum={pageNum}&flowId={flowId}&nodeId={nodeId}&docId={docId}&type={type} **参数说明:** | **参数** | **必须** | **说明** | | ------------- | -------- | ------------------------------------------------------------ | | applicationId | 是 | 软件id | | roleId | 是 | 角色id | | pageSize | 是 | 每页显示数据数(传入0时默认显示5条数据) | | pageNum | 是 | 当前页(传入0时默认显示第一页) | | flowId | 是 | 流程id | | nodeId | 是 | 节点id(指定抄送传的是当前节点id,指定审批人是下一节点id) | | docId | 是 | 文档id | | type | 是 | 类型(传1是指定下一节点审批人,传2指定抄送人,其他传0或者不传) | **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok", "data": { "datas": [ { "id": "11e7-5f9a-595d2be8-917f-e799edecb417", "name": "员工", "type": 4 }, { "id": "11e7-6bb9-a4500a1c-a461-afe7c10bb740", "name": "总经理", "type": 4 } ] } } { "errcode": 0, "errmsg": "ok", "data": { "datas": [ { "id": "11e7-5f9a-210f9112-917f-e799edecb417", "name": "李玲", "type": 1, "mobile": "", "mobile2": "", "email": "jack@teemlink.com", "avatar": null, "dept": "自动化测试组", "deptId": "11e7-5f9a-0020047a-917f-e799edecb417", "loginNo": "liling", "domainId": "11e7-5f99-cc5d96f1-917f-e799edecb417" } ], "pageCount": 1, "rowCount": 2, "pageNum": 1, "linesPerPage": 5 } } ``` **参数说明:** | **参数** | **说明** | | ------------ | ---------------------- | | errcode | 返回码 | | errmsg | 对返回码的文本描述内容 | | datas | 角色下用户集合 | | pageCount | 总页数 | | rowCount | 总行数 | | pageNum | 当前页 | | linesPerPage | 每页显示条数 | ### 获取通讯录用户集 -------------------------------- 服务器返回通讯录下所有用户的集合数据。 **请求方式:** GET **请求地址:**/api/email/users/selectbox/contacts?contactsId={contactsId}&pageSize={pageSize}&pageNum **参数说明:** | **参数** | **必须** | **说明** | | ---------- | -------- | ------------ | | contactsId | 否 | 通讯录分组id | | pageSize | 否 | 每页显示条数 | | pageNom | 否 | 当前页 | **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok", "data": { "datas": [ { "avatar": "", "dept": "自动化测试用例系统企业域", "email": "", "id": "11e7-661d-31b9954a-8f1a-bfe936d3ae2a", "mobile": "13025478965", "mobile2": "", "name": "伟强", "type": 1 } ], "pageCount": 1, "rowCount": 2, "pageNum": 1, "linesPerPage": 5 } } ``` **参数说明:** | **参数** | **说明** | | ------------ | ---------------------- | | errcode | 返回码 | | errmsg | 对返回码的文本描述内容 | | datas | 通讯录下用户集合 | | pageCount | 总页数 | | rowCount | 总行数 | | pageNum | 当前页 | | linesPerPage | 每页显示条数 | ### 模糊查询用户 ------------ 根据联系人姓名,首字母,电话进行模糊查询,服务器返回用户的集合。 **请求方式:** GET **请求地址:**/api/email/users/selectbox/search?keyWord={keyWord}&pageNum={pageNum}&pageSize={pageSize} **参数说明:** | **参数** | **必须** | **说明** | | -------- | -------- | ------------ | | pageNum | 否 | 当前页 | | pageSize | 否 | 每页显示条数 | | keyWord | 否 | 关键字 | **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok", "datas": [ { "avatar": "", "dept": "自动化测试用例系统企业域", "email": "", "id": "11e7-661d-31b9954a-8f1a-bfe936d3ae2a", "mobile": "13025478965", "mobile2": "", "name": "伟强", "type": 1 } ], "pageCount": 1, "rowCount": 2, "pageNum": 1, "linesPerPage": 5 } ``` **参数说明:** | **参数** | **说明** | | ------------ | ---------------------- | | errcode | 返回码 | | errmsg | 对返回码的文本描述内容 | | datas | 查询用户用户集合 | | pageCount | 总页数 | | rowCount | 总行数 | | pageNum | 当前页 | | linesPerPage | 每页显示条数 | ### 根据父级获取部门集合 -------- 根据客户端传递的部门名称,服务器返回查询出的部门集合。 **请求方式:** GET **请求地址:**/api/email/departments/selectbox/childs?parentId={parentId} **参数说明:** | **参数** | **必须** | **说明** | | -------- | -------- | -------- | | parentId | 否 | 部门id | **权限说明:** 无。 **返回结果:** ``` { "errcode": 0, "errmsg": "ok", "data": [ { "id": "11e7-654a-2b182ffe-9cdb-af6bc8266ed2", "name": "产品部", "count": 2, "child": false }, { "id": "11e7-654a-2b182ffe-9cdb-af6bc8266ed2", "name": "产品部", "count": 2, "child": true } ] } ``` **参数说明:** | **参数** | **说明** | | -------- | ---------------------- | | errcode | 返回码 | | errmsg | 对返回码的文本描述内容 | | data | 返回部门数据 |