1. if a then
  2. ngx.say("hello")
  3. end

You can simplify the operation by changing the tab to 4 spaces in the editor you are using.

Space

On both sides of the operator, you need to use a space to separate:

  1. --No
  2. local i=1
  3. local s = "apisix"
  1. --Yes
  2. local i = 1
  3. local s = "apisix"

Blank line

Many developers will add a semicolon at the end of the line:

  1. --No
  2. if a then
  3. ngx.say("hello");
  4. end;

Adding a semicolon will make the Lua code look ugly and unnecessary. Also, don’t want to save the number of lines in the code, the latter turns the multi-line code into one line in order to appear “simple”. This will not know when the positioning error is in the end of the code:

  1. --No
  2. if a then ngx.say("hello") end
  1. --Yes
  2. if a then
  3. ngx.say("hello")
  4. end

The functions needs to be separated by two blank lines:

  1. --No
  2. local function foo()
  3. end
  4. local function bar()
  5. end
  1. --Yes
  2. local function foo()
  3. end
  4. local function bar()
  5. end

If there are multiple if elseif branches, they need a blank line to separate them:

  1. --No
  2. if a == 1 then
  3. foo()
  4. elseif a== 2 then
  5. bar()
  6. elseif a == 3 then
  7. run()
  8. else
  9. error()
  10. end
  1. --Yes
  2. if a == 1 then
  3. foo()
  4. elseif a == 2 then
  5. bar()
  6. elseif a == 3 then
  7. run()
  8. else
  9. error()
  10. end

Each line cannot exceed 100 characters. If it exceeds, you need to wrap and align:

  1. --No
  2. return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst, conf.default_conn_delay)
  1. --Yes
  2. return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst,
  3. conf.default_conn_delay)

If it is a string stitching alignment, you need to put .. in the next line:

  1. return limit_conn_new("plugin-limit-conn" .. "plugin-limit-conn" ..
  2. "plugin-limit-conn")
  1. --Yes
  2. return "param1", "plugin-limit-conn"
  3. .. "plugin-limit-conn"

Variable

Local variables should always be used, not global variables:

  1. --No
  2. i = 1
  3. s = "apisix"
  1. local i = 1
  2. local s = "apisix"

Variable naming uses the snake_case style:

  1. --No
  2. local IndexArr = 1
  3. local str_Name = "apisix"
  1. --Yes
  2. local index_arr = 1
  3. local str_name = "apisix"

Use all capitalization for constants:

  1. --No
  2. local max_int = 65535
  3. local server_name = "apisix"
  1. --Yes
  2. local MAX_INT = 65535
  3. local SERVER_NAME = "apisix"

Table

Use table.new to pre-allocate the table:

  1. --No
  2. local t = {}
  3. for i = 1, 100 do
  4. t[i] = i
  5. end
  1. --Yes
  2. local new_tab = require "table.new"
  3. local t = new_tab(100, 0)
  4. for i = 1, 100 do
  5. t[i] = i
  6. end

Don’t use nil in an array:

  1. --No
  2. local t = {1, 2, nil, 3}

If you must use null values, use ngx.null to indicate:

  1. --Yes
  2. local t = {1, 2, ngx.null, 3}
  1. --No
  2. local s = ""
  3. for i = 1, 100000 do
  4. s = s .. "a"
  5. end
  1. --Yes
  2. local new_tab = require "table.new"
  3. local t = new_tab(100, 0)
  4. for i = 1, 100000 do
  5. t[i] = "a"
  6. end
  7. local s = table.concat(t, "")

Function

The naming of functions also follows snake_case:

  1. --Yes
  2. local function test_nginx()
  3. end

The function should return as early as possible:

  1. --No
  2. local function check(age, name)
  3. local ret = true
  4. if age < 20 then
  5. ret = false
  6. end
  7. if name == "a" then
  8. ret = false
  9. end
  10. -- do something else
  11. return ret
  12. end
  1. --Yes
  2. local function check(age, name)
  3. if age < 20 then
  4. end
  5. if name == "a" then
  6. end
  7. -- do something else
  8. return true
  9. end

The function should return <boolean>, err. The first return value means successful or not, if not, the second return value specifies the error message. The error message can be ignored in some case.

  1. --No
  2. local function check()
  3. return "failed"
  4. end
  1. --Yes
  2. local function check()
  3. return false, "failed"
  4. end

Module

All require libraries must be localized:

  1. --No
  2. local function foo()
  3. local ok, err = ngx.timer.at(delay, handler)
  4. end
  1. --Yes
  2. local timer_at = ngx.timer.at
  3. local function foo()
  4. local ok, err = timer_at(delay, handler)
  5. end

For style unification, require and ngx also need to be localized:

  1. --No
  2. local core = require("apisix.core")
  3. local timer_at = ngx.timer.at
  4. local function foo()
  5. local ok, err = timer_at(delay, handler)
  6. end
  1. --Yes
  2. local ngx = ngx
  3. local require = require
  4. local core = require("apisix.core")
  5. local timer_at = ngx.timer.at
  6. local function foo()
  7. local ok, err = timer_at(delay, handler)
  8. end

For functions that return with error information, the error information must be judged and processed:

  1. --No
  2. local sock = ngx.socket.tcp()
  3. local ok = sock:connect("www.google.com", 80)
  4. ngx.say("successfully connected to google!")
  1. --Yes
  2. local sock = ngx.socket.tcp()
  3. local ok, err = sock:connect("www.google.com", 80)
  4. if not ok then
  5. ngx.say("failed to connect to google: ", err)
  6. return
  7. end
  8. ngx.say("successfully connected to google!")

The function you wrote yourself, the error message is to be returned as a second parameter in the form of a string:

  1. --No
  2. local function foo()
  3. local ok, err = func()
  4. if not ok then
  5. return false
  6. end
  7. return true
  8. end
  1. --No
  2. local function foo()
  3. local ok, err = func()
  4. if not ok then
  5. return false, {msg = err}
  6. end
  7. return true