主要架构
为知笔记服务主要分为两部分:
- 账号服务
- 数据服务
其中账号服务(as: Account Server)只有一个服务地址,主要提供账号相关的服务,例如登录,注销,获取用户信息,获取用户数据信息等。
一个账号可以有一个或者多个知识库(kb: Knowledge Base),每一个kb都是独立的。每一个kb,数据都保存在某一个数据服务上面。
数据服务(ks: Knowledge Server)可能有多个,每一个数据服务都包含若干kb,提供数据的读写服务。
登录
可以使用用户名密码直接登录,如果登录正常,服务器将返回用户个人kb,token等信息。
const axios = require('axios');
const AS_URL = 'https://as.wiz.cn';
async function execRequest(method, url, body, token) {
const options = {
url,
method,
data: body,
};
if (token) {
options.headers = {
'X-Wiz-Token': token,
};
}
const res = await axios(options);
const data = res.data;
if (data.returnCode !== 200) {
console.error(`request error: ${data.returnMessage}`);
const err = new Error(data.returnMessage);
err.code = data.returnCode;
err.externCode = data.externCode;
throw err;
}
return data.result;
}
async function login(userId, password) {
return await execRequest('post', `${AS_URL}/as/user/login`, {userId, password});
}
async function getFolders(kbServer, kbGuid, token) {
return await execRequest('get', `${kbServer}/ks/category/all/${kbGuid}`, null, token);
}
async function test() {
const userId = 'test_api@wiz.cn';
const password = '123456';
try {
const loginResult = await login(userId, password);
console.log(JSON.stringify(loginResult, null, 2));
} catch (err) {
if (err.externCode === 'WizErrorInvalidPassword') {
console.error('Invalid password');
} else {
console.error(err.message);
}
}
}
test();
获取个人笔记文件夹列表
用户登录返回的信息里面,包含kb服务器地址:(kbServer), kbGuid,我们可以利用这两个参数,向ks发送请求获取相应的数据:
async function getFolders(kbServer, kbGuid, token) {
return await execRequest('get', `${kbServer}/ks/category/all/${kbGuid}`, null, token);
}
async function test() {
const userId = 'test_api@wiz.cn';
const password = '123456';
try {
const loginResult = await login(userId, password);
console.log(JSON.stringify(loginResult, null, 2));
//
const {kbServer, kbGuid, token} = loginResult;
const folders = await getFolders(kbServer, kbGuid, token);
console.log(JSON.stringify(folders, null, 2));
//
} catch (err) {
if (err.externCode === 'WizErrorInvalidPassword') {
console.error('Invalid password');
} else {
console.error(err.message);
}
}
}
获取文件夹下面的笔记
async function getFolderNotes(kbServer, kbGuid, folder, token) {
const count = 50;
let start = 0;
let notes = [];
folder = encodeURIComponent(folder);
for (;;) {
let params = `start=${start}&count=${count}&category=${folder}&orderBy=created`;
let subNotes = await execRequest('get', `${kbServer}/ks/note/list/category/${kbGuid}?${params}`, null, token);
notes = notes.concat(subNotes);
start += count;
if (subNotes.length < count) {
break;
}
}
return notes;
}
async function test() {
const userId = 'test_api@wiz.cn';
const password = '123456';
try {
const loginResult = await login(userId, password);
console.log(JSON.stringify(loginResult, null, 2));
//
const {kbServer, kbGuid, token} = loginResult;
const folders = await getFolders(kbServer, kbGuid, token);
console.log(JSON.stringify(folders, null, 2));
//
for (let folder of folders) {
const notes = await getFolderNotes(kbServer, kbGuid, folder, token);
console.log(JSON.stringify(notes, null, 2));
}
//
} catch (err) {
if (err.externCode === 'WizErrorInvalidPassword') {
console.error('Invalid password');
} else {
console.error(err.message);
}
}
}
创建文件夹
async function createFolder(kbServer, kbGuid, parent, child, token) {
const body = {
parent,
child,
};
return await execRequest('post', `${kbServer}/ks/category/create/${kbGuid}`, body, token);
}
async function test() {
const userId = 'test_api@wiz.cn';
const password = '123456';
try {
const loginResult = await login(userId, password);
console.log(JSON.stringify(loginResult, null, 2));
//
const {kbServer, kbGuid, token} = loginResult;
const folders = await getFolders(kbServer, kbGuid, token);
console.log(JSON.stringify(folders, null, 2));
//
for (let folder of folders) {
const notes = await getFolderNotes(kbServer, kbGuid, folder, token);
console.log(JSON.stringify(notes, null, 2));
}
//
await createFolder(kbServer, kbGuid, '/', 'My Folder 1', token);
await createFolder(kbServer, kbGuid, '/', 'My Folder 2', token);
await createFolder(kbServer, kbGuid, '/My Folder 1/', 'My Sub Folder 1', token);
await createFolder(kbServer, kbGuid, '/My Folder 1/', 'My Sub Folder 2', token);
//
const folders2 = await getFolders(kbServer, kbGuid, token);
console.log(JSON.stringify(folders2, null, 2));
//
} catch (err) {
if (err.externCode === 'WizErrorInvalidPassword') {
console.error('Invalid password');
} else {
console.error(err.message);
}
}
}
新建笔记
async function createNote(kbServer, kbGuid, title, folder, html, extOptions, token) {
const url = `${kbServer}/ks/note/create/${kbGuid}`;
let note = {
kbGuid,
title,
category: folder,
html,
};
//
if (extOptions) {
note = Object.assign(note, extOptions);
}
//
return await execRequest('post', url, note, token);
}
const noteHtml = `
<!doctype html>
<html>
<head>
<title>Note from API</title>
</head>
<body>
<p>Hello WizNote</p>
</body>
</html>`;
async function test() {
const userId = 'test_api@wiz.cn';
const password = '123456';
try {
const loginResult = await login(userId, password);
console.log(JSON.stringify(loginResult, null, 2));
//
const {kbServer, kbGuid, token} = loginResult;
const folders = await getFolders(kbServer, kbGuid, token);
console.log(JSON.stringify(folders, null, 2));
//
for (let folder of folders) {
const notes = await getFolderNotes(kbServer, kbGuid, folder, token);
console.log(JSON.stringify(notes, null, 2));
}
//
await createFolder(kbServer, kbGuid, '/', 'My Folder 1', token);
await createFolder(kbServer, kbGuid, '/', 'My Folder 2', token);
await createFolder(kbServer, kbGuid, '/My Folder 1/', 'My Sub Folder 1', token);
await createFolder(kbServer, kbGuid, '/My Folder 1/', 'My Sub Folder 2', token);
//
const folders2 = await getFolders(kbServer, kbGuid, token);
console.log(JSON.stringify(folders2, null, 2));
//
const newNote1 = await createNote(kbServer, kbGuid, 'Hello WizNote', '/My Folder 1/', noteHtml, null, token);
console.log(JSON.stringify(newNote1, null, 2));
//
} catch (err) {
if (err.externCode === 'WizErrorInvalidPassword') {
console.error('Invalid password');
} else {
console.error(err.message);
}
}
}
运行之后的结果:
为知笔记API调用约定
判断请求是否成功
如果发生http错误,通常都是网络问题,也可能是为知笔记服务端没有正常启动等。具体请查看网络或者服务端日志。
如果没有发生http错误,除非特别说明,否则请求和返回的数据,都是json格式。
为知笔记API返回的数据,除非特别说明,格式如下:
{
returnCode: 200,
returnMessage: "OK",
externCode: "",
result: xxx
}
如果请求成功,则returnCode=200。
请求成功后,如果有返回结果,请求结果在result字段。result可能是一个值,也可能是一个对象。
所有不等于200的returnCode值,都表示请求失败。具体失败原因,可以参考returnMessage以及externCode。
externCode对于特定的失败原因会返回特定的值,可以用来区分错误原因。
returnMessage则是可阅读的错误提示,同样的错误也可能返回不同的内容,不要用来区分错误原因。
url里面的参数,包含路径参数以及query string参数
例如下面的url里面就包含参数,参数统一用:paramName表示,例如:bizGuid代表一个团队的Guid,请使用bizGuid的值替换
get /as/biz/user_kb_list?bizGuid=:bizGuid
get /as/user/avatar/:userGuid
get /ks/note/download/:kbGuid/:docGuid?downloadInfo=true|false&=downloadData=true|false
如果参数是可选值,例如downloadInfo=true|false,代表downloadInfo只有两种参数可选,分别是true或者false。
body参数
例如注册用户,则需要通过json提交userId, password两个参数
post /as/user/signup
body: {
userId,
password,
}
常见错误代码
returnCode可能的返回值如下:
- 200: 请求成功
- 301: 无效的token或者没有token
- 31002:密码错误
- 2000: 参数错误,通常是缺少参数,或者参数错误
- 2001:内部错误,通常是服务端遇到无法出路的错误,或者未知错误
- 2002:OSS错误,数据存储错误
- 2003:逻辑错误,例如数据错误等
- 2004:数据不存在错误
- 2005:禁止访问,通常是用户权限问题
- 2006:解压缩错误,通常是数据错误
- 2007:上传限制错误,通常代表用户vip可能过期等
- 2009:OAUTH错误,OAuth功能出错
externCode错误格式:
通常以WizError开头,例如:
- WizErrorServiceExpired:团队服务到期
- WizErrorUserNotExists:用户不存在
- WizErrorInvalidPassword:密码错误
- 具体错误,请参考具体的API请求。
为知笔记API token传递方式
调用为知笔记API的时候,除了用户注册等少数API,其他的API都需要用户token。token必须通过http请求的head传递,head key为X-Wiz-Token。
下面是一个例子:
async function execRequest(method, url, body, token) {
const options = {
url,
method,
data: body,
};
if (token) {
options.headers = {
'X-Wiz-Token': token,
};
}
const res = await axios(options);
const data = res.data;
if (data.returnCode !== 200) {
console.error(`request error: ${data.returnMessage}`);
const err = new Error(data.returnMessage);
err.code = data.returnCode;
err.externCode = data.externCode;
throw err;
}
return data.result;
}
Account Server
Knowledge Server
笔记相关
下载笔记
get /ks/note/download/:kbGuid/:docGuid?downloadInfo=1|0&=downloadData=1|0
新建笔记,用于web新建笔记
post /ks/note/create/:kbGuid
body: {
kbGuid,
html,
title,
category, //example: /My Notes/
}
保存笔记html,
put /ks/note/save/:kbGuid/:docGuid
body: {
kbGuid,
docGuid,
html,
url,
tags, //tagGuid1*tagGuid2
author,
keywords,
resources, //[a.png, 1.jpg] 需要上传笔记包含的所有资源文件,服务端会返回需要上传的resource
}
上传一个图片
post /ks/resource/upload/:kbGuid/:docGuid
content-type: multipart/form-data
body: {
kbGuid,
docGuid,
data, //resource file
}
获取笔记图片缩略图,如果不存在报告404
get /ks/note/abstract/:kbGuid/:docGuid
下载加密笔记数据,笔记资源,附件数据, 笔记缩略图
get /ks/object/download/:kbGuid/:docGuid?objType=document
下载附件数据
get /ks/object/download/:kbGuid/:docGuid?objId=:attGuid&objType=attachment
下载笔记资源数据
get /ks/object/download/:kbGuid/:docGuid?objId=:resName&objType=resource
获取笔记/附件历史版本列表
get /ks/history/list/:kbGuid/:docGuid?objType=document|attachment&objGuid=docGuid|attGuid
获取某一个文件夹下面的笔记列表
通过start和count进行分页获取。
get /ks/note/list/category/:kbGuid?category=:folder&withAbstract=true|false&start=:start&count=:count&orderBy=title|created|modified&ascending=asc|desc
获取某一个标签下面的笔记列表
get /ks/note/list/tag/:kbGuid?tag=:tagGuid&withAbstract=true|false&start=:start&count=:count&orderBy=title|created|modified&ascending=asc|desc
获取某一个笔记的附件列表
get /ks/note/attachments/:kbGuid/:docGuid
删除笔记
delete /ks/note/delete/:kbGuid/:docGuid/
获取某一个笔记资源数据,用于直接在浏览器内显示笔记内容
get /ks/note/view/:kbGuid/:docGuid/index_files/:resName
获取笔记html,用户在浏览器内直接显示笔记
get /ks/note/view/:kbGuid/:docGuid/
获取笔记信息
get /ks/note/info/:kbGuid/:docGuid
暂无评论内容