RESTFul API 的 mock server 解決方案

會寫這一篇主要是最近在公司上有遇到我們需要快速迭代與試錯,但在前後端是不一樣的團隊,但在快速迭代的情況下,為了避免不要互相影嚮進度,一個常見的作法就是架設json mock server,也就是設定對應的api 只回應對應的假資料…

這類型的工具也很多,只是最近剛好摸到一個工具覺得是我目前碰過的類似工具之中,最容易上手的,而且可以有GUI可以使用…

Mockoon

這個工具與其它類似工具的主要差異是,它有GUI界面,可以直接在界面上設定要開哪些endpoint與對應的response以後,就可以直接在local 端跑起mock server了。

而且GUI 界面類似於 Postman,所以上手難度很低,稍微摸一下界面就知道它可以做哪些工具了…

Mockoon routes view
reference: https://mockoon.com/docs/latest/gui-cheat-sheet/

其它更多好用的功能像是

  • Proxy configurations

這個是當api request 打進時,mockoon上如果有沒設定的endpoint時,可以指定它轉發到特定的機器。

  • Support openapi/swagger config import

這個顧名思義是可以直接把我們寫的api 文件檔直接丟到mockoon上,這樣對應的endpoints 就被設定好了。

  • Rule based responses

這我覺得也算是蠻客製化的功能,我們可以針對一個endpoint設定多個responses,然後透過一些客製化的規則(rules)來設定mockoon 要回哪個response。

  • Support CLI based runtime

除了gui 界面以外,官方也有支援cli (用npm包的),所以我們可以把local端的mockoon設定檔丟到cloud上的機器,然後就可以在機器上用cli跑起一個對應的mock server。

像是下面一個簡單的 restart.sh 就可以讓重啟linux 上的mockcoon 並且讀取對應的設定檔。

!/bin/bash
 pkill -f "mockoon-cli"
 mockoon-cli start --data mockoon_api_config.json -p 9000 > /dev/null 2>&1 &

Javascript中的位移符號

剛好在寫LeetCode 190, 191時遇到要如何處理正負數的位移問題,因為題目要求的是傳入的值會是一個32bits長度的數,但是在javascript 中這就可能會是個正整數或負整數,所以需要的處理方式不一樣…

大概問了下gpt主要在js中有三種位移符號

  1. 左移運算符 (<<):這個運算符將數字的二進位表示向左移動指定的位數。左移後,右邊空出的位將被0填充。這是有符號左移,會考慮符號位。

假設我們有一個正整數 x = 5,在二進制中表示為 0000 0000 0000 0000 0000 0000 0000 0101

我們對 x 執行左移1位的操作 (x << 1),結果會是:

x << 10000 0000 0000 0000 0000 0000 0000 1010

在十進制中,這個數字是10(5的兩倍)。左移一位基本上等於乘以2。

  1. 帶符號右移運算符 (>>):這個運算符將數字的二進位表示向右移動指定的位數。右移後,左邊空出的位將由原來的符號位(即最左邊的位)填充。這允許負數在右移後保持為負數。

假設我們有一個負整數 y = -5,它在32位二進制補碼中的表示為 1111 1111 1111 1111 1111 1111 1111 1011

進行 y << 1 操作,結果會是:

y << 11111 1111 1111 1111 1111 1111 1111 0110

在十進制中,這個數字是-10。類似於正數的情況,左移一位相當於乘以2,但符號保持不變。

  1. 無符號右移運算符 (>>>):這個運算符也將數字的二進位表示向右移動,但移動後左邊空出的位將被0填充,不考慮符號位。這意味著結果總是非負的。

假設我們有一個負整數 y = -8,它在32位二進制補碼中的表示為 1111 1111 1111 1111 1111 1111 1111 1000

進行 y >>> 1 操作,結果會是:

y >>> 10111 1111 1111 1111 1111 1111 1111 1100

在十進制中,這個數字是非常大的,因為無符號右移將負數轉換為正數。這個具體數值是2147483644(2^31-4)

這些例子展示了無符號右移運算符在正數和負數上的作用。對於正數,無符號右移一位與普通右移(帶符號)沒有區別,都相當於將數字除以2。

然而,對於負數,無符號右移會產生顯著不同的結果。由於無符號右移不考慮數字的符號位,它將原始數字視為一個非常大的正數,然後進行位移。這導致負數在經過無符號右移後變成一個非常大的正數。

結論:

在js中如果要處理unsighted intger的相關需求時,會有需要用到 >>> 符號,具體的使用方式如下:

  • 透過 value >>> 0 可以將value轉成正整數。
  • 如果 value 轉成 unsighted int 是一個大於 1<<31-1的正數,則如果要用右移運算符時,則第一次右移需要使用(>>>)運算符,之後就可以使用 (>>)右移運算符。
    (如果 value 在這時用的是 >> 運算符的話,則代表在使用完以後,還是會保留最左邊的1 bit以為持此數的正負號)

透過ChatGPT 來對網頁做總結

剛在看最近的HackerDailyNews時,剛好看到一篇文章為 Why Take a Compiler Course? ,文章的內容本身不長, 剛好想說這種東西好像蠻適合叫GPT來幫我做個總結…

大概找了一下,看到這個 ChatGPT – Summarize everything! – Chrome Web Store (google.com),也適用了一下,感覺真的蠻不錯的XDDDD

以下是GPT給的總結:

Summary

Learning about compilers and their components has broad practical use for serious programmers. Even if you don’t plan on writing a compiler, understanding parsers and interpreters is important as we end up writing them all the time. Knowing the details of a language can help you write better, faster, and more correct code. Understanding the optimization capabilities and limitations of a compiler can help you work more effectively with it.

  • 🤔 Serious programmers need to understand parsers and interpreters, which are used frequently in extensible programs and dealing with new input files.
  • 💻 Understanding a language’s corner cases and complexities can help write better, faster, and more correct code.
  • 🚀 Knowing what optimizations are in-scope for a compiler can help programmers work more effectively with it.
  • 🤝 Cooperation with a compiler can lead to faster code, while fighting against it can lead to premature optimization and other tricks.
  • 💬 Compiler backends can help gain a better understanding of computer architectures.
  • 💡 There are three main components of a compiler: the frontend, middle end, and backend, all of which have value to understand.
  • 📚 Learning about compilers can bring together theoretical and practical knowledge that can be applied to daily little languages.

看來總結的蠻不錯的,以後很適合我快速掃文章重點XDDDD

VSCode 中編寫Markdown table 的plugin

每次要寫Markdwon 時, 總覺得最麻煩的就是要編輯table, 只要欄位中的字串長度改變, 每次都要在調整相對應的欄位邊界很久…

剛好在Vscode上發現這個Markdown Table plugin 這個好物, 真是不錯, 每次有table欄位值變更時, 只需要無腦的按 Tab鍵即可!!!

真是幫我省下不少時間阿XDDDDD

Reference:

TrinoDB cli 中將query 結果輸出成csv 的方式

剛好工作上用到,記錄一下…. 這樣以後再用到時就只要稍微改一下相關的參數就好了XD

trino --server localhost:8080 \
 --user george \
 --execute 'SELECT * FROM A as a
  LEFT JOIN b ON a.id = b.id
  WHERE a.id > 0' \
 --output-format CSV > ~/workspace/mds_object.csv

Reference:

Google 的新程式語言Carbon

Google 最近發表了新的程式語言 Carbon, 其主要的目的是用來作為C++的後繼語言;從目前的資訊可以知道,它的角色比較像是 Kotlin 之於 Java, 除了強調現代化的編程方式以外,且能夠繼續支援舊有的C++程式庫(這點其實蠻吸引人的XD)。

通常看到C++程式語言的繼任者,現在大概都會想到Rust吧,但其實定位不太一樣…

Rust 在設計之初主要是作為更安全的系統語言為出發點而設計的,所以它並不相容於既有的C++程式,所以對於已經有許多C++ 程式的組織而言,使用Rust 就相當於要改寫許多內部的程式…

Carbon在這邊則採用類似於Kotlin的模式,新的語法但又可與公司現有的C++程式一起編譯的特性,想必正式GA之後應該可以有不錯的發展…

Reference:

如何寫好Logs

寫好Log對我而言一直是一項重要的技能, 因為它可以讓問題發生時, 讓開發者用最短的時間找到並解決問題… 剛好在Hacker News上看到這篇 Logging in Python like a PRO , 順便紀錄一下這位作者的一些觀點…

好的Log所需具備的特性

* Descriptive
* Contextual
* Reactive

They’re descriptive in the sense that they give you a piece of information, they’re contextual because they give you an overview of the state of things at the moment, and finally, they’re reactive because they allow you to take action only after something happened (even though your logs are sent/consumed real-time, there’s not really something you can do to change what just happened).

https://guicommits.com/how-to-log-in-python-like-a-pro/

簡單來說如果一段log可以具備上述三個特性, 作者就認為可以讓log的讀者能夠更輕鬆的定位問題的發生點, 以及相對應的事件背景 !

Log 的時機點

As a rule of thumb consider logging:

* At the start of relevant operations or flows (e.g. Connection to third-party, etc);

* At any relevant progress (e.g. Authentication successful, got a valid response code, etc);

* At the conclusion of an operation (e.g. EITHER succeeded or failed);

https://guicommits.com/how-to-log-in-python-like-a-pro/

至於說何時要寫Log呢? 作者這邊指出事件的起始點, 相關的處理進度發生時, 以及事件處理完成時都是適合Log的時間點 !!!

Python 下的Logging的一些範例設定

Python上的一些Log設定我就不太熟了, 先紀錄一下之後可以看看….

總結

這篇文章算是簡單的提要了寫Log時的一些大方向, 這樣之後要寫也蠻適合當參考…

Reference:

透過Dehydrated來設定Let’s encrypt

之前是使用Certbot來更新我這個網誌的Let’s encrypt certificate,運作上也還算正常,但自動更新cert這邊常常更新不了(這部分感覺應該是我設定上的問題)…

後來在公司上, DK有提到了dehydrated這個輕量化的Let’s enrypt 設定工具,實際上去快速看了一下它的repoistory以後,真的覺得對於一般的Linux 環境使用上蠻友善的(因為它所需要的工具通常都是Linux 系統預設的工具)。

快速掃完以後,直接進入正題關於設定上的相關指令… (這邊直接參考 DK 的 wiki上的設定)

安裝Dehydrated

# using a temporary directory to download the dehydrated
cd ~/tmp
wget "https://raw.githubusercontent.com/dehydrated-io/dehydrated/master/dehydrated"
chmod +x dehydrated
sudo mv dehydrated /usr/local/bin/

Dehydrated環境設定

# create directories that dehydrated will need
sudo mkdir -p /etc/dehydrated /var/www/dehydrated

#change to the dehydrated dir
cd /etc/dehydrated

# setup the config
echo 'OCSP_MUST_STAPLE=yes' | sudo tee -a config
echo 'KEYSIZE=2048' | sudo tee -a config
echo 'WELLKNOWN=/var/www/dehydrated' | sudo tee -a config

# setup the domain file
echo 'blog.gechen.org' | sudo tee -a domains.txt
 

設定Nginx

這邊的範例主要是透過Nginx來當做之後dehydrated 執行時,用來回應Let’s encrypt 的challenge…

下面就直接貼Nginx 的對應domain的範例設定檔

server {
     listen 80;
     server_name blog.gechen.org;
     rewrite ^(.*) https://$host$1 permanent;
 }

server {
     listen 443 ssl;
     server_name blog.gechen.org;
     
     index index.php;
     ssl_certificate /etc/dehydrated/certs/blog.gechen.org/fullchain.pem;
     ssl_certificate_key /etc/dehydrated/certs/blog.gechen.org/privkey.pem;


     # ... skip some configs

   
     # this part is for dehydrated
     location /.well-known/acme-challenge/ {
        alias /var/www/dehydrated;
     }
 }

執行Dehydrated 來更新Let’s encrypt certs

如果是第一次使用 dehydrated 則要額外執行下面指令

sudo dehydrated --register --accept-terms

透過下面的指令來做Let’s encrypt certificate的申請/更新

# the following command will apply/renew certificates for the domains in file: /etc/dehydrated/domains.txt
sudo dehydrated -c

# or we can also directly use command below to apply for specific domain certificate
sudo dehydrated -c -d blog.gechen.org

設定自動更新certificate的cron jobs

這邊直接引用DK 大大的wiki範例來設定 weekly 的憑證更新…

echo -e '#!/bin/bash\nexport PATH=/usr/sbin:/usr/bin:/bin:"${PATH}"\nsleep $(expr $(printf "%d" "0x$(hostname | md5sum | cut -c 1-8)") % 86400); dehydrated -c && ( service nginx reload )' | sudo tee /etc/cron.weekly/dehydrated; sudo chmod 755 /etc/cron.weekly/dehydrated 

References:

透過jq 將json檔案格式輸出成 env格式

剛好工作上有這個需求, 就順便找了一下看 jq 指令是否可以簡單的做到這件事…

測試了下面的指令以後, 看起來真的是頗好用, 一行指令就可以把 json 轉成 env 了!

cat example.json| jq -r 'to_entries[] | [.key,.value] | join("=")' > example.env

Reference:

透過SQLite3 來用一指令實現SQL讀取CSV檔

看到DK的文章上提到這個功能覺得也太有趣了, 沒想到會有這麼簡單方式來從CSV檔中讀取想要的內容…

使用方式

將sqlite3 透過memory的方式讀取了以後, 就可以透過SQL來找到其中想要的內容了…

sqlite3 :memory: -cmd '.mode csv' -cmd '.import mds_content_status.csv temp' -cmd '.mode column' 'SELECT * FROM temp'

為了讓使用方式更方便, 還可以在.bashrc.zshrc中把上面的cli 指令包裝成 shell function 如下:

function query_csv() {
    local CSV_FILE=$1
    local TABLE=$2
    local QUERY=$3

    sqlite3 :memory: -cmd '.headers on' -cmd '.mode csv' -cmd ".import ${CSV_FILE} ${TABLE}" -cmd '.mode column' "${QUERY}"
}

然後我們就可以用下面的方式去query了…

query_csv users.csv user_table 'SELECT id, name FROM user_table where id=17807'

reference