API Dribbble возвращает 403 неавторизован при публикации нового выстрела.

Вопрос или проблема

Я следую этому API: https://developer.dribbble.com/v2/shots/#create-a-shot и пытаюсь опубликовать новый шот. Токен доступа был создан с использованием scope=upload. Я смог вызвать /user/shots, используя тот же токен, так что токен действителен. API возвращает HTTP 403 неавторизовано. Тело сообщения ответа пустое.

Вот метод, который я использую:


type DribbbleApi struct {
    Token string
}

// https://developer.dribbble.com/v2/shots/#create-a-shot
// Нулевое значение не будет отправлено (например, игнорируется)
type CreateShotArgs struct {
    Image             io.Reader
    Filename          string
    Title             string
    Description       string
    LowProfile        bool
    ReboundResourceId int
    ScheduledFor      *time.Time
    Tags              []string
    TeamId            int
    Timeout           time.Duration
}

// CreateShot создает новый шот с использованием https://developer.dribbble.com/v2/shots/#create-a-shot
func (d *DribbbleApi) CreateShot(args CreateShotArgs) error {
    rd, wr := io.Pipe()
    w := multipart.NewWriter(wr)
    var err error = nil
    go func() {
        defer wr.Close()
        defer w.Close()

        err = w.WriteField("title", args.Title)
        if err != nil {
            return
        }
        if args.Description != "" {
            err = w.WriteField("description", args.Description)
            if err != nil {
                return
            }
        }
        if args.LowProfile {
            err = w.WriteField("low_profile", "true")
            if err != nil {
                return
            }
        }
        if args.ReboundResourceId > 0 {
            err = w.WriteField("rebound_resource_id", fmt.Sprintf("%d", args.ReboundResourceId))
            if err != nil {
                return
            }
        }
        if args.ScheduledFor != nil {
            err = w.WriteField("scheduled_for", args.ScheduledFor.Format(time.RFC3339))
            if err != nil {
                return
            }
        }
        if len(args.Tags) > 0 {
            tags := strings.Join(args.Tags, ",")
            err = w.WriteField("tags", tags)
            if err != nil {
                return
            }
        }
        if args.TeamId > 0 {
            err = w.WriteField("team_id", fmt.Sprint(args.TeamId))
            if err != nil {
                return
            }
        }

        var fp io.Writer
        fp, err = w.CreateFormFile("image", args.Filename)
        if err != nil {
            return
        }
        _, err = io.Copy(fp, args.Image)
        return
    }()

    req, err2 := http.NewRequest("POST", "https://api.dribbble.com/v2/shots", rd)
    if err2 != nil {
        return err2
    }
    if err != nil {
        return err
    }
    req.Header.Set("Content-Type", w.FormDataContentType())
    req.Header.Set("Authorization", "Bearer "+d.Token)
    client := &http.Client{
        Timeout: args.Timeout,
    }
    res, err2 := client.Do(req)
    if err2 != nil {
        return err2
    }
    defer res.Body.Close()
    if err != nil {
        return err
    }

    if res.StatusCode != http.StatusAccepted {
        bodyBytes, err := io.ReadAll(res.Body)
        if err != nil {
            return err
        }
        fmt.Println(string(bodyBytes)) // выводит пустую строку
        return fmt.Errorf("плохой статус: %s %s", res.Status, string(bodyBytes))
    }
    return nil
}

Документация API Dribbble не очень ясна. Она не объясняет типы полей, например, поле low_profile имеет тип “boolean”, но что это значит? Если это POST-запрос с многокомпонентной формой, то такого понятия как “boolean” не существует, и неясно, как его следует представлять.

В ответе нет сообщения об ошибке, и у меня нет понятия, что не так.

Что я делаю не так?

Ответ или решение

Для решения проблемы с получением ошибки 403 Unauthorized при попытке создать новый шот (shot) с помощью API Dribbble, необходимо обратить внимание на несколько аспектов вашего кода и конфигурации.

  1. Проверка доступа и прав токена: Вы упомянули, что токен был создан с использованием scope=upload и что вы можете вызывать эндпоинт /user/shots с тем же токеном. Это означает, что у вас есть права на публикацию шотов. Однако обязательно убедитесь, что токен не истек и с ним не связаны ограничения.

  2. Параметры запроса: API требует определенные поля в запросе. По вашему коду видно, что вы пытаетесь превратить low_profile в строку "true", когда он установлен в true. Однако, поскольку это поле является булевым, его следует отправлять как "true" или "false" (возможны строки). Убедитесь, что вы передаете его корректно:

    if args.LowProfile {
       err = w.WriteField("low_profile", "true")
       if err != nil {
           return
       }
    }

    Вместо этого, вы можете полностью исключить поле, если оно равно false.

  3. Отправка файла изображения: Убедитесь, что файл изображения корректно загружается и передается. Если он не может быть прочитан или я неправильно переданы, это может вызывать ошибку 403. Убедитесь, что args.Image является корректным io.Reader и что вы передаете файл в нужном формате.

  4. Формат даты для scheduled_for: Убедитесь, что передаваемая дата scheduled_for соответствует формату time.RFC3339. Вы правильно это делаете, но если передаете nil, это должно быть обработано, чтобы избежать попыток писать это поле при отсутствии значения.

  5. Обработка HTTP-ответа: В вашем коде логика обработки ответа выглядит корректно. К тому же, выдвигайте дополнительные попытки логирования, чтобы понять, в каком именно месте возникает сбой.

  6. Изменение URL API: Убедитесь, что используете правильный URL для API. Текущая версия API может измениться, и не следует полагаться на старую информацию.

  7. Тестирование через Postman или аналогичный инструмент: Если проблема сохраняется, попробуйте выполнить запрос через Postman или аналогичный инструмент, чтобы вручную проверить работу API с тем же токеном и параметрами запросов. Это может помочь выявить проблемы на уровне данных или аутентификации.

Пример отправки запроса через Postman:

  • Установите метод HTTP на POST.
  • Установите URL на https://api.dribbble.com/v2/shots.
  • Вкладка Authorization: выберите Bearer Token и вставьте ваш токен.
  • Вкладка Body выберите form-data и добавьте поля, аналогично тем, что вы добавляете в коде, убедитесь, что файл изображения загружается корректно.

Если после проверки всех вышеперечисленных шагов проблема все еще не решена, я рекомендую обратиться к документации API Dribbble или службе поддержки для получения более детальной информации о наличии возможных ограничений или ошибок в API.

Оцените материал
Добавить комментарий

Капча загружается...