\chapter{API design}
Before we start to build UI, we have to design our API first.


\section{Verification}
\noindent This is a simple API for a potential user to know if it is a real user in the server. 

\begin{lstlisting}
@app.route('/api/v1/verify', methods=['POST'])
async def verify(request):
    data = request.json
    result = {"status": "wrong, you have to sign up or log in"}
    if data:
        username = data.get("username")
        temp_token = data.get("temp_token")
        if username and temp_token:
            the_user_we_found = users.find_one({"username": username, "temp_token": temp_token})
            if the_user_we_found != None:
                result["status"] = "ok"
    return response.json(result)
\end{lstlisting}

\noindent If our client get status with 'wrong', he may need to re-login 


\section{Get contacts}
\noindent We use this API to get a list of people that we can talk with.

\noindent The logic here is quite simple, we get all user's names in our server except the user who asks for this list.

\begin{lstlisting}
@app.route('/api/v1/contactlist', methods=['POST'])
async def get_contact_list(request):
    data = request.json
    result = {"status": "wrong"}
    if data:
        username = data.get("username")
        temp_token = data.get("temp_token")
        if username and temp_token:
            the_user_we_found = users.find_one({"username": username, "temp_token": temp_token})
            if the_user_we_found == None:
                result["status"] = "wrong: user doesn't exist"
            else:
                userlist = users.find({"_id": {"$nin": [the_user_we_found.get("_id")]}})
                #userlist = users.find({"username": {"$nin": [username]}})
                name_list = []
                for user in userlist:
                    name_list.append(user.get("username"))
                result["result"] = {"name_list": name_list}
                result["status"] = "ok"
    return response.json(result)
\end{lstlisting}

\section{Send Message}
We need to create an API to handle message sending.

\subsection{Step 1}
I would like to let this API to have 3 parameters: 
\begin{table}[h!]
\centering
\begin{tabular}{ll}
\hline
name & description \\ \hline
from & where this message comes from               \\ 
to   & where we need to send this message to       \\
text & what's the message you wanted me to deliver
\end{tabular}
\end{table}

Function that handles "/api/v1/send":
\begin{lstlisting}
     username = data.get("username")
     temp_token = data.get("temp_token")
     body = data.get("body")
     if username and temp_token and body:
         the_user_we_found = users.find_one({"username": username, "temp_token": temp_token})
         if the_user_we_found != None:
             from_ = username
             to = body.get("to")
             text = body.get("text")
             if to and text:
                 result["status"] = "ok"
                 update_an_conversation(from_, to, text)
\end{lstlisting}


\subsection{Step 2}
Also, we need to create a new data-structure for saving chat history.

If the from=a-user, to=b-user, the text="hi", the data structure would be:
\begin{lstlisting}
     [
         {
             "conversation_name": "a-user_b-user",
             "history": [
                 {
                     "date": "2020.3.29",
                     "from": "a-user",
                     "to": "b-user",
                     "text": "hi",
                 },
             ]
         }
     ]
\end{lstlisting}

In this way, we could get a series of chat histories based on two clients' names, dates.

With this information, building a chat view won't be difficult.

Here are the functions that handle this processing:
\begin{lstlisting}
     def update_an_conversation(from_, to_, text):
         date = datetime.datetime.utcnow()
         conversation_name = "_".join(list(sorted([from_, to_])))
         conversation = conversations.find_one({"conversation_name": conversation_name})
         if conversation == None:
             create_an_conversation(from_, to_, text, date)
         else:
             conversations.find_one_and_update({"_id": conversation.get("_id")}, {
                 "$addToSet": {
                     "history": {
                         "date": date,
                         "from": from_,
                         "to": to_,
                         "text": text,
                     }
                 }
             })
     
     def create_an_conversation(from_, to_, text, date):
         conversation_name = "_".join(list(sorted([from_, to_])))
         conversation = {
             "conversation_name": conversation_name,
             "history": [
                 {
                     "date": date,
                     "from": from_,
                     "to": to_,
                     "text": text,
                 }
             ]
         }
         conversations.insert_one(conversation)
\end{lstlisting}



\section{Receive Message}
We need to define an API to allow users to get their chat history.

By analyzing chat history, the user could also know whether they got new messages from others.

It's quite simple for the client because if new chat history is different than old chat history, it means it got new messages.

\subsection{Step 1}
I would like to let this API to have 1 parameter: target

When the target == “an empty string”, we return all chat history related to this user.

When the target == "another-user", we return only the chat history happened between another-user and this user.

Hers is the code:
\begin{lstlisting}
    target = body.get("target")
    if target == "" or target:
        got = get_conversation(username, target)
        if got == None:
            result["status"] = f"wrong: no record with {username}_{target}"
        else:
            result["status"] = "ok"
            result["result"] = got
\end{lstlisting}

\subsection{Step 2}
This process is all about finding the history chat record related to the user that requires this.

If the user has provided a target-user, we could get a unique string representing one of the conversations that stores in our database. 

Or, if the user didn't provide us a specific target-user, we can still use a regular expression to get all conversations that include this user.

Here is the code:
\begin{lstlisting}
    def get_conversation(username, target):
        data = None
        if target == "" or target:
            if target != "":
                conversation_name = "_".join(list(sorted([username, target])))
                conversation = conversations.find_one({"conversation_name": conversation_name})
                if conversation != None:
                    data = [conversation]
    
            else:
                regex = "(" + username+"_.*)|(.*_"+username+")"
                many_conversations = conversations.find({"conversation_name": {"$regex": regex}})
                if many_conversations != None:
                    result = []
                    for conversation in many_conversations:
                        result.append(conversation)
                    data = result
        return data
\end{lstlisting}