# Scene Examples

The Feishu Open Platform, based on the SDK, encapsulates commonly used API combinations and business scenario examples for your reference.

- The [oapi-sdk-go-demo](https://github.com/larksuite/oapi-sdk-go-demo) includes various scenario example codes, such as:

- [Send File Message](https://github.com/larksuite/oapi-sdk-go-demo/blob/main/composite_api/im/send_file.go)

```go
      /*
       Send file message, using two OpenAPIs:
       1. [Upload File](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/file/create)
       2. [Send Message](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message/create)
      */

package im

import (
              "context"
              "encoding/json"
              "fmt"
              "io"

"github.com/larksuite/oapi-sdk-go/v3"
              larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
              "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
      )

type SendFileRequest struct {
              FileType      string
              FileName      string
              File          io.Reader
              Duration      int
              ReceiveIdType string
              ReceiveId     string
              Uuid          string
      }

type SendFileResponse struct {
              *larkcore.CodeError
              CreateFileResponse    *larkim.CreateFileRespData
              CreateMessageResponse *larkim.CreateMessageRespData
      }

// SendFile sends a file message
      func SendFile(client *lark.Client, request *SendFileRequest) (*SendFileResponse, error) {
              // Upload file
              createFileReq := larkim.NewCreateFileReqBuilder().
                      Body(larkim.NewCreateFileReqBodyBuilder().
                              FileType(request.FileType).
                              FileName(request.FileName).
                              Duration(request.Duration).
                              File(request.File).
                              Build()).
                      Build()
              createFileResp, err := client.Im.File.Create(context.Background(), createFileReq)
              if err != nil {
                      return nil, err
              }
              if !createFileResp.Success() {
                      fmt.Printf("client.Im.File.Create failed, code: %d, msg: %s, log_id: %s\n",
                              createFileResp.Code, createFileResp.Msg, createFileResp.RequestId())
                      return nil, createFileResp.CodeError
              }

// Send message
              bs, err := json.Marshal(createFileResp.Data)
              if err != nil {
                      return nil, err
              }
              createMessageReq := larkim.NewCreateMessageReqBuilder().
                      ReceiveIdType(request.ReceiveIdType).
                      Body(larkim.NewCreateMessageReqBodyBuilder().
                              ReceiveId(request.ReceiveId).
                              MsgType("file").
                              Content(string(bs)).
                              Uuid(request.Uuid).
                              Build()).
                      Build()

createMessageResp, err := client.Im.Message.Create(context.Background(), createMessageReq)
              if err != nil {
                      return nil, err
              }
              if !createMessageResp.Success() {
                      fmt.Printf("client.Im.Message.Create failed, code: %d, msg: %s, log_id: %s\n",
                              createMessageResp.Code, createMessageResp.Msg, createMessageResp.RequestId())
                      return nil, createMessageResp.CodeError
              }

// Return result
              return &SendFileResponse{
                      CodeError: &larkcore.CodeError{
                              Code: 0,
                              Msg:  "success",
                      },
                      CreateFileResponse:    createFileResp.Data,
                      CreateMessageResponse: createMessageResp.Data,
              }, nil
      }
      ```

- [Send Image Message](https://github.com/larksuite/oapi-sdk-go-demo/blob/main/composite_api/im/send_image.go)

```go
    /*
     Send image message, using two OpenAPIs:
     1. [Upload Image](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/image/create)
     2. [Send Message](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message/create)
    */

package im

import (
            "context"
            "encoding/json"
            "fmt"
            "io"

"github.com/larksuite/oapi-sdk-go/v3"
            larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
            "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
    )

type SendImageRequest struct {
            Image         io.Reader
            ReceiveIdType string
            ReceiveId     string
            Uuid          string
    }

type SendImageResponse struct {
            *larkcore.CodeError
            CreateImageResponse   *larkim.CreateImageRespData
            CreateMessageResponse *larkim.CreateMessageRespData
    }

// SendImage sends an image message
    func SendImage(client *lark.Client, request *SendImageRequest) (*SendImageResponse, error) {
            // Upload image
            createImageReq := larkim.NewCreateImageReqBuilder().
                    Body(larkim.NewCreateImageReqBodyBuilder().
                            ImageType("message").
                            Image(request.Image).
                            Build()).
                    Build()
            createImageResp, err := client.Im.Image.Create(context.Background(), createImageReq)
            if err != nil {
                    return nil, err
            }
            if !createImageResp.Success() {
                    fmt.Printf("client.Im.Image.Create failed, code: %d, msg: %s, log_id: %s\n",
                            createImageResp.Code, createImageResp.Msg, createImageResp.RequestId())
                    return nil, createImageResp.CodeError
            }

// Send message
            bs, err := json.Marshal(createImageResp.Data)
            if err != nil {
                    return nil, err
            }
            createMessageReq := larkim.NewCreateMessageReqBuilder().
                    ReceiveIdType(request.ReceiveIdType).
                    Body(larkim.NewCreateMessageReqBodyBuilder().
                            ReceiveId(request.ReceiveId).
                            MsgType("image").
                            Content(string(bs)).
                            Uuid(request.Uuid).
                            Build()).
                    Build()

createMessageResp, err := client.Im.Message.Create(context.Background(), createMessageReq)
            if err != nil {
                    return nil, err
            }
            if !createMessageResp.Success() {
                    fmt.Printf("client.Im.Message.Create failed, code: %d, msg: %s, log_id: %s\n",
                            createMessageResp.Code, createMessageResp.Msg, createMessageResp.RequestId())
                    return nil, createMessageResp.CodeError
            }

// Return result
            return &SendImageResponse{
                    CodeError: &larkcore.CodeError{
                            Code: 0,
                            Msg:  "success",
                    },
                    CreateImageResponse:   createImageResp.Data,
                    CreateMessageResponse: createMessageResp.Data,
            }, nil
    }
    ```

- [Get All Users in a Department](https://github.com/larksuite/oapi-sdk-go-demo/blob/main/composite_api/contact/list_user_by_department.go)

```go
      /*
       Get all users in a department, using two OpenAPIs:
       1. [Get Sub-department List](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/contact-v3/department/children)
       2. [Get Department Direct Users](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/contact-v3/user/find_by_department)
      */

package contact

import (
              "context"
              "fmt"

lark "github.com/larksuite/oapi-sdk-go/v3"
              larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
              larkcontact "github.com/larksuite/oapi-sdk-go/v3/service/contact/v3"
      )

type ListUserByDepartmentRequest struct {
              DepartmentId string
      }

type ListUserByDepartmentResponse struct {
              *larkcore.CodeError
              ChildrenDepartmentResponse   *larkcontact.ChildrenDepartmentRespData
              FindByDepartmentUserResponse []*larkcontact.User
      }

// ListUserByDepartment retrieves all users under a department
      func ListUserByDepartment(client *lark.Client, request *ListUserByDepartmentRequest) (*ListUserByDepartmentResponse, error) {
              // Get sub-department list
              childrenDepartmentReq := larkcontact.NewChildrenDepartmentReqBuilder().
                      DepartmentIdType("open_department_id").
                      DepartmentId(request.DepartmentId).
                      Build()

childrenDepartmentResp, err := client.Contact.Department.Children(context.Background(), childrenDepartmentReq)

if err != nil {
                      return nil, err
              }
              if !childrenDepartmentResp.Success() {
                      fmt.Printf("client.Contact.Department.Children failed, code: %d, msg: %s, log_id: %s\n",
                              childrenDepartmentResp.Code, childrenDepartmentResp.Msg, childrenDepartmentResp.RequestId())
                      return nil, childrenDepartmentResp.CodeError
              }

// Get direct users of the department
              users := make([]*larkcontact.User, 0)
              openDepartmentIds := []string{request.DepartmentId}
              for _, item := range childrenDepartmentResp.Data.Items {
                      openDepartmentIds = append(openDepartmentIds, *item.OpenDepartmentId)
              }

for _, id := range openDepartmentIds {
                      findByDepartmentUserReq := larkcontact.NewFindByDepartmentUserReqBuilder().
                              DepartmentId(id).
                              Build()

findByDepartmentUserResp, err := client.Contact.User.FindByDepartment(context.Background(), findByDepartmentUserReq)

if err != nil {
                              return nil, err
                      }
                      if !findByDepartmentUserResp.Success() {
                              fmt.Printf("client.Contact.User.FindByDepartment failed, code: %d, msg: %s, log_id: %s\n",
                                      findByDepartmentUserResp.Code, findByDepartmentUserResp.Msg, findByDepartmentUserResp.RequestId())
                              return nil, findByDepartmentUserResp.CodeError
                      }

users = append(users, findByDepartmentUserResp.Data.Items...)
              }

// Return result
              return &ListUserByDepartmentResponse{
                      CodeError: &larkcore.CodeError{
                              Code: 0,
                              Msg:  "success",
                      },
                      ChildrenDepartmentResponse:   childrenDepartmentResp.Data,
                      FindByDepartmentUserResponse: users,
              }, nil
      }
      ```

- [Create a Multi-Dimensional Table and Add Data Tables](https://github.com/larksuite/oapi-sdk-go-demo/blob/main/composite_api/base/create_app_and_tables.go)

```go
/*
 Create a multi-dimensional table and add data tables, using two OpenAPIs:
 1. [Create a Multi-Dimensional Table](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app/create)
 2. [Add a Data Table](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/bitable-v1/app-table/create)
*/

package base

import (
    "context"
    "fmt"

lark "github.com/larksuite/oapi-sdk-go/v3"
    larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
    larkbitable "github.com/larksuite/oapi-sdk-go/v3/service/bitable/v1"
)

type CreateAppAndTablesRequest struct {
    Name        string
    FolderToken string
    Tables      []*larkbitable.ReqTable
}

type CreateAppAndTablesResponse struct {
    *larkcore.CodeError
    CreateAppResponse       *larkbitable.CreateAppRespData
    CreateAppTablesResponse []*larkbitable.CreateAppTableRespData
}

// CreateAppAndTables creates a multi-dimensional table and adds data tables
func CreateAppAndTables(client *lark.Client, request *CreateAppAndTablesRequest) (*CreateAppAndTablesResponse, error) {
    // Create a multi-dimensional table
    createAppReq := larkbitable.NewCreateAppReqBuilder().
        ReqApp(larkbitable.NewReqAppBuilder().
            Name(request.Name).
            FolderToken(request.FolderToken).
            Build()).
        Build()

createAppResp, err := client.Bitable.App.Create(context.Background(), createAppReq)
    if err != nil {
        return nil, err
    }
    if !createAppResp.Success() {
        fmt.Printf("client.Bitable.App.Create failed, code: %d, msg: %s, log_id: %s\n",
            createAppResp.Code, createAppResp.Msg, createAppResp.RequestId())
        return nil, createAppResp.CodeError
    }

// Add data tables
    tables := make([]*larkbitable.CreateAppTableRespData, 0)
    for _, table := range request.Tables {
        req := larkbitable.NewCreateAppTableReqBuilder().
            AppToken(*createAppResp.Data.App.AppToken).
            Body(larkbitable.NewCreateAppTableReqBodyBuilder().
                Table(table).
                Build()).
            Build()

createAppTableResp, err := client.Bitable.AppTable.Create(context.Background(), req)
        if err != nil {
            return nil, err
        }
        if !createAppTableResp.Success() {
            fmt.Printf("client.Bitable.AppTable.Create failed, code: %d, msg: %s, log_id: %s\n",
                createAppTableResp.Code, createAppTableResp.Msg, createAppTableResp.RequestId())
            return nil, createAppTableResp.CodeError
        }

tables = append(tables, createAppTableResp.Data)
    }

// Return the result
    return &CreateAppAndTablesResponse{
        CodeError: &larkcore.CodeError{
            Code: 0,
            Msg:  "success",
        },
        CreateAppResponse:       createAppResp.Data,
        CreateAppTablesResponse: tables,
    }, nil
}
```

- [Copy and Paste Cell Data from a Specific Range](https://github.com/larksuite/oapi-sdk-go-demo/blob/main/composite_api/sheets/copy_and_paste_by_range.go)

```go
/*
 Copy and paste cell data from a specific range, using two OpenAPIs:
 1. [Read a Single Range](https://open.feishu.cn/document/ukTMukTMukTM/ugTMzUjL4EzM14COxMTN)
 2. [Write Data to a Single Range](https://open.feishu.cn/document/ukTMukTMukTM/uAjMzUjLwIzM14CMyMTN)
*/

package sheets

import (
    "context"
    "encoding/json"
    "fmt"
    "net/http"

lark "github.com/larksuite/oapi-sdk-go/v3"
    larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
)

type CopyAndPasteByRangeRequest struct {
    SpreadsheetToken string
    SrcRange         string
    DstRange         string
}

type CopyAndPasteRangeResponse struct {
    *larkcore.CodeError
    ReadResponse  *SpreadsheetRespData
    WriteResponse *SpreadsheetRespData
}

// CopyAndPasteRange copies and pastes cell data from a specified range
func CopyAndPasteRange(client *lark.Client, request *CopyAndPasteByRangeRequest) (*CopyAndPasteRangeResponse, error) {
    // Read a single range
    readResp, err := client.Do(context.Background(), &larkcore.ApiReq{
        HttpMethod:                http.MethodGet,
        ApiPath:                   fmt.Sprintf("/open-apis/sheets/v2/spreadsheets/%s/values/%s", request.SpreadsheetToken, request.SrcRange),
        SupportedAccessTokenTypes: []larkcore.AccessTokenType{larkcore.AccessTokenTypeTenant},
    })
    if err != nil {
        return nil, err
    }

readSpreadsheetResp := &SpreadsheetResp{}
    err = json.Unmarshal(readResp.RawBody, readSpreadsheetResp)
    if err != nil {
        return nil, err
    }
    readSpreadsheetResp.ApiResp = readResp
    if readSpreadsheetResp.Code != 0 {
        fmt.Printf("read spreadsheet failed, code: %d, msg: %s, log_id: %s\n",
            readSpreadsheetResp.Code, readSpreadsheetResp.Msg, readSpreadsheetResp.RequestId())
        return nil, readSpreadsheetResp.CodeError
    }

// Write data to a single range
    valueRange := map[string]interface{}{}
    valueRange["range"] = request.DstRange
    valueRange["values"] = readSpreadsheetResp.Data.ValueRange.Values
    body := map[string]interface{}{}
    body["valueRange"] = valueRange

writeResp, err := client.Do(context.Background(), &larkcore.ApiReq{
        HttpMethod:                http.MethodPut,
        ApiPath:                   fmt.Sprintf("/open-apis/sheets/v2/spreadsheets/%s/values", request.SpreadsheetToken),
        Body:                      body,
        SupportedAccessTokenTypes: []larkcore.AccessTokenType{larkcore.AccessTokenTypeTenant},
    })
    if err != nil {
        return nil, err
    }

writeSpreadsheetResp := &SpreadsheetResp{}
    err = json.Unmarshal(writeResp.RawBody, writeSpreadsheetResp)
    if err != nil {
        return nil, err
    }
    writeSpreadsheetResp.ApiResp = writeResp
    if writeSpreadsheetResp.Code != 0 {
        fmt.Printf("write spreadsheet failed, code: %d, msg: %s, log_id: %s\n",
            writeSpreadsheetResp.Code, writeSpreadsheetResp.Msg, writeSpreadsheetResp.RequestId())
        return nil, writeSpreadsheetResp.CodeError
    }

// Return the result
    return &CopyAndPasteRangeResponse{
        CodeError: &larkcore.CodeError{
            Code: 0,
            Msg:  "success",
        },
        ReadResponse:  readSpreadsheetResp.Data,
        WriteResponse: writeSpreadsheetResp.Data,
    }, nil
}
```

- [Download All Media Files in a Specific Range of Cells](https://github.com/larksuite/oapi-sdk-go-demo/blob/main/composite_api/sheets/download_media_by_range.go)

```go
/*
 Download all media files in a specific range of cells, using two OpenAPIs:
 1. [Read a Single Range](https://open.feishu.cn/document/ukTMukTMukTM/ugTMzUjL4EzM14COxMTN)
 2. [Download Media](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/drive-v1/media/download)
*/

package sheets

import (
    "context"
    "encoding/json"
    "fmt"
    "net/http"
    "reflect"

lark "github.com/larksuite/oapi-sdk-go/v3"
    larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
    larkdrive "github.com/larksuite/oapi-sdk-go/v3/service/drive/v1"
)

type DownloadMediaByRangeRequest struct {
    SpreadsheetToken string
    Range            string
}

type DownloadMediaByRangeResponse struct {
    *larkcore.CodeError
    ReadResponse          *SpreadsheetRespData
    DownloadMediaResponse []*larkdrive.DownloadMediaResp
}

func DownloadMediaByRange(client *lark.Client, request *DownloadMediaByRangeRequest) (*DownloadMediaByRangeResponse, error) {
    // Read a single range
    readResp, err := client.Do(context.Background(), &larkcore.ApiReq{
        HttpMethod:                http.MethodGet,
        ApiPath:                   fmt.Sprintf("/open-apis/sheets/v2/spreadsheets/%s/values/%s", request.SpreadsheetToken, request.Range),
        SupportedAccessTokenTypes: []larkcore.AccessTokenType{larkcore.AccessTokenTypeTenant},
    })
    if err != nil {
        return nil, err
    }

readSpreadsheetResp := &SpreadsheetResp{}
    err = json

.Unmarshal(readResp.RawBody, readSpreadsheetResp)
    if err != nil {
        return nil, err
    }
    readSpreadsheetResp.ApiResp = readResp
    if readSpreadsheetResp.Code != 0 {
        fmt.Printf("read spreadsheet failed, code: %d, msg: %s, log_id: %s\n",
            readSpreadsheetResp.Code, readSpreadsheetResp.Msg, readSpreadsheetResp.RequestId())
        return nil, readSpreadsheetResp.CodeError
    }

// Download files
    files := make([]*larkdrive.DownloadMediaResp, 0)
    values := readSpreadsheetResp.Data.ValueRange.Values
    tokens := parseFileToken(values, make(map[string]bool))
    for _, token := range tokens {
        downloadMediaReq := larkdrive.NewDownloadMediaReqBuilder().
            FileToken(token).
            Build()

downloadMediaResp, err := client.Drive.Media.Download(context.Background(), downloadMediaReq)
        if err != nil {
            return nil, err
        }
        if !downloadMediaResp.Success() {
            fmt.Printf("client.Drive.Media.Download failed, code: %d, msg: %s, log_id: %s\n",
                downloadMediaResp.Code, downloadMediaResp.Msg, downloadMediaResp.RequestId())
            return nil, downloadMediaResp.CodeError
        }

files = append(files, downloadMediaResp)
    }

// Return the result
    return &DownloadMediaByRangeResponse{
        CodeError: &larkcore.CodeError{
            Code: 0,
            Msg:  "success",
        },
        ReadResponse:          readSpreadsheetResp.Data,
        DownloadMediaResponse: files,
    }, nil
}

func parseFileToken(values []interface{}, tokens map[string]bool) []string {
    if len(values) == 0 {
        res := make([]string, 0, len(tokens))
        for k := range tokens {
            res = append(res, k)
        }
        return res
    }
    for _, i := range values {
        kind := reflect.TypeOf(i).Kind()
        if kind == reflect.Slice {
            parseFileToken(i.([]interface{}), tokens)
        } else if kind == reflect.Map {
            m := i.(map[string]interface{})
            if val, ok := m["fileToken"]; ok {
                tokens[val.(string)] = true
            }
        }
    }

res := make([]string, 0, len(tokens))
    for k := range tokens {
        res = append(res, k)
    }
    return res
}
```
