# integration team questionnaire 2022 June
## overview
This exam contains following sections
* coding practice
* golang insight
* communicating technical issue
## coding practice
* extract and transform data is one of the foundation feature of API gateway.
* the coding practice is to write simple transformation to show your coding/design skills using golang
### sample json
```
{
"version": "1.0",
"rules": [
{
"resource": {
"path": "/api/data/documents"
},
"allowOrigins"["http://this.example.com","http://that.example.com"],
"allowMethods": [ "GET" ],
"allowCredentials": true
}
]
}
```
### expected result
* read json file with camel case key field and write out coverted key field name as snake_case
* using stand library only. don’t use any 3rd party library/framework
* allowed language: golang
:::success
```
type Rule struct {
Resource struct {
Path string `json:"path"`
} `json:"resource"`
AllowOrigins []string `json:"allowOrigins"`
AllowMethods []string `json:"allowMethods"`
AllowCredentials bool `json:"allowCredentials"`
}
type InputStruct struct {
Version string `json:"version"`
Rules []Rule `json:"rules"`
}
type NewRule struct {
Resource struct {
Path string `json:"path"`
} `json:"resource"`
AllowOrigins []string `json:"allow_origins"`
AllowMethods []string `json:"allow_methods"`
AllowCredentials bool `json:"allow_credentials"`
}
```
```
func main() {
//為了打印結果,在生產環境可直接將interface resposne給前端
log.Println(string(ResultStructTagsModify().([]byte)))
}
func ResultStructTagsModify() interface{} {
input := `{
"version": "1.0",
"rules": [
{
"resource": {"path": "/api/data/documents"},
"allowOrigins": [ "http://this.example.com", "http://that.example.com"],
"allowMethods": [ "GET" ],
"allowCredentials": true
}
]
}`
var inputData InputStruct
if err := json.Unmarshal([]byte(input), &inputData); err != nil {
log.Panic(err)
}
newRules := make([]NewRule, 0)
for _, rule := range inputData.Rules {
var newRule NewRule
newRule.Resource = rule.Resource
newRule.AllowOrigins = rule.AllowOrigins
newRule.AllowMethods = rule.AllowMethods
newRule.AllowCredentials = rule.AllowCredentials
newRules = append(newRules, newRule)
}
newStruct := struct {
Version string `json:"version"`
Rules []NewRule `json:"rules"`
}{
Version: inputData.Version,
Rules: newRules,
}
result, err := json.Marshal(newStruct)
if err != nil {
log.Panic(err)
}
return result
}
```
:::
### food for thought
* what will you do to handle generic/arbitrary json format?
:::success
<font color="black">使用interface{} type 或者以 reflect.typeOf() 來判斷型別</font>
:::
## golang insight
### OOP
```
// You can edit this code!
// Click here and start typing.
package main
import "fmt"
type data struct {
num int
key *string
items map[string]bool
}
func (this data) updateData(value int) {
this.num = value
*this.key = "updated"
this.items["updateData"] = true
}
func main() {
key := "first"
d := data{1, &key, make(map[string]bool)}
fmt.Printf("num=%v key=%v items=%v\n", d.num, *d.key, d.items)
d.updateData(8)
fmt.Printf("num=%v key=%v items=%v\n", d.num, *d.key, d.items)
}
```
* what would be the output?
:::success
```
num=1 key=first items=map[]
num=8 key=updated items=map[updateData:true]
```
:::
* what would you modify to make better result? why?
:::success
```
type data struct {
Num int
Key *string
Items map[string]bool
}
type IData interface {
InitData()
UpdateData()
}
func (r *data) InitData() {
fmt.Printf("num=%v key=%v items=%v\n", r.Num, &r.Key, r.Items)
}
func (r *data) UpdateData() {
fmt.Printf("num=%v key=%v items=%v\n", r.Num, &r.Key, r.Items)
}
func main() {
var d IData
// initial
key := `first`
d = &data{1, &key, map[string]bool{}}
d.InitData()
// update
key = "updated"
d = &data{
Num: 8,
Key: &key,
Items: map[string]bool{"updated": true},
}
d.UpdateData()
}
```
<font color="black">
將initial, update 改寫成物件形式,可以提升可讀性、及方便管理functions。
</font>
:::
### loop variable
```
func main() {
samples := []string{"cloud", "d2nova", "evox"}
for _, name := range samples {
go func() {
fmt.Println(name)
}()
}
// wait before exiting
time.Sleep(3 * time.Second)
}
```
* what would the possible output of this code snippet
:::success
<font color="black">
evox<br>evox<br>evox
</font>
:::
* what is the root cause/explanation the result? is that a bug or feature of golang?
:::success
<font color="black">
Race Condition<br>
執行過程中創建的goroutine同時對name做存取
</font>
:::
* what would you do to change the code for better result? why?
:::success
```
func main() {
var wg sync.WaitGroup
samples := []string{"cloud", "d2nova", "evox"}
for _, name := range samples {
wg.Add(1)
go func(n string) {
fmt.Println(n)
wg.Done()
}(name)
}
wg.Wait()
}
```
<font color='black'>
改以依序傳入name value,就可以避免race condition,
同時將time.sleep()改用waitGroup,資料量大時waitGroup能保證線程安全;
資料量小時,資料處理完成也不需等待time.sleep()結束。
</font>
---
```
結果:
cloud
evox
d2nova
```
:::
## written/oral communication
### oauth2
* what is oauth2? write down your understanding.
:::success
<font color="black">
可設有oauth server 獨立於主要的業務邏輯API之外,
對oauth server 發出請求可以得到包含access token, expired, scope 等資訊。<br>
接著clients 將access token攜帶於reqest中向主要的業務邏輯API發出請求。<br><br>
我的實際經驗也有使用過Google Oauth,係向google 驗證登入之email address是否為合法的,frontend可以取得一個token,將之傳遞給backend,由backend使用該token向google驗證並取回登入資訊。由backend使用該token向google驗證並取回登入資訊。
</font>
:::
* if need to explain to 3rd party developer to allow them to access your api, what will you do?
:::success
<font color="black">
可使用Swagger API格式或者使用類似hackmd或者Gitbook有支援markdown格式的編輯器撰寫API spec.
下例是曾經寫過的使用markdown撰寫的API spec
</font>
:::
### Register
:::info
POST v1/User/Register
>>
>>
|Body|Type|Description|Format|
|:--:|:--:|:---------:|:----:|
|Email*|String|信箱|x-www-form-urlencoded,JSON|
|Pwd*|String|密碼|x-www-form-urlencoded,JSON|
|Name*|String|真實姓名|x-www-form-urlencoded,JSON|
|NickName*|String|暱稱|x-www-form-urlencoded,JSON|
|Birthday|String|生日|x-www-form-urlencoded,JSON|
:::