megaplan

package module
v3.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 5, 2024 License: MIT Imports: 15 Imported by: 0

README

Пример использования

Иниализация клиента + опция включения заголовка "Accept-Encoding":"gzip", ответ будет возвращаться сжатым:

import (
    "github.com/stvoidit/megaplan/v3"
)
const (
    domain = `https://yourdomain.ru`
    token  = `token`
)
func main() {
    client := megaplan.NewClient(domain, token, megaplan.OptionEnableAcceptEncodingGzip(true))
}

Пример создания задачами

https://demo.megaplan.ru/api/v3/docs#entityTask Для удобства составления json для тела запроса есть функция megaplan.BuildQueryParams. Её единственное название - собрать параметры в правильном формате. Некоторые сущности требуют специального формата (например Дата и Время, Интервал, Дата, Сдвиг дат), то функция megaplan.BuildQueryParams корректно сформирует структуру этих сущностей.

func CreateTask(c *megaplan.ClientV3) {
    const endpoint = "/api/v3/task"
    var qp = megaplan.BuildQueryParams(
        megaplan.SetRawField("contentType", "Task"),
        megaplan.SetRawField("isUrgent", false),
        megaplan.SetRawField("isTemplate", false),
        megaplan.SetRawField("name", "library test"),
        megaplan.SetRawField("subject", "subject library test"),
        megaplan.SetRawField("statement", "statement library test"),
        megaplan.SetEntityField("owner", "Employee", 1000129),
        megaplan.SetEntityField("responsible", "Employee", 1000129),
        megaplan.SetEntityField("deadline", "DateOnly", time.Now().Add(time.Hour*72)),
        megaplan.SetEntityField("plannedWork", "DateInterval", time.Hour*13),
    )
    r, err := qp.ToReader()
    if err != nil {
        panic(err)
    }
    rc, err := c.DoRequestAPI(http.MethodPost, endpoint, nil, r)
    if err != nil {
        panic(err)
    }
    defer rc.Close()
    os.Stdout.ReadFrom(rc)
}

Пример запроса с параметрами URL

Так как параметры запроса на api "Мегаплан" передаются в нетипичном формате ("*?json=?"), то необходимо их экранировать через url.QueryEscape. Для удобства составления этих параметров можно так же использовать тип megaplan.QueryParams.

func testGetWithFilters(c *megaplan.ClientV3) {
    const endpoint = "/api/v3/task"
    var requestedFiled = [...]string{
        "id",
        "name",
        "status",
        "deadline",
        "actualWork",
        "responsible",
        "timeCreated",
    }
    // параметры верхнего уровня
    var searchParams = megaplan.BuildQueryParams(
        megaplan.SetRawField("limit", 50),
        megaplan.SetRawField("onlyRequestedFields", true),
        megaplan.SetRawField("fields", requestedFiled),
    )

    // пример составления параметров без megaplan.BuildQueryParams (т.к. есть большая вложенность параметров)
    // megaplan.QueryParams - это просто алиас к типа megaplan.QueryParams, но с доп. методами,
    // поэтому для корректного составления json в параметрах URL необходимо передавать в DoRequestAPI именно megaplan.QueryParams
    now := time.Now()
    from := time.Date(now.Year(), time.January, 1, 0, 0, 0, 0, time.Local)
    var filterParams = map[string]interface{}{
        "contentType": "TaskFilter",
        "id":          nil,
        "config": megaplan.QueryParams{
            "contentType": "FilterConfig",
            "termGroup": megaplan.QueryParams{
                "contentType": "FilterTermGroup",
                "join":        "and",
                "terms": [...]megaplan.QueryParams{
                    {
                        "contentType": "FilterTermEnum",
                        "field":       "status",
                        "comparison":  "equals",
                        "value":       [...]string{"filter_any"},
                    },
                    {
                        "comparison":  "equals",
                        "field":       "responsible",
                        "contentType": "FilterTermRef",
                        "value": [...]megaplan.QueryParams{
                            {"id": 1000129, "contentType": "Employee"},
                        },
                    },
                    {
                        "comparison":  "equals",
                        "field":       "statusChangeTime",
                        "contentType": "FilterTermDate",
                        "value": megaplan.QueryParams{
                            "contentType": "IntervalDates",
                            "from":        megaplan.CreateEnity("DateOnly", from),
                            "to": megaplan.QueryParams{
                                "contentType": "DateOnly",
                                "year":        now.Year(),
                                "month":       int(now.Month()) - 1,
                                "day":         now.Day(),
                            },
                        },
                    },
                },
            },
        },
    }
    searchParams["filter"] = filterParams

    {
        // вариант отправки через DoRequestAPI, внутри формируется корректный http.Request, если http.Response был сжат, то будет разархивирован
        rc, err := c.DoRequestAPI(http.MethodGet, endpoint, searchParams, nil)
        if err != nil {
            panic(err)
        }
        defer rc.Close()
        os.Stdout.ReadFrom(rc)
    }
    {
        // пример с использование Do, внучную собирается http.Request (добавляются необходимые заголовки, http.Response никак не обрабатывается перед возвратом)
        c.SetOptions(megaplan.OptionEnableAcceptEncodingGzip(false))
        request, err := http.NewRequest(http.MethodGet, domain, nil)
        if err != nil {
            panic(err)
        }
        request.URL.Path = endpoint
        request.URL.RawQuery = searchParams.QueryEscape() // параметры будут правильно экранированы
        response, err := c.Do(request)
        if err != nil {
            panic(err)
        }
        defer response.Body.Close()
        os.Stdout.ReadFrom(response.Body)
    }
}

! Про типы и сущности "мегаплана" !

Многие реализации библиотек для API "Мегаплана" пытаются строго типизировать и описать полностью сущности, которыми оперирует "Мегаплан". Однако это подход влечет за собой обязанность этих библиотек поддерживать согласованность с версиями "Мегаплана", а так же каким-то образом поддерживать кастомные варианты полей. Данная библиотека является просто оберткой для использования API v3 и включает минимальное кол-во вспомогательных функций для составления запросов и парсинга ответов.

В силу специфики строения сущностей "Мегаплана" некоторые типы могут некорретно собираться функцией megaplan.BuildQueryParams, поэтому выше даны примере, как можно "дособрать" необходимые объекты.

Documentation

Index

Constants

View Source
const ISO8601 = `2006-01-02T15:04:05-07:00`

ISO8601 - формат даты для api

Variables

View Source
var (
	DefaultClient = &http.Client{
		Transport: &http.Transport{
			Proxy:               http.ProxyFromEnvironment,
			MaxIdleConns:        cpus,
			MaxConnsPerHost:     cpus,
			MaxIdleConnsPerHost: cpus,
		},
		Timeout: time.Minute,
	}
	// DefaultHeaders - заголовок по умолчанию - версия go. Используется при инициализации клиента в NewClient.
	DefaultHeaders = http.Header{"User-Agent": {runtime.Version()}}
)

DefaultClient - клиент по умаолчанию для API.

View Source
var ErrUnknownCompressionMethod = errors.New("unknown compression method")

ErrUnknownCompressionMethod - неизвестное значение в заголовке "Content-Encoding" не является фатальной ошибкой, должна возвращаться вместе с http.Response.Body, чтобы пользователь мог реализовать свой метод обработки сжатого сообщения

Functions

func ParseResponse

func ParseResponse(r io.Reader, i interface{}) (next bool, prev bool, err error)

ParseResponse - обертка над методов Response.Decode + данные о пагинации utility-функция для упрощения чтения ответа API

Types

type ClientOption

type ClientOption func(*ClientV3)

ClientOption - функция применения настроект

func OptionEnableAcceptEncodingGzip

func OptionEnableAcceptEncodingGzip(b bool) ClientOption

OptionEnableAcceptEncodingGzip - доабвить заголов Accept-Encoding=gzip к запросу т.е. объекм трафика на хуках может быть большим, то удобно запрашивать сжатый ответ

func OptionInsecureSkipVerify

func OptionInsecureSkipVerify(b bool) ClientOption

OptionInsecureSkipVerify - переключение флага bool в http.Client.Transport.TLSClientConfig.InsecureSkipVerify - отключать или нет проверку сертификтов Если домен использует самоподписанные сертифика, то удобно включать на время отладки и разработки

func OptionSetClientHTTP

func OptionSetClientHTTP(client *http.Client) ClientOption

OptionSetClientHTTP - установить свой экземпляр httpClient

func OptionSetXUserID

func OptionSetXUserID(userID int) ClientOption

OptionSetXUserID - добавить заголовок "X-User-Id" - запросы будут выполнятся от имени указанного пользователя. Если передано значение <= 0, то заголовок будет удален

func OptionsSetHTTPTransport

func OptionsSetHTTPTransport(tr http.RoundTripper) ClientOption

OptionsSetHTTPTransport - установить своб настройку http.Transport

type ClientV3

type ClientV3 struct {
	// contains filtered or unexported fields
}

ClientV3 - клиент

func NewClient

func NewClient(domain, token string, opts ...ClientOption) (c *ClientV3)

NewClient - обертка над http.Client для удобной работы с API v3

func (*ClientV3) Do

func (c *ClientV3) Do(req *http.Request) (*http.Response, error)

Do - http.Do + установка обязательных заголовков + декомпрессия ответа, если ответ сжат

func (ClientV3) DoCtxRequestAPI

func (c ClientV3) DoCtxRequestAPI(ctx context.Context, method string, endpoint string, search QueryParams, body io.Reader) (*http.Response, error)

DoRequestAPI - т.к. в v3 параметры запроса для GET (json маршализируется и будет иметь вид: "*?{params}=")

func (ClientV3) DoRequestAPI

func (c ClientV3) DoRequestAPI(method string, endpoint string, search QueryParams, body io.Reader) (*http.Response, error)

DoRequestAPI - т.к. в v3 параметры запроса для GET (json маршализируется и будет иметь вид: "*?{params}=")

func (*ClientV3) SetOptions

func (c *ClientV3) SetOptions(opts ...ClientOption)

SetOptions - применить опции

func (*ClientV3) SetToken

func (c *ClientV3) SetToken(token string)

SetToken - установить или изменить токен доступа

func (*ClientV3) UploadFile

func (c *ClientV3) UploadFile(filename string, fileRader io.Reader) (*http.Response, error)

UploadFile - загрузка файла, возвращает обычный http.Response, в ответе стандартная структура ответа + данные для базовой сущности

type Meta

type Meta struct {
	Errors []struct {
		Fields  interface{} `json:"field"`
		Message interface{} `json:"message"`
	} `json:"errors"`
	Status     int64      `json:"status"`
	Pagination Pagination `json:"pagination"`
}

Meta - metainfo

func (Meta) Error

func (m Meta) Error() (err error)

Error - если была ошибка, переданная в meta, то вернется ошибка с описание мегаплана, если нет, то вернется nil

type Pagination

type Pagination struct {
	Count       int64 `json:"count"`
	Limit       int64 `json:"limit"`
	CurrentPage int64 `json:"currentPage"`
	HasMoreNext bool  `json:"hasMoreNext"`
	HasMorePrev bool  `json:"hasMorePrev"`
}

Pagination - пагинация

func (Pagination) MarshalJSON

func (p Pagination) MarshalJSON() ([]byte, error)

MarshalJSON - json.Marshaler TODO: вообще обратный маршалинг на практике не нужен, поэтому нужно доделать позже

func (*Pagination) UnmarshalJSON

func (p *Pagination) UnmarshalJSON(b []byte) (err error)

UnmarshalJSON - json.Unmarshaler

type QueryBuildingFunc

type QueryBuildingFunc func(QueryParams)

QueryBuildingFunc - функция посттроения тела запроса (обычно json для post запроса)

func SetEntityArray

func SetEntityArray(field string, ents ...QueryBuildingFunc) QueryBuildingFunc

SetEntityArray - добавление массива сущностей в поле (например список аудиторов)

func SetEntityField

func SetEntityField(fieldName string, contentType string, value interface{}) (qbf QueryBuildingFunc)

SetEntityField - добавить поле с сущностью

func SetRawField

func SetRawField(field string, value interface{}) QueryBuildingFunc

SetRawField - добавить поле с простым типом значения (string, int, etc.)

type QueryParams

type QueryParams map[string]interface{}

QueryParams - параметры запроса

func BuildQueryParams

func BuildQueryParams(opts ...QueryBuildingFunc) (qp QueryParams)

BuildQueryParams - сборка объекта для запроса

func CreateEnity

func CreateEnity(contentType string, value interface{}) (qp QueryParams)

CreateEnity - создать базовую сущность в формате "Мегаплана" ! могут быть не описаны крайние или редкоиспользуемые типы

func (QueryParams) PrettyPrintJSON

func (qp QueryParams) PrettyPrintJSON(w io.Writer) error

PrettyPrintJSON - SetIndent для читабельного вывода

func (QueryParams) QueryEscape

func (qp QueryParams) QueryEscape() string

QueryEscape - urlencode для запроса

func (QueryParams) ToJSON

func (qp QueryParams) ToJSON() ([]byte, error)

ToJSON - маршализация параметров в JSON

func (QueryParams) ToReader

func (qp QueryParams) ToReader() (io.Reader, error)

ToReader - преобразование с JSON и io.Reader для удобства записи в http.Request

type Response

type Response struct {
	Meta Meta        `json:"meta"` // metainfo ответа
	Data interface{} `json:"data"` // поле для декодирования присвоенной структуры
}

Response - ответ API

func (*Response) Decode

func (res *Response) Decode(r io.Reader, i interface{}) (err error)

Decode - парсинг ответа API

func (Response) Next

func (res Response) Next() bool

Next - есть ли следующая страница

func (Response) Prev

func (res Response) Prev() bool

Prev - есть ли предыдущая страница

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL