Hands On Money 任务挣闲钱系统分析与设计

The Documents on Software Analysis & Design Team Work

RESTful API 设计文档

标准

参考

目录

API

er model db design

//request: creating user 
POST /users HTTP/1.1
Content-Type: application/json
{
    "email": "user@example.com",
    "phone_number": "13123456789",
    "password": "password"
}
//response: create successfully
HTTP/1.1 201 Created  //redirect to /
Content-Type: application/json
{
    "user_id":123456,
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E"
}
//about access_token, see Flask-JWT doc(https://pythonhosted.org/Flask-JWT/) for further information.

//response: create conflicted, duplicate email or phone_number
HTTP/1.1 409 Conflict
Content-Type: application/json
{
    "error_code": 409,
    "error_msg": "create conflicted, duplicate email or phone_number, goto login"
}

用户登陆

//request: login by email
POST /sessions HTTP/1.1
Content-Type: application/json
{
    "email": "user@example.com",
    "password": "password"
}
//request: or login by phone_number
{
    "phone_number": "13123456789",
    "password": "password"
}
//response: login successfully, redirect to homepage
HTTP/1.1 200 OK
Content-Type: application/json
{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E"
}
//about access_token, see Flask-JWT doc(https://pythonhosted.org/Flask-JWT/) for further information.

//response: login failed, account not found/password incorrect
HTTP/1.1 404 Not Found
Content-Type: application/json
{
    "error_code": 404,
    "error_msg": "account not found/password incorrect"
}

用户登陆注销

//request: delete user session
DELETE /users/:user_id/session HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
//response: delete session successfully, redirect to login page
HTTP/1.1 200 OK
//response: Unauthorized JWT, do not delete any session and redirect to login page
HTTP/1.1 401 Unauthorized
//response: user Not Found, do not delete any session and redirect to login page
HTTP/1.1 404 Not Found

用户信息

//request: get user info
GET /users/:user_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
//response: get user info successfully
//user profile_photo will be downloaded independently from API
HTTP/1.1 200 OK
Content-Type: application/json
{
    "email": "",
    "phone_number": "",
    "profile_photo_path": "",
    "student_id": "",
    "name": "",
    "age": 0,
    "sex": "",
    "grade": "",
    "school": "",
    "bio": "",
    "balance": 0,
    "avg_comment": 0
}

//response: JWT missing/incorrect/timeout
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
    "error_code": 401,
    "error_msg": "Unauthorized"
}

//response: no this user:/users/:user_id in table
HTTP/1.1 404 Not Found
Content-Type: application/json
{
    "error_code": 404,
    "error_msg": "user Not Found"
}

用户信息修改

分段更新。

//request: update personality
PUT /users/:user_id/personality HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: application/json
{
    "nickname": "nickname",
    "bio": "bio"
}

//request: update school
PUT /users/:user_id/school HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: application/json
{
    "school": "school",
    "grade": "grade",
    "student_number": "sid"
}

//request: update personal_info
PUT /users/:user_id/personal_info HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: application/json
{
    "name": "name",
    "age": 0,
    "sex": "sex"
}

//request: update photo, after update, pull photo to client
POST /users/:user_id/profile_photo HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: image/jpeg
//response: update success, NOT FOR update photo
HTTP/1.1 200 OK
Content-Type: application/json
{
    "key1": "value",
    "key2": "value",
    "key3": "value"
}

//response: JWT missing/incorrect/timeout
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
    "error_code": 401,
    "error_msg": "Unauthorized"
}

//response: no this /users/:user_id in table
HTTP/1.1 404 Not Found
Content-Type: application/json
{
    "error_code": 404,
    "error_msg": "user Not Found"
}
//response: not support img format
HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json
{
    "error_code": 415,
    "error_msg": "Unsupported Media Type"
}

组织创建

//request: creating organization 
POST /users/:user_id/organizations HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: application/json
{
    "name": "organization_name",
    "bio": "bio",
}
//response: create successfully
HTTP/1.1 201 Created  //redirect to /organizations/:organization_id
Content-Type: application/json
{
    "organization_id":"123456"
}

//response: JWT missing/incorrect/timeout
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
    "error_code": 401,
    "error_msg": "Unauthorized"
}

//response: create conflicted, duplicate name
HTTP/1.1 409 Conflict
Content-Type: application/json
{
    "error_code": 409,
    "error_msg": "create conflicted, duplicate organization name"
}

组织信息

//request: get organization info. All registered user can see it.
GET /users/:user_id/organizations/:organization_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI

//request: get organization balance. Only admin can see it.
GET /users/:user_id/organizations/:organization_id/balance HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
//response: get organization info successfully. 
//user profile_photo will be downloaded independently from API
// NOTE: If you want member list to show more info of members, it will lead to N+1 problem, 
// see also (https://restfulapi.net/rest-api-n-1-problem/). Try server side solutions.
HTTP/1.1 200 OK
Content-Type: application/json
{
    "name": "",
    "bio": "",
    "avg_comment": 0,
    "members":[
        {
            "user_id": 123,
            "status": "status"
        },
        {
            "user_id": 123,
            "status": "status"
        }
    ]
}

//response: get organization balance successfully
HTTP/1.1 200 OK
Content-Type: application/json
{
    "balance": 0
}

//response: JWT missing/incorrect/timeout
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
    "error_code": 401,
    "error_msg": "Unauthorized"
}

//response: no this organization/:organization_id in table
HTTP/1.1 404 Not Found
Content-Type: application/json
{
    "error_code": 404,
    "error_msg": "organization Not Found"
}

组织信息修改

//request: update organization info
PUT /users/:user_id/organizations/:organization_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: application/json
{
    "name": "name",
    "bio": "bio"
}
//request: update organization photo, after update, pull photo to client
POST /users/:user_id/organizations/:organization_id/profile_photo HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: image/jpeg
//response: get organization info successfully. 
HTTP/1.1 200 OK
Content-Type: application/json
{
    "name": "",
    "bio": ""
}
//response: JWT missing/incorrect/timeout
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
    "error_code": 401,
    "error_msg": "Unauthorized",
}
//response: no this organization/:organization_id in table
HTTP/1.1 404 Not Found
Content-Type: application/json
{
    "error_code": 404,
    "error_msg": "organization Not Found"
}
//response: not support img format
HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json
{
    "error_code": 415,
    "error_msg": "Unsupported Media Type"
}

组织成员添加

//request: add organization member
POST /users/:user_id/organizations/:organization_id/members HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: application/json
{
    "email": "email@mail.com",
    "status": "member"
}
or
{
    "phone_number": "13123456789",
    "status": "member"
}
//response: add member successfully. Redirect to organization info
HTTP/1.1 201 Created

//response: JWT missing/incorrect/timeout, redirect to login;
//or you dont have permission to add member to such "status"
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
    "error_code": 401,
    "error_msg": "Unauthorized"
}
or
{
    "error_code": 401,
    "error_msg": "insufficient permission"
}
//response: no this user/organizations in users
HTTP/1.1 404 Not Found
Content-Type: application/json
{
    "error_code": 404,
    "error_msg": "user/organizations Not Found"
}

组织成员权限变更

//request: modify organization member status
PUT /users/:user_id/organizations/:organization_id/members/:user_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: application/json
{
    "status": "member"
}
//response: modify member successfully. Redirect to organization info
HTTP/1.1 200 OK

//response: JWT missing/incorrect/timeout, redirect to login;
//or you dont have permission to modify member to such "status"
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
    "error_code": 401,
    "error_msg": "Unauthorized"
}
or
{
    "error_code": 401,
    "error_msg": "insufficient permission"
}
//response: no this user/organizations in users
HTTP/1.1 404 Not Found
Content-Type: application/json
{
    "error_code": 404,
    "error_msg": "user/organizations Not Found"
}

组织成员删除

//request: delete organization member
DELETE /users/:user_id/organizations/:organization_id/members/:user_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
//response: delete member successfully. Redirect to organization info
HTTP/1.1 200 OK

//response: JWT missing/incorrect/timeout, redirect to login;
//or you dont have permission to delete member while he is in such "status"
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
    "error_code": 401,
    "error_msg": "Unauthorized"
}
or
{
    "error_code": 401,
    "error_msg": "insufficient permission"
}
//response: no this user/organizations in users
HTTP/1.1 404 Not Found
Content-Type: application/json
{
    "error_code": 404,
    "error_msg": "user/organizations Not Found"
}

组织删除

//request: delete organization, only creator
DELETE /users/:user_id/organizations/:organization_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
//response: show deleted organization info. 
HTTP/1.1 200 OK
Content-Type: application/json
{
    "name": "",
    "bio": ""
}
//response: JWT missing/incorrect/timeout
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
    "error_code": 401,
    "error_msg": "Unauthorized",
}
//response: no this organization/:organization_id in table
HTTP/1.1 404 Not Found
Content-Type: application/json
{
    "error_code": 404,
    "error_msg": "organization Not Found"
}

用户参加的组织

//request: get user's organization
GET /users/:user_id/organizations HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
//response: show organizations list.
//NOTE front end should get organization img via oid
HTTP/1.1 200 OK
Content-Type: application/json
{
   "organizations": [
        {
            "organization_id": 123,
            "organization_name": "name",
            "status": "member"
        },
        {
            "organization_id": 124,
            "organization_name": "name2",
            "status": "creator"
        }
   ] 
}
    

任务系统

用户/组织创建任务

//request: user creating task 
POST /users/:user_id/tasks HTTP/1.1
//or request: organization creating task 
POST /users/:user_id/organizations/:organization_id/tasks HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: application/json
{
    "title": "string",
    "description": "string",
    "tags": ["tag1", "tag2", "tag3"],
    "participant_number_limit": 10,
    "reward_for_one_participant": 0,
    "post_time": "date_obj",
    "receive_end_time": "date_obj",
    "finish_deadline_time": "date_obj",
    "user_limit": {
        "age_upper": 0,
        "age_lower": 1,
        "grades": ["grade1", "grade1"],
        "sexes": ["sex_type1", "sex_type2", "sex_type3"],
        "schools": ["school_name1", "school_name2"]
    },
    "steps": [
        {
            "title": "string",
            "description": "string"
        },
        {
            "title": "string",
            "description": "string"
        }
    ]
}
//response: create task successfully, show created task
HTTP/1.1 201 Created
// NOTE would be better if return a list of users' name/nickname to avoid N+1 
// NOTE if create by person, OMIT creator_organization_name problem 
{
    "task_id": 123,
    "creator_user_id": 123,
    "creator_organization_id": 123,
    "status": "ongoing",
    "title": "string",
    "description": "string",
    "tags": ["tag1", "tag2", "tag3"],
    "participant_number_limit": 10,
    "reward_for_one_participant": 0,
    "post_time": "date_obj",
    "receive_end_time": "date_obj",
    "finish_deadline_time": "date_obj",
    "user_limit": {
        "age_upper": 0,
        "age_lower": 1,
        "grades": ["grade1", "grade1"],
        "sexes": ["sex_type1", "sex_type2", "sex_type3"],
        "schools": ["school_name1", "school_name2"]
    },
    "steps": [
        {
            "title": "string",
            "description": "string"
        },
        {
            "title": "string",
            "description": "string"
        }
    ]
}

//response: no this user/organizations in users/organizations
HTTP/1.1 404 Not Found
Content-Type: application/json
{
    "error_code": 404,
    "error_msg": "user/organization Not Found"
}

用户/组织查询自己创建的任务列表

//request: get user created tasks 
GET /users/:user_id/my_tasks HTTP/1.1
//or request: get organization created tasks 
GET /users/:user_id/organizations/:organization_id/my_tasks HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: application/json
//response: just a list of tasks brief info
HTTP/1.1 200 OK
Content-Type: application/json
{
    "tasks":[
        {
            "task_id": 123,
            "task_name": "name",
            "status": "status"
        },
        {
            "task_id": 124,
            "task_name": "name",
            "status": "status"
        }
    ]
}

查询自己的任务详情

//request: get user created tasks 
GET /users/:user_id/my_tasks/:tasks_id HTTP/1.1
//or request: get organization created tasks 
GET /users/:user_id/organizations/:organization_id/my_tasks/:tasks_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
//response: task's detail
HTTP/1.1 200 OK
Content-Type: application/json
{
    "task_id": 123456,
    "creator_user_email": "i@sirius.com",
    "creator_user_phone_number": "13123456789",
    "creator_organization_name": "name",
    "status": "ongoing",
    "title": "string",
    "description": "string",
    "tags": ["tag1", "tag2", "tag3"],
    "current_participant_number": 3,
    "participant_number_limit": 10,
    "reward_for_one_participant": 2,
    "post_time": "date_obj",
    "receive_end_time": "date_obj",
    "finish_deadline_time": "date_obj",
    "user_limit": {
        "age_upper": 0,
        "age_lower": 1,
        "grades": ["grade1", "grade1"],
        "sexes": ["sex_type1", "sex_type2", "sex_type3"],
        "schools": ["school_name1", "school_name2"]
    },
    "steps": [
        {
            "title": "string",
            "description": "string"
        },
        {
            "title": "string",
            "description": "string"
        }
    ],
    "participant_ids": [123, 124, 125, 126],
    "ongoing_participant_ids": [123, 124],
    "waiting_examine_participant_ids": [125],
    "finished_participant_ids": [126]
}

任务查询

//request: user query tasks
//NOTE never return all tasks in one query
//TODO maybe we can set an size and RETURN_SIZE(like 20), 
//each query only return size-RETURN_SIZE tasks.
GET /users/:user_id/tasks HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: application/json
{
    "size": 20,
    "creator_user_email": "i@sirius.com",
    "creator_user_phone_number": "13123456789",
    "creator_organization_name": "name",
    "status": "ongoing",
    "title": "sub_string",
    "tags": ["tag1", "tag2", "tag3"],
    "reward_for_one_participant_upper": 3,
    "reward_for_one_participant_lower": 1,
    "receive_end_time": "date_obj",
    "finish_deadline_time": "date_obj",
    "user_limit": {
        "age_upper": 0,
        "age_lower": 1,
        "grades": ["grade1", "grade1"],
        "sexes": ["sex_type1", "sex_type2", "sex_type3"],
        "schools": ["school_name1", "school_name2"]
    },
    "steps_number_upper": 5,
    "steps_number_lower": 1
}
// NOTE if user do not set a particular value of some key, 
// just OMIT the entire key-value pair, and send the rest.
// Let us see some examples.
// Example 1: query tasks from a org without any limits.
{
    "creator_organization_name": "name"
} 
// should return all tasks created by org with name:"name"  
// AND satisfied user limit of /users/:user_id

// Example 2: query tasks for girls(even if you are a boy(ew~))
{
    "user_limit": {
        "sexes": ["female"]
    } 
}
// should return all tasks with user_limit:sexes:girl
// THAT'S SAY, if query json contain "user_limit", 
// it will OVERRIDE user_limit inherit from /users/:user_id

// Example 3: query task with no more than 3 steps
{
    "steps_number_upper": 3
}
// should return all tasks with tasks:len(tasks)<=3
// THAT'S SAY, all bound(upper/lower) is INCLUDE,
// if only one bound is set, the return will be [-INF, bound] or [bound, +INF]
//response: show all queried tasks. 
// NOTE only show some of the json, not all of them.
HTTP/1.1 200 OK
Content-Type: application/json
{
    "tasks":[
        {
            "task_id": 123456,
            "creator_user_email": "i@sirius.com",
            "creator_user_phone_number": "13123456789",
            "creator_organization_name": "name",
            "status": "ongoing",
            "title": "string",
            "description": "string",
            "tags": ["tag1", "tag2", "tag3"],
            "current_participant_number": 3,
            "participant_number_limit": 10,
            "reward_for_one_participant": 2,
            "post_time": "date_obj",
            "receive_end_time": "date_obj",
            "finish_deadline_time": "date_obj",
            "user_limit": {
                "age_upper": 0,
                "age_lower": 1,
                "grades": ["grade1", "grade1"],
                "sexes": ["sex_type1", "sex_type2", "sex_type3"],
                "schools": ["school_name1", "school_name2"]
            },
            "steps": [
                {
                    "title": "string",
                    "description": "string"
                },
                {
                    "title": "string",
                    "description": "string"
                }
            ]
        },
    ]
}

任务详情

//request: detail of a tasks/:task_id
GET /users/:user_id/tasks/:task_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
//response: detail of that task
HTTP/1.1 200 OK
Content-Type: application/json
{
    "task_id": 123456,
    "creator_user_email": "i@sirius.com",
    "creator_user_phone_number": "13123456789",
    "creator_organization_name": "name",
    "status": "ongoing",
    "title": "string",
    "description": "string",
    "tags": ["tag1", "tag2", "tag3"],
    "current_participant_number": 3,
    "participant_number_limit": 10,
    "reward_for_one_participant": 2,
    "post_time": "date_obj",
    "receive_end_time": "date_obj",
    "finish_deadline_time": "date_obj",
    "user_limit": {
        "age_upper": 0,
        "age_lower": 1,
        "grades": ["grade1", "grade1"],
        "sexes": ["sex_type1", "sex_type2", "sex_type3"],
        "schools": ["school_name1", "school_name2"]
    },
    "steps": [
        {
            "title": "string",
            "description": "string"
        },
        {
            "title": "string",
            "description": "string"
        }
    ]
}

任务接受

//request: user accepting task 
POST /users/:user_id/tasks/:task_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
//response: accept task successfully, show updated task
HTTP/1.1 201 Created
//TODO return a updated task info

任务完成

//request: user finishing a step of task 
PUT /users/:user_id/tasks/:task_id/steps/:step_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
//response: finish step successfully, show updated task
HTTP/1.1 200 OK
//TODO return a updated task info

任务审核

//request: user finishing a step of task 
PUT /users/:user_id/tasks/:task_id/finishers/:user_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
//response: task finish accepted successfully
HTTP/1.1 200 OK
//TODO should return a new doing-er, done-er, finished-er list

撤回任务

//request: user change task status into pending
//NOTE only for ongoing tasks 
PUT /users/:user_id/tasks/:task_id HTTP/1.1
//or request: organization creating task 
PUT /users/:user_id/organizations/:organization_id/tasks/:task_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: application/json
{
    "status": "pending"
}

修改未发布任务

//request: user editing task
//NOTE only for not published(waiting/pending) tasks 
PUT /users/:user_id/tasks/:task_id HTTP/1.1
//or request: organization creating task 
PUT /users/:user_id/organizations/:organization_id/tasks/:task_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
Content-Type: application/json
//TODO the same json as create task

组织/个人删除任务

//request: delete tasks
DELETE /users/:user_id/tasks/:task_id HTTP/1.1
DELETE /users/:user_id/organizations/:organization_id/tasks/:task_id HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI
//TODO